Browse Source

commit: import project

HOME 4 years ago
parent
commit
36887c4778

+ 14 - 0
EfDbCommentGenerator/Core/CommentEntry.cs

@@ -0,0 +1,14 @@
+namespace EfDbCommentGenerator.Core
+{
+    internal class CommentEntry
+    {
+        public string Table { get; set; }
+        public string Column { get; set; }
+        public string Comment { get; set; }
+
+        public override string ToString()
+        {
+            return $"Table=\"{Table}\",Field=\"{Column}\",Comment=\"{Comment}\"";
+        }
+    }
+}

+ 98 - 0
EfDbCommentGenerator/Core/MetaMapper.cs

@@ -0,0 +1,98 @@
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations.Schema;
+using System.Linq;
+using System.Reflection;
+using System.Text;
+
+namespace EfDbCommentGenerator.Core
+{
+    internal class MetaMapper
+    {
+        public static string Generate(string asmPath)
+        {
+            var doc = new XmlDocFinder();
+
+            var asm = Assembly.LoadFrom(asmPath);
+
+            var types = asm.GetTypes();
+
+            var tblTypes = types
+                .Where(p => p.IsDefined(typeof(TableAttribute)) && p.IsAbstract == false)
+                .ToArray();
+
+            var entries = new List<CommentEntry>();
+
+            foreach (var tblType in tblTypes)
+            {
+                var tNam = tblType.GetCustomAttribute<TableAttribute>().Name;
+                var tDoc = doc.FindDoc(tblType);
+                entries.Add(new CommentEntry { Table = tNam, Column = null, Comment = tDoc });
+                entries.AddRange(tblType
+                    .GetProperties()
+                    .Where(p => //Skip NaviProp and Getter
+                        p.CanWrite && p.CanRead
+                        && false == p.PropertyType.IsDefined(typeof(TableAttribute))
+                        && false == (p.PropertyType.IsGenericType && p.PropertyType.GetGenericTypeDefinition() == typeof(ICollection<>))
+                    )
+                    .Select(p => new
+                    {
+                        prop = p,
+                        pDoc = doc.FindDoc(p)
+                    })
+                    .Where(p => !string.IsNullOrEmpty(p.pDoc))
+                    .Select(p => new CommentEntry
+                    {
+                        Table = tNam,
+                        Column = p.prop.IsDefined(typeof(ColumnAttribute))
+                            ? p.prop.GetCustomAttribute<ColumnAttribute>().Name
+                            : p.prop.Name,
+                        Comment = p.pDoc
+                    })
+                );
+            }
+
+            var sb = new StringBuilder();
+            foreach (var entry in entries)
+            {
+                var comment = entry
+                     .Comment?
+                     .Replace("'", "''") //你懂
+                     .Replace("\n", " ")
+                     .Trim(' ', '\t'); //去空格
+
+                if (string.IsNullOrEmpty(comment)) continue;
+
+                //------------------------------ Dont Care error.... -------------------------
+
+                sb.AppendLine($"EXEC sp_addextendedproperty");
+                sb.AppendLine($"    @name = N'MS_Description'" + $",@value = N'{comment}'");
+                sb.AppendLine($"    ,@level0type = N'Schema'" + $",@level0name = N'dbo'");
+                sb.AppendLine($"    ,@level1type = N'Table'" + $",@level1name = N'{entry.Table}'");
+
+                if (false == string.IsNullOrEmpty(entry.Column))
+                    sb.AppendLine(
+                        $"    ,@level2type = N'Column'" + $",@level2name = N'{entry.Column}'"
+                    );
+
+                //------------------------------ Dont Care error.... -------------------------
+
+                sb.AppendLine("GO");
+
+                sb.AppendLine($"EXEC sp_updateextendedproperty");
+                sb.AppendLine($"    @name = N'MS_Description'" + $",@value = N'{comment}'");
+                sb.AppendLine($"    ,@level0type = N'Schema'" + $",@level0name = N'dbo'");
+                sb.AppendLine($"    ,@level1type = N'Table'" + $",@level1name = N'{entry.Table}'");
+
+                if (false == string.IsNullOrEmpty(entry.Column))
+                    sb.AppendLine(
+                        $"    ,@level2type = N'Column'" + $",@level2name = N'{entry.Column}'"
+                    );
+
+                sb.AppendLine("GO");
+            }
+
+            var sql = sb.ToString();
+            return sql;
+        }
+    }
+}

+ 101 - 0
EfDbCommentGenerator/Core/XmlDocFinder.cs

@@ -0,0 +1,101 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using System.Reflection;
+using System.Xml.Linq;
+using System.Xml.XPath;
+
+namespace EfDbCommentGenerator.Core
+{
+    internal class XmlDocFinder
+    {
+        private readonly Dictionary<string, XDocument> _dicXml;
+
+        public XmlDocFinder()
+        {
+            _dicXml = new Dictionary<string, XDocument>();
+        }
+
+        private XDocument GetXml(Assembly assembly)
+        {
+            var xmlFilePath = Path.ChangeExtension(assembly.Location, "xml");
+            if (_dicXml.ContainsKey(xmlFilePath)) return _dicXml[xmlFilePath];
+
+            XDocument load = null;
+
+            try
+            {
+                load = XDocument.Load(xmlFilePath);
+            }
+            catch (Exception ex)
+            {
+                Debug.Print(ex.ToString());
+            }
+
+            return _dicXml[xmlFilePath] = load;
+        }
+
+        public string FindDoc(MemberInfo member)
+        {
+            var xml = GetXml(member.Module.Assembly);
+            if (xml == null) return null;
+
+            Type identityType;
+            switch (member.MemberType)
+            {
+                case MemberTypes.TypeInfo:
+                case MemberTypes.NestedType:
+                    return xml.XPathSelectElement($"/doc/members/member[@name=\"T:{((Type)member).FullName.Replace("+", ".")}\"]/summary")?.Value.Trim();
+
+                case MemberTypes.Field:
+                    var fi = (FieldInfo)member;
+                    identityType = fi.ReflectedType;
+                    if (identityType != null && identityType.IsGenericType && false == identityType.IsGenericTypeDefinition)
+                    {
+                        identityType = identityType.GetGenericTypeDefinition();
+                    }
+
+                    Debug.Assert(identityType != null, "t != null");
+
+                    return xml.XPathSelectElement($"/doc/members/member[@name=\"F:{identityType.FullName.Replace("+", ".")}.{fi.Name}\"]/summary")?.Value.Trim();
+                case MemberTypes.Property:
+                    var pi = (PropertyInfo)member;
+                    if (pi.ReflectedType != pi.DeclaringType && pi.DeclaringType != null)
+                    {
+                        var findDoc = FindDoc(pi.DeclaringType.GetProperty(pi.Name));
+                        return findDoc;
+                    }
+
+                    string additionalComment = null;
+                    if (pi.PropertyType.IsEnum)
+                    {
+                        additionalComment += FindDoc(pi.PropertyType)
+                            + "("
+                            + string.Join(",", Enum.GetValues(pi.PropertyType).Cast<object>().Select(p => pi.PropertyType.GetField(p.ToString())).Select(p => Convert.ToInt64(p.GetRawConstantValue()) + ":" + FindDoc(p)))
+                            + ")";
+                    }
+
+                    identityType = pi.ReflectedType;
+                    if (identityType != null && identityType.IsGenericType && false == identityType.IsGenericTypeDefinition)
+                    {
+                        identityType = identityType.GetGenericTypeDefinition();
+                    }
+
+                    Debug.Assert(identityType != null, "t != null");
+
+                    return xml.XPathSelectElement($"/doc/members/member[@name=\"P:{identityType.FullName.Replace("+", ".")}.{pi.Name}\"]/summary")?.Value.Trim()
+                        + additionalComment;
+
+                case MemberTypes.Constructor:
+                case MemberTypes.Event:
+                case MemberTypes.Method:
+                case MemberTypes.Custom:
+                case MemberTypes.All:
+                default:
+                    return null;
+            }
+        }
+    }
+}

+ 64 - 0
EfDbCommentGenerator/Demo/DemoData.cs

@@ -0,0 +1,64 @@
+namespace EfDbCommentGenerator.Demo
+{
+#if DEMO
+
+    internal class NestDamn
+    {
+        internal abstract class BaseEntity
+        {
+            /// <summary>
+            /// 名称
+            /// </summary>
+            public string Name { get; set; }
+        }
+    }
+
+    /// <summary>
+    /// 煤
+    /// </summary>
+    [Table("DebugData_Coal")]
+    internal class Coal : NestDamn.BaseEntity
+    {
+        /// <summary>
+        /// 泥煤 标识
+        /// </summary>
+        public int YourSysterId { get; set; }
+
+        /// <summary>
+        /// 泥煤 导航属性
+        /// </summary>
+        public YourSyster YourSyster { get; set; }
+    }
+
+    /// <summary>
+    /// 泥煤
+    /// </summary>
+    [Table("DebugData_YourSyster")]
+    internal class YourSyster : NestDamn.BaseEntity
+    {
+        /// <summary>
+        /// 拥有者 标识
+        /// </summary>
+        public int OwnerId { get; set; }
+
+        /// <summary>
+        /// 拥有者 导航属性
+        /// </summary>
+        public SysterOwner Owner { get; set; }
+
+        /// <summary>
+        /// 煤堆
+        /// </summary>
+        public ICollection<Coal> Coals { get; set; }
+    }
+
+    /// <summary>
+    /// 拥有者
+    /// </summary>
+    [Table("DebugData_SysterOwner")]
+    internal class SysterOwner : NestDamn.BaseEntity
+    {
+    }
+
+#endif
+}

+ 88 - 0
EfDbCommentGenerator/EfDbCommentGenerator.csproj

@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProjectGuid>{72A3827C-D797-4CBC-BC38-6551FCC04905}</ProjectGuid>
+    <OutputType>WinExe</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>EfDbCommentGenerator</RootNamespace>
+    <AssemblyName>EfdbComgen</AssemblyName>
+    <TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+    <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <PlatformTarget>AnyCPU</PlatformTarget>
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <DocumentationFile>bin\Debug\EfdbComgen.xml</DocumentationFile>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <PlatformTarget>AnyCPU</PlatformTarget>
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup>
+    <StartupObject>
+    </StartupObject>
+  </PropertyGroup>
+  <PropertyGroup>
+    <RunPostBuildEvent>OnOutputUpdated</RunPostBuildEvent>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="System" />
+    <Reference Include="System.ComponentModel.DataAnnotations" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Xml.Linq" />
+    <Reference Include="System.Data.DataSetExtensions" />
+    <Reference Include="Microsoft.CSharp" />
+    <Reference Include="System.Data" />
+    <Reference Include="System.Deployment" />
+    <Reference Include="System.Drawing" />
+    <Reference Include="System.Net.Http" />
+    <Reference Include="System.Windows.Forms" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="Core\CommentEntry.cs" />
+    <Compile Include="Core\XmlDocFinder.cs" />
+    <Compile Include="Demo\DemoData.cs" />
+    <Compile Include="MainForm.cs">
+      <SubType>Form</SubType>
+    </Compile>
+    <Compile Include="MainForm.Designer.cs">
+      <DependentUpon>MainForm.cs</DependentUpon>
+    </Compile>
+    <Compile Include="Core\MetaMapper.cs" />
+    <Compile Include="Program.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <EmbeddedResource Include="MainForm.resx">
+      <DependentUpon>MainForm.cs</DependentUpon>
+    </EmbeddedResource>
+    <None Include="packages.config" />
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <PropertyGroup>
+    <PostBuildEvent>if $(ConfigurationName) == Release if not exist $(TargetDir)Packed md $(TargetDir)Packed
+if $(ConfigurationName) == Release $(SolutionDir)packages\ILRepack.2.0.12\tools\ILRepack /ndebug /out:$(TargetDir)Packed\$(TargetFileName) $(TargetPath)
+if $(ConfigurationName) == Release if exist $(TargetDir)Packed\$(TargetFileName).config del $(TargetDir)Packed\$(TargetFileName).config</PostBuildEvent>
+  </PropertyGroup>
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+</Project>

+ 63 - 0
EfDbCommentGenerator/MainForm.Designer.cs

@@ -0,0 +1,63 @@
+namespace EfDbCommentGenerator
+{
+    partial class MainForm
+    {
+        /// <summary>
+        /// 必需的设计器变量。
+        /// </summary>
+        private System.ComponentModel.IContainer components = null;
+
+        /// <summary>
+        /// 清理所有正在使用的资源。
+        /// </summary>
+        /// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>
+        protected override void Dispose(bool disposing)
+        {
+            if (disposing && (components != null))
+            {
+                components.Dispose();
+            }
+            base.Dispose(disposing);
+        }
+
+        #region Windows 窗体设计器生成的代码
+
+        /// <summary>
+        /// 设计器支持所需的方法 - 不要修改
+        /// 使用代码编辑器修改此方法的内容。
+        /// </summary>
+        private void InitializeComponent()
+        {
+            this.richTextBox1 = new System.Windows.Forms.RichTextBox();
+            this.SuspendLayout();
+            // 
+            // richTextBox1
+            // 
+            this.richTextBox1.Dock = System.Windows.Forms.DockStyle.Fill;
+            this.richTextBox1.Location = new System.Drawing.Point(0, 0);
+            this.richTextBox1.Name = "richTextBox1";
+            this.richTextBox1.Size = new System.Drawing.Size(1264, 682);
+            this.richTextBox1.TabIndex = 0;
+            this.richTextBox1.Text = "";
+            this.richTextBox1.WordWrap = false;
+            this.richTextBox1.MouseDoubleClick += new System.Windows.Forms.MouseEventHandler(this.richTextBox1_MouseDoubleClick);
+            // 
+            // MainForm
+            // 
+            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
+            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+            this.ClientSize = new System.Drawing.Size(1264, 682);
+            this.Controls.Add(this.richTextBox1);
+            this.Name = "MainForm";
+            this.Text = "Form1";
+            this.Shown += new System.EventHandler(this.MainForm_Shown);
+            this.ResumeLayout(false);
+
+        }
+
+        #endregion
+
+        private System.Windows.Forms.RichTextBox richTextBox1;
+    }
+}
+

+ 63 - 0
EfDbCommentGenerator/MainForm.cs

@@ -0,0 +1,63 @@
+using System;
+using System.Windows.Forms;
+using EfDbCommentGenerator.Core;
+
+namespace EfDbCommentGenerator
+{
+    public partial class MainForm : Form
+    {
+        public MainForm()
+        {
+            InitializeComponent();
+            InitUi();
+        }
+
+        private void InitUi()
+        {
+            Text = Application.ProductName;
+        }
+
+        private void MainForm_Shown(object sender, System.EventArgs e)
+        {
+#if DEMO
+            richTextBox1.Text = MetaMapper.Generate(Application.ExecutablePath);
+#else
+            string asm;
+            if (Program.CliArgs.Length == 0)
+            {
+                var dlg = new OpenFileDialog
+                {
+                    Multiselect = false
+                };
+                if (dlg.ShowDialog() == DialogResult.OK)
+                {
+                    asm = dlg.FileName;
+                }
+                else
+                {
+                    this.Close();
+                    return;
+                }
+            }
+            else
+            {
+                asm = Program.CliArgs[0];
+            }
+
+            try
+            {
+                richTextBox1.Text = MetaMapper.Generate(asm);
+            }
+            catch (Exception ex)
+            {
+                richTextBox1.Text = ex.ToString();
+            }
+#endif
+        }
+
+        private void richTextBox1_MouseDoubleClick(object sender, MouseEventArgs e)
+        {
+            richTextBox1.SelectAll();
+        }
+    }
+}

+ 120 - 0
EfDbCommentGenerator/MainForm.resx

@@ -0,0 +1,120 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+  <!-- 
+    Microsoft ResX Schema 
+    
+    Version 2.0
+    
+    The primary goals of this format is to allow a simple XML format 
+    that is mostly human readable. The generation and parsing of the 
+    various data types are done through the TypeConverter classes 
+    associated with the data types.
+    
+    Example:
+    
+    ... ado.net/XML headers & schema ...
+    <resheader name="resmimetype">text/microsoft-resx</resheader>
+    <resheader name="version">2.0</resheader>
+    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+        <value>[base64 mime encoded serialized .NET Framework object]</value>
+    </data>
+    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+        <comment>This is a comment</comment>
+    </data>
+                
+    There are any number of "resheader" rows that contain simple 
+    name/value pairs.
+    
+    Each data row contains a name, and value. The row also contains a 
+    type or mimetype. Type corresponds to a .NET class that support 
+    text/value conversion through the TypeConverter architecture. 
+    Classes that don't support this are serialized and stored with the 
+    mimetype set.
+    
+    The mimetype is used for serialized objects, and tells the 
+    ResXResourceReader how to depersist the object. This is currently not 
+    extensible. For a given mimetype the value must be set accordingly:
+    
+    Note - application/x-microsoft.net.object.binary.base64 is the format 
+    that the ResXResourceWriter will generate, however the reader can 
+    read any of the formats listed below.
+    
+    mimetype: application/x-microsoft.net.object.binary.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+            : and then encoded with base64 encoding.
+    
+    mimetype: application/x-microsoft.net.object.soap.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+            : and then encoded with base64 encoding.
+
+    mimetype: application/x-microsoft.net.object.bytearray.base64
+    value   : The object must be serialized into a byte array 
+            : using a System.ComponentModel.TypeConverter
+            : and then encoded with base64 encoding.
+    -->
+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+    <xsd:element name="root" msdata:IsDataSet="true">
+      <xsd:complexType>
+        <xsd:choice maxOccurs="unbounded">
+          <xsd:element name="metadata">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" />
+              </xsd:sequence>
+              <xsd:attribute name="name" use="required" type="xsd:string" />
+              <xsd:attribute name="type" type="xsd:string" />
+              <xsd:attribute name="mimetype" type="xsd:string" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="assembly">
+            <xsd:complexType>
+              <xsd:attribute name="alias" type="xsd:string" />
+              <xsd:attribute name="name" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="data">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="resheader">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" />
+            </xsd:complexType>
+          </xsd:element>
+        </xsd:choice>
+      </xsd:complexType>
+    </xsd:element>
+  </xsd:schema>
+  <resheader name="resmimetype">
+    <value>text/microsoft-resx</value>
+  </resheader>
+  <resheader name="version">
+    <value>2.0</value>
+  </resheader>
+  <resheader name="reader">
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+</root>

+ 22 - 0
EfDbCommentGenerator/Program.cs

@@ -0,0 +1,22 @@
+using System;
+using System.Windows.Forms;
+
+namespace EfDbCommentGenerator
+{
+    static class Program
+    {
+        internal static string[] CliArgs;
+
+        /// <summary>
+        /// 应用程序的主入口点。
+        /// </summary>
+        [STAThread]
+        private static void Main(string[] args)
+        {
+            CliArgs = args;
+            Application.EnableVisualStyles();
+            Application.SetCompatibleTextRenderingDefault(false);
+            Application.Run(new MainForm());
+        }
+    }
+}

+ 36 - 0
EfDbCommentGenerator/Properties/AssemblyInfo.cs

@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// 有关程序集的一般信息由以下
+// 控制。更改这些特性值可修改
+// 与程序集关联的信息。
+[assembly: AssemblyTitle("EfDbCommentGenerator")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Microsoft")]
+[assembly: AssemblyProduct("Sdat.EfDbCommentGenerator")]
+[assembly: AssemblyCopyright("Copyright © Microsoft 2017")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+//将 ComVisible 设置为 false 将使此程序集中的类型
+//对 COM 组件不可见。  如果需要从 COM 访问此程序集中的类型,
+//请将此类型的 ComVisible 特性设置为 true。
+[assembly: ComVisible(false)]
+
+// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
+[assembly: Guid("72a3827c-d797-4cbc-bc38-6551fcc04905")]
+
+// 程序集的版本信息由下列四个值组成: 
+//
+//      主版本
+//      次版本
+//      生成号
+//      修订号
+//
+//可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值,
+// 方法是按如下所示使用“*”: :
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]

+ 4 - 0
EfDbCommentGenerator/packages.config

@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+  <package id="ILRepack" version="2.0.12" targetFramework="net461" />
+</packages>

File diff suppressed because it is too large
+ 1190 - 0
MiscToolSet/MainForm.Designer.cs


+ 235 - 0
MiscToolSet/MainForm.cs

@@ -0,0 +1,235 @@
+using System;
+using System.CodeDom.Compiler;
+using System.IO;
+using System.Linq;
+using System.Security.Cryptography;
+using System.Text;
+using System.Text.RegularExpressions;
+using System.Windows.Forms;
+using Microsoft.AspNet.Identity;
+
+namespace MiscToolSet
+{
+    public partial class MainForm : Form
+    {
+        private readonly RandomNumberGenerator _rng = RandomNumberGenerator.Create();
+        private readonly PasswordHasher _passwordHasher = new PasswordHasher();
+        private readonly MD5 _md5 = new MD5Cng();
+        private readonly Encoding _asciiEncoding = Encoding.ASCII;
+
+        [STAThread]
+        private static void Main()
+        {
+            Application.EnableVisualStyles();
+            Application.SetCompatibleTextRenderingDefault(false);
+            Application.Run(new MainForm());
+        }
+
+        public MainForm()
+        {
+            InitializeComponent();
+        }
+
+        private void Md5HasherUpperCaseCheckBox_CheckedChanged(object sender, EventArgs e)
+        {
+            MD5HasherInputTextBox_TextChanged(null, null);
+        }
+
+        private void MD5HasherInputTextBox_TextChanged(object sender, EventArgs e)
+        {
+            var fmt = Md5HasherUpperCaseCheckBox.Checked ? "X2" : "x2";
+            Md5HasherOutputTextBox.Text = string.Join("", _md5.ComputeHash(Encoding.UTF8.GetBytes(MD5HasherInputTextBox.Text)).Select(p => p.ToString(fmt)));
+        }
+
+        private void txtToPasswordHash_TextChanged(object sender, System.EventArgs e)
+        {
+            PasswordHasherOutputTextBox.Text = _passwordHasher.HashPassword(PasswordHasherInputTextBox.Text);
+        }
+
+        private void txtResultOfPasswordHash_MouseDoubleClick(object sender, MouseEventArgs e)
+        {
+            PasswordHasherOutputTextBox.SelectAll();
+        }
+
+        private void btnNewGuid_Click(object sender, EventArgs e)
+        {
+            var g = Guid.NewGuid();
+            GuidGeneratorResultDTextBox.Text = g.ToString("D").ProcessWhen(UpperCaseCheckBox.Checked, p => p.ToUpper());
+            GuidGeneratorResultNTextBox.Text = g.ToString("N").ProcessWhen(UpperCaseCheckBox.Checked, p => p.ToUpper());
+            GuidGeneratorResultAttributeTextBox.Text = $"[Guid(\"{g.ToString("D").ProcessWhen(UpperCaseCheckBox.Checked, p => p.ToUpper()) }\")]";
+            GuidGeneratorResultNewTextBox.Text = $"new Guid(\"{g.ToString("D").ProcessWhen(UpperCaseCheckBox.Checked, p => p.ToUpper())}\")";
+        }
+
+        private void btnCpN_Click(object sender, EventArgs e) => Clipboard.SetText(GuidGeneratorResultNTextBox.Text);
+
+        private void btnCpD_Click(object sender, EventArgs e) => Clipboard.SetText(GuidGeneratorResultDTextBox.Text);
+
+        private void btnCpA_Click(object sender, EventArgs e) => Clipboard.SetText(GuidGeneratorResultAttributeTextBox.Text);
+
+        private void GuidGeneratorCopyNewButton_Click(object sender, EventArgs e) => Clipboard.SetText(GuidGeneratorResultNewTextBox.Text);
+
+        private void NewMachineKeyButton_Click(object sender, EventArgs e)
+        {
+            var rng = new RNGCryptoServiceProvider();
+            string CreateKey(int numBytes)
+            {
+                var buff = new byte[numBytes];
+                rng.GetBytes(buff);
+                return string.Join("", buff.Select(p => $"{p:X2}"));
+            }
+
+            MachineKeyResult.Text =
+                $"<machineKey" +
+                $" validationKey=\"{CreateKey(64)}\"" +
+                $" decryptionKey=\"{CreateKey(24)}\"" +
+                $" decryption=\"3DES\"" +
+                $" validation=\"3DES\" />";
+        }
+
+        private void CopyMachineKeyButton_Click(object sender, EventArgs e)
+        {
+            Clipboard.SetText(MachineKeyResult.Text);
+        }
+
+        private void PasswordGenerateButton_Click(object sender, EventArgs e)
+        {
+            int GetIntRandomly()
+            {
+                var buf = new byte[4];
+                _rng.GetBytes(buf);
+                return BitConverter.ToInt32(buf, 0);
+            }
+
+            var stringBuilder = new StringBuilder();
+            if (PasswordGenerateIncludeUpperCaseCheckBox.Checked) stringBuilder.Append(Enumerable.Range('A', 'Z' - 'A' + 1).Select(p => (char)p).ToArray());
+            if (PasswordGenerateIncludeLowerCaseCheckBox.Checked) stringBuilder.Append(Enumerable.Range('a', 'z' - 'a' + 1).Select(p => (char)p).ToArray());
+            if (PasswordGenerateIncludeNumberCheckBox.Checked) stringBuilder.Append(Enumerable.Range('0', '9' - '0' + 1).Select(p => (char)p).ToArray());
+            if (PasswordGenerateIncludeSymbolCheckBox.Checked) stringBuilder.Append("!@#$%&*");
+
+            var charPool = stringBuilder.ToString();
+            string GetRandomString()
+            {
+                return new string(
+                    Enumerable.Range(0, (int)PasswordGenerateLengthUpDownBox.Value)
+                        .Select(p => charPool[Math.Abs(GetIntRandomly() % charPool.Length)])
+                        .ToArray()
+                );
+            }
+
+            string HashString(string str)
+            {
+                if (PasswordGenerateUseMd5RadioButton.Checked)
+                {
+                    var fmt = PasswordGeneratorHashUseUpperCaseCheckBox.Checked ? "X2" : "x2";
+                    return string.Join("", _md5.ComputeHash(_asciiEncoding.GetBytes(str)).Select(p => p.ToString(fmt)));
+                }
+
+                if (PasswordGenerateUsePasswordHasherRadioButton.Checked)
+                {
+                    return _passwordHasher.HashPassword(str);
+                }
+
+                throw new NotImplementedException();
+            }
+
+            PasswordGenerateResultRichTextBox.Clear();
+            for (var i = 0; i < PasswordGenerateNumberUpDownBox.Value; i++)
+            {
+                var str = GetRandomString();
+
+                PasswordGenerateResultRichTextBox.AppendText($"{str} {HashString(str)}{Environment.NewLine}");
+            }
+        }
+
+        private void DropToBase64Label_DragEnter(object sender, DragEventArgs e)
+        {
+            e.Effect = e.Data.GetDataPresent(DataFormats.FileDrop)
+                ? DragDropEffects.Copy
+                : DragDropEffects.None;
+        }
+
+        private void DropToBase64Label_DragDrop(object sender, DragEventArgs e)
+        {
+            var files = (string[])e.Data.GetData(DataFormats.FileDrop);
+
+            DropToBase64FileNameLabel.Text = Path.GetFileName(files[0]);
+
+            var bytes = File.ReadAllBytes(files[0]);
+            var base64String = Convert.ToBase64String(bytes, Base64FormattingOptions.None);
+            DropToBase64TextBox.Text = DataUrlCheckBox.Checked
+                ? $"data:{DataUrlMimeTypeTextBox.Text};base64,{base64String}"
+                : base64String;
+        }
+
+        private void CopyBase64Button_Click(object sender, EventArgs e)
+        {
+            Clipboard.SetText(DropToBase64TextBox.Text);
+        }
+
+        private void BulkNewGuidButton_Click(object sender, EventArgs e)
+        {
+            var length = ((int)BulkNewGuidUpDown.Value);
+            for (var i = 0; i < length; i++)
+            {
+                var guid = Guid.NewGuid();
+
+                if (NormalBulkNewGuidRadioButton.Checked) BulkNewGuidTextBox.AppendText($"{guid:D}{Environment.NewLine}".ProcessWhen(UpperCaseCheckBox.Checked, p => p.ToUpper()));
+                if (CtorBulkNewGuidRadioButton.Checked) BulkNewGuidTextBox.AppendText($"new Guid(\"{$"{guid:D}".ProcessWhen(UpperCaseCheckBox.Checked, p => p.ToUpper())}\");{Environment.NewLine}");
+                if (AttrBulkNewGuidRadioButton.Checked) BulkNewGuidTextBox.AppendText($"[Guid(\"{$"{guid:D}".ProcessWhen(UpperCaseCheckBox.Checked, p => p.ToUpper())}\"]{Environment.NewLine}");
+                if (NumberBulkNewGuidRadioButton.Checked) BulkNewGuidTextBox.AppendText($"{guid:N}{Environment.NewLine}".ProcessWhen(UpperCaseCheckBox.Checked, p => p.ToUpper()));
+            }
+        }
+
+        private void MagicHuntingButton_Click(object sender, EventArgs e)
+        {
+            var magicPattern = new Regex(MagicPatternText.Text, RegexOptions.Compiled);
+
+            var dicCollect = new System.Collections.Generic.Dictionary<string, string>();
+
+            CodeConvertTextBox.Text = magicPattern.Replace(CodeInputTextBox.Text, match =>
+            {
+                var identity = match.Groups[1].Value;
+
+                if (false == IdentifierChecker.Valid(identity)) return match.Value;
+                if (false == dicCollect.ContainsKey(identity)) dicCollect[identity] = match.Result(CollectPatternTextBox.Text);
+
+                return match.Result(ConvertPatternTextBox.Text);
+            });
+
+            CodeCollectTextBox.Text =
+                "private static class Identities {"
+                + Environment.NewLine + "// ReSharper disable InconsistentNaming" + Environment.NewLine;
+
+            CodeCollectTextBox.Text += string.Join(Environment.NewLine, dicCollect.Values.OrderBy(p => p));
+
+            CodeCollectTextBox.Text +=
+                Environment.NewLine
+                + "// ReSharper restore InconsistentNaming" + Environment.NewLine
+                + "}";
+        }
+
+        private void RsaKeyGenerateButton_Click(object sender, EventArgs e)
+        {
+            // thanks to dotblogs.com.tw/supershowwei/2015/12/23/160510
+            // docs.microsoft.com/en-us/dotnet/api/system.security.cryptography.rsacryptoserviceprovider.keysize#remarks
+            var rsa = new RSACryptoServiceProvider((int)RsaKeySizeUpDown.Value);
+            RsaPrivateKeyTextBox.Text = rsa.ToXmlString(true);
+            RsaPublicKeyTextBox.Text = rsa.ToXmlString(false);
+        }
+    }
+
+    internal static class CommonExtensionMetond
+    {
+        public static T ProcessWhen<T>(this T me, bool when, Func<T, T> process)
+        {
+            return when ? process(me) : me;
+        }
+    }
+
+    internal static class IdentifierChecker
+    {
+        private static readonly CodeDomProvider Provider = CodeDomProvider.CreateProvider("C#");
+
+        public static bool Valid(string word) => Provider.IsValidIdentifier(word);
+    };
+}

+ 120 - 0
MiscToolSet/MainForm.resx

@@ -0,0 +1,120 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+  <!-- 
+    Microsoft ResX Schema 
+    
+    Version 2.0
+    
+    The primary goals of this format is to allow a simple XML format 
+    that is mostly human readable. The generation and parsing of the 
+    various data types are done through the TypeConverter classes 
+    associated with the data types.
+    
+    Example:
+    
+    ... ado.net/XML headers & schema ...
+    <resheader name="resmimetype">text/microsoft-resx</resheader>
+    <resheader name="version">2.0</resheader>
+    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+        <value>[base64 mime encoded serialized .NET Framework object]</value>
+    </data>
+    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+        <comment>This is a comment</comment>
+    </data>
+                
+    There are any number of "resheader" rows that contain simple 
+    name/value pairs.
+    
+    Each data row contains a name, and value. The row also contains a 
+    type or mimetype. Type corresponds to a .NET class that support 
+    text/value conversion through the TypeConverter architecture. 
+    Classes that don't support this are serialized and stored with the 
+    mimetype set.
+    
+    The mimetype is used for serialized objects, and tells the 
+    ResXResourceReader how to depersist the object. This is currently not 
+    extensible. For a given mimetype the value must be set accordingly:
+    
+    Note - application/x-microsoft.net.object.binary.base64 is the format 
+    that the ResXResourceWriter will generate, however the reader can 
+    read any of the formats listed below.
+    
+    mimetype: application/x-microsoft.net.object.binary.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+            : and then encoded with base64 encoding.
+    
+    mimetype: application/x-microsoft.net.object.soap.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+            : and then encoded with base64 encoding.
+
+    mimetype: application/x-microsoft.net.object.bytearray.base64
+    value   : The object must be serialized into a byte array 
+            : using a System.ComponentModel.TypeConverter
+            : and then encoded with base64 encoding.
+    -->
+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+    <xsd:element name="root" msdata:IsDataSet="true">
+      <xsd:complexType>
+        <xsd:choice maxOccurs="unbounded">
+          <xsd:element name="metadata">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" />
+              </xsd:sequence>
+              <xsd:attribute name="name" use="required" type="xsd:string" />
+              <xsd:attribute name="type" type="xsd:string" />
+              <xsd:attribute name="mimetype" type="xsd:string" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="assembly">
+            <xsd:complexType>
+              <xsd:attribute name="alias" type="xsd:string" />
+              <xsd:attribute name="name" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="data">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="resheader">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" />
+            </xsd:complexType>
+          </xsd:element>
+        </xsd:choice>
+      </xsd:complexType>
+    </xsd:element>
+  </xsd:schema>
+  <resheader name="resmimetype">
+    <value>text/microsoft-resx</value>
+  </resheader>
+  <resheader name="version">
+    <value>2.0</value>
+  </resheader>
+  <resheader name="reader">
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+</root>

+ 89 - 0
MiscToolSet/MiscToolSet.csproj

@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="..\packages\ILRepack.2.0.13\build\ILRepack.props" Condition="Exists('..\packages\ILRepack.2.0.13\build\ILRepack.props')" />
+  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProjectGuid>{9A38DF9F-2A22-413A-B51B-5647DCA8F131}</ProjectGuid>
+    <OutputType>WinExe</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>MiscToolSet</RootNamespace>
+    <AssemblyName>MiscToolSet</AssemblyName>
+    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+    <NuGetPackageImportStamp>
+    </NuGetPackageImportStamp>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <PlatformTarget>AnyCPU</PlatformTarget>
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <PlatformTarget>AnyCPU</PlatformTarget>
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup>
+    <RunPostBuildEvent>OnOutputUpdated</RunPostBuildEvent>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="Microsoft.AspNet.Identity.Core, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
+      <HintPath>..\packages\Microsoft.AspNet.Identity.Core.2.2.1\lib\net45\Microsoft.AspNet.Identity.Core.dll</HintPath>
+      <Private>True</Private>
+    </Reference>
+    <Reference Include="System" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Xml.Linq" />
+    <Reference Include="System.Data.DataSetExtensions" />
+    <Reference Include="Microsoft.CSharp" />
+    <Reference Include="System.Data" />
+    <Reference Include="System.Deployment" />
+    <Reference Include="System.Drawing" />
+    <Reference Include="System.Net.Http" />
+    <Reference Include="System.Windows.Forms" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="MainForm.cs">
+      <SubType>Form</SubType>
+    </Compile>
+    <Compile Include="MainForm.Designer.cs">
+      <DependentUpon>MainForm.cs</DependentUpon>
+    </Compile>
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <EmbeddedResource Include="MainForm.resx">
+      <DependentUpon>MainForm.cs</DependentUpon>
+    </EmbeddedResource>
+    <None Include="packages.config" />
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
+    <PropertyGroup>
+      <ErrorText>这台计算机上缺少此项目引用的 NuGet 程序包。使用“NuGet 程序包还原”可下载这些程序包。有关更多信息,请参见 http://go.microsoft.com/fwlink/?LinkID=322105。缺少的文件是 {0}。</ErrorText>
+    </PropertyGroup>
+    <Error Condition="!Exists('..\packages\ILRepack.2.0.13\build\ILRepack.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\ILRepack.2.0.13\build\ILRepack.props'))" />
+  </Target>
+  <PropertyGroup>
+    <PostBuildEvent>if $(ConfigurationName) == Release if not exist $(TargetDir)Packed md $(TargetDir)Packed
+if $(ConfigurationName) == Release $(SolutionDir)packages\ILRepack.2.0.13\tools\ILRepack /ndebug /out:$(TargetDir)Packed\$(TargetFileName) $(TargetPath) Microsoft.AspNet.Identity.Core.dll
+if $(ConfigurationName) == Release if exist $(TargetDir)Packed\$(TargetFileName).config del $(TargetDir)Packed\$(TargetFileName).config</PostBuildEvent>
+  </PropertyGroup>
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+</Project>

+ 36 - 0
MiscToolSet/Properties/AssemblyInfo.cs

@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// 有关程序集的一般信息由以下
+// 控制。更改这些特性值可修改
+// 与程序集关联的信息。
+[assembly: AssemblyTitle("MiscToolSet")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Microsoft")]
+[assembly: AssemblyProduct("MiscToolSet")]
+[assembly: AssemblyCopyright("Copyright © Microsoft 2017")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+//将 ComVisible 设置为 false 将使此程序集中的类型
+//对 COM 组件不可见。  如果需要从 COM 访问此程序集中的类型,
+//请将此类型的 ComVisible 特性设置为 true。
+[assembly: ComVisible(false)]
+
+// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
+[assembly: Guid("9a38df9f-2a22-413a-b51b-5647dca8f131")]
+
+// 程序集的版本信息由下列四个值组成: 
+//
+//      主版本
+//      次版本
+//      生成号
+//      修订号
+//
+//可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值,
+// 方法是按如下所示使用“*”: :
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]

+ 5 - 0
MiscToolSet/packages.config

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+  <package id="ILRepack" version="2.0.13" targetFramework="net45" />
+  <package id="Microsoft.AspNet.Identity.Core" version="2.2.1" targetFramework="net45" />
+</packages>

+ 35 - 0
SoftwareDevelopAssistantTools.sln

@@ -0,0 +1,35 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.29728.190
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EfDbCommentGenerator", "EfDbCommentGenerator\EfDbCommentGenerator.csproj", "{72A3827C-D797-4CBC-BC38-6551FCC04905}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MiscToolSet", "MiscToolSet\MiscToolSet.csproj", "{9A38DF9F-2A22-413A-B51B-5647DCA8F131}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{72A3827C-D797-4CBC-BC38-6551FCC04905}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{72A3827C-D797-4CBC-BC38-6551FCC04905}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{72A3827C-D797-4CBC-BC38-6551FCC04905}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{72A3827C-D797-4CBC-BC38-6551FCC04905}.Release|Any CPU.Build.0 = Release|Any CPU
+		{9A38DF9F-2A22-413A-B51B-5647DCA8F131}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{9A38DF9F-2A22-413A-B51B-5647DCA8F131}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{9A38DF9F-2A22-413A-B51B-5647DCA8F131}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{9A38DF9F-2A22-413A-B51B-5647DCA8F131}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ExtensibilityGlobals) = postSolution
+		SolutionGuid = {715043C9-C42D-4EDE-8B39-7F3D2EA8FA2A}
+	EndGlobalSection
+	GlobalSection(SubversionScc) = preSolution
+		Svn-Managed = True
+		Manager = AnkhSVN - Subversion Support for Visual Studio
+	EndGlobalSection
+EndGlobal