利用Visual Studio 2017的扩展开发(VSIX、ItemTemplate) 快速实现项目的半自动化搭建

目录html

0.引言前端

1.什么是Visual Studio项目模板git

2.IWizad接口github

3.经过Visual Studio扩展开发实现领域驱动开发web

3.1 使用VSIX+ProjectTemplate建立项目模板安全

3.2使用ItempTemplate建立自定义项模板服务器

3.3实现可视化添加实体字段,自动生成应用层(Dto、IAppService、AppService)、领域层(Entity)、展示层(Views、Controller)、基础设施层(IRepository)等。架构

4.结语app


文章是有图片的,若是图片打不开请访问CSDNhttps://blog.csdn.net/lynchee/article/details/83065608

0.引言

        最近一直在学习博客【老张的哲学】的.NET Core2.0 Api + Vue 2.0的系列文章,经过边看边本身动手实践,本身对一些概念有了更深刻的理解(如依赖注入、前端的一些知识、VUE框架),原本也计划好经过该系列文章好好学习一下VUE框架并应用到实际的项目中的,特此还重点突击了一个星期左右,但最后发现自身功力不够(毕业3年都没有敲过代码,加之以前只是作过一些win form的简单开发,Web知识仍是比较欠缺的,因为工做的须要今年才从新捡起来),因此是后仍是放弃了。哈哈,扯远了......下面开始进入正题框架

       在【老张的哲学】的系列教程第32篇博文中博主主要介绍了快速实现项目的半自动化搭建的四种方式:动软代码生成器、VSTO、T4模板、SqlSuagr等,按个人理解我以为这几种方式,无非就是事先定义好一些模板,而后按各自的方法生成相应的文件(好像这句话等于没有说,哈哈.....),这几种方式确实在实际的工做中能够减小不少重复性的工做,并且本身经过这大半年的开发工做中,也深有感触是颇有必要找到一种适合的方式来减小这些没必要要的工做量(不瞒你们说,也不怕你们笑话,最近的项目开发中的CRUD真的是我本身一行一行敲出来的),今天的话主要在博主的基础上在介绍另一种方式:VSIX插件+ItemTemplate+ProjectTemplate来实现一样的目的,这里的话主要是介绍基础的,后面在根据项目的须要完善。本人也没有写过技术博客,若是写得很差或有误,请你们多多包含和批评指正。

1.什么是Visual Studio项目模板

       说了那么多,你们可能仍是比较蒙圈(也多是我没有解释清楚),直接来3张图(以下所示),在日常的开发过程当中,你们确定常常经过在项目中右键建立类、接口、Windows窗体、用户控件等,其实这些就是Visual Studio自身提供的一些模板,如新建一个Windows窗体后,窗体的大小、颜色、显示的名称都已经定义好了,不须要用户在敲一大堆代码才能把这个窗体显示出来,本文就是经过这种方式快速实现项目的半自动化搭建。

【新建项】

【新建Windows窗体】

【Form1】

 

2.IWizad接口

       在开始操做前,首先说说“IWizard”接口:

       Visual Stdudio提供了IWizard接口,该接口提供了几个方法帮助用户在建立模板项时可运行自定义的代码,见下表,本文就是经过这个接口实现的。

  Name Description
System_CAPS_pubmethod BeforeOpeningFile(ProjectItem)

Runs custom wizard logic before opening an item in the template.

System_CAPS_pubmethod ProjectFinishedGenerating(Project)

Runs custom wizard logic when a project has finished generating.

System_CAPS_pubmethod ProjectItemFinishedGenerating(ProjectItem)

Runs custom wizard logic when a project item has finished generating.

System_CAPS_pubmethod RunFinished()

Runs custom wizard logic when the wizard has completed all tasks.

System_CAPS_pubmethod RunStarted(Object, Dictionary<String, String>, WizardRunKind, Object[])

Runs custom wizard logic at the beginning of a template wizard run.

System_CAPS_pubmethod ShouldAddProjectItem(String)

Indicates whether the specified project item should be added to the project.

3.经过Visual Studio扩展开发实现领域驱动开发

3.1 使用VSIX+ProjectTemplate建立项目模板

        什么是领域驱动开发,哈哈......有兴趣的能够去深刻了解一下,之因此提起这个概念,主要是最近在Github上了解到ABP这个开源项目,目前start的人数多达5.5k,网址asp.net boilerplate,这个框架比较好的实现了领域驱动开发这个概念(听说也不是彻底符合领域驱动设计的概念,具体的话还须要本身深刻了解学习),自我认为这是个比较好的学习框架,里面涉及到比较多新的技术和知识(对于我来讲基本上是新知识),你们有时间能够抽空看看,后期我也计划把该框架应用到实际的项目中去,哈哈......又扯远了。

 下面正式进入正题:

1.建立项目模板,命名为FirstProjectTemplate。并打开该项目下的Class1.cs文件,随意输入一些注释,有啥用?请耐心等待。

备注:若是没有Extensibility这个分类,请在更新与扩展里安装。

2.添加新的VSIX项目,命名为FirstProjectWizard,并把该项目设置为启动项目。

3.在FirstProjectWizard项目中双击打开source.extension.vsixmaifest文件,填写Product Name、Author、Version、Desription等基本信息。

4.在3打开的文件中,在左侧栏中切换到Assets选项卡,单击【New】新建一个Asset(中文不知道翻译成啥好,哈哈...),Type选择Microsoft.VisualStudio.ProjectTemplate,Source选择A Project in current solution,Project选择FirstProjectTemplate,其它设置见图。

5.按F5 生成解决方案并启动调试,将打开另外一个Visual Studio实例(这可能须要几分钟的时间,电脑配置好点估计秒开...),仔细的估计会注意到Visual Studio窗口多了【实验实例】几个字,这个具体拿来干啥的,有兴趣的能够百度一下,哈哈...

6.在刚刚打开的Visual Sdudio窗口新建一个项目,弹出的【新建项目】窗口,在右上角输入first,选中FirstProjectTemplate,单击肯定。

7.打开刚新建项目中的Class1.cs,哦哦...刚在1步骤中注释的语句出现了,是否是尝到了胜利的味道。或许说到这里,你们已经大概了解到思路了,恭喜你离成功更靠近一步了....加油,请给点耐心哟。

3.2使用ItempTemplate建立自定义项模板

本节主要介绍经过自定义一些参数,实如今添加项时项模板能按要求输出,好了...话很少说,直接演示。

1.在3.1建立的解决方案中,新建一个项项目(ItemTemplate),命名FirstItemTemplate

2.选中3.1中建立的FirstProjectWizard项目,按F4弹出属性窗口,设置如图三个属性字段为ture。

3.将FirstProjectWizard、FirstItemTemplate做为Asset添加到VSIX项目中。双击打开source.extension.vsixmanifest 文件,并切换到Asset窗口中,相关设置见下图。

【添加FirstProjectWizard】

【添加FirstItemTemplate】

【添加后的Asset】

4.添加VSIX开发要用到的相关类库。在FirstProjectWizard项目下的引用鼠标右键,添加

EnvDTE、Microsoft.VisualStudio.TemplateWizardInterface、System.Drawing、System.Windows、System.Windows.Forms等。

5.在FirstProjectWizard项目中添加类,并命名为WizardImplementation,并继承IWizard接口,具体代码以下:

using EnvDTE;
using Microsoft.VisualStudio.TemplateWizard;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace FirstProjectWizard
{
    public class WizardImplementation : IWizard
    {
        private CustomFieldForm customFieldForm;
        private string customField;

        public void BeforeOpeningFile(ProjectItem projectItem)
        {
           
        }

        public void ProjectFinishedGenerating(Project project)
        {
           
        }

        public void ProjectItemFinishedGenerating(ProjectItem projectItem)
        {
            
        }

        public void RunFinished()
        {
            
        }

        public void RunStarted(object automationObject, Dictionary<string, string> replacementsDictionary, WizardRunKind runKind, object[] customParams)
        {
            try
            { 
                customFieldForm = new CustomFieldForm();
                customFieldForm.ShowDialog();

                customField = CustomFieldForm.CustomField;

                //添加自定义参数 
                replacementsDictionary.Add("customField",
                    customField);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
            }
        }

        public bool ShouldAddProjectItem(string filePath)
        {
            return true;
        }
    }
}

6.在FirstProjectWizard项目中添加Windows窗体,命名为CustomFieldForm,具体代码以下:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace FirstProjectWizard
{
    public partial class CustomFieldForm : Form
    {
        private static string customField;

        public CustomFieldForm()
        {
            InitializeComponent();
        }

        public static string CustomField
        {
            get
            {
                return customField;
            }
            set
            {
                customField = value;
            }
        }

        private void button1_Click(object sender, EventArgs e)
        {
            customField = textBox1.Text;
        }
    }
}

7.添加程序集签名。选中FirstProjectWizard项目,右键单击,选中项目属性,切换到签名栏,勾选为程序集签名,输入秘钥文件名称key.snk,去掉勾选使用密码保护秘钥文件,相关设置见下图。

8.选中FirstProjectWizard项目,按F4弹出属性窗口,设置复制生成输出到输出目录字段true,并从新生成解决方案。

9.将刚生成的key.snk秘钥文件拷贝到C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.6.1 Tools目录下,运行cmd(须要管理员身份运行),并cd到C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.6.1 Tools该目录下,输入:

sn.exe -p key.snk outfile.key

10.从key.snk中获取公钥,在命令窗口输入,如图 并记下该公钥。

sn.exe -t outfile.key

11.将对自定义向导的引用添加到项目模板的.vstemplate 文件。分别找到FirstItemTemplate、FirstProjectTemplate项目中的两个vstemplate文件,在<TemplateContent>节点后面添加以下代码,最终如图。

  <WizardExtension>
    <Assembly>FirstProjectWizard, Version=1.0.0.0, Culture=Neutral, PublicKeyToken=df318ff0a21a5d6d</Assembly>
    <FullClassName>FirstProjectWizard.WizardImplementation</FullClassName>
  </WizardExtension>

12.保存全部文件,并从新生成解决方案。按F5运行,打开刚刚建立的FirstProjectTemplate1项目,右键添加新项,弹出【添加新项】窗口,在右上角搜索first,哈哈...FirstItemTemplate出现啦...成功八九十

3.3实现可视化添加实体字段,自动生成应用层(Dto、IAppService、AppService)、领域层(Entity)、展示层(Views、Controller)、基础设施层(IRepository)等。

      好啦,经过3.一、3.2的介绍基本的框架已经搭建起来啦,下面就在ABP架构的基础上实现经过可视化添加实体,快速自动生成领域驱动设计各层的部分文件,注意只是部分哈,不要纠结是否符合领域驱动设计

     在开始前,首先介绍一下【模板参数】,见下表,replacementsDictionary共有23个系统自带的参数,经过键值(Dictionary)保存,固然用户能够经过自定义参数添加到字典中,具体有什么做用,请见后文。

参数 描述
clrversion 公共语言运行时 (CLR) 的当前版本。
GUID [1-10] 一个用于替换项目文件中的项目 GUID 的 GUID。 可指定最多 10 个惟一的 GUID(例如,guid1)
itemname “添加新项”对话框中由用户提供的名称。
machinename 当前的计算机名称(例如,Computer01)。
projectname “新建项目”对话框中由用户提供的名称。
registeredorganization 来自 HKLM\Software\Microsoft\Windows NT\CurrentVersion\RegisteredOrganization 的注册表项值。
rootnamespace 当前项目的根命名空间。 此参数仅适用于项模板。
safeitemname 用户在“添加新项”对话框中提供的名称,名称中移除了全部的不安全字符和空格。
safeprojectname 用户在“新建项目”对话框中提供的名称,名称中移除了全部的不安全字符和空格。
time 以 DD/MM/YYYY 00:00:00 格式表示的当前时间。
SpecificSolutionName 解决方案的名称。 在选中“建立解决方案目录”时,SpecificSolutionName 具备解决方案名称。 在未选中“建立解决方案目录”时,SpecificSolutionName 为空。
userdomain 当前的用户域。
username 当前的用户名称。
webnamespace 当前网站的名称。 此参数在 Web 窗体模板中用于保证类名是惟一的。 若是网站在 Web 服务器的根目录下,则此模板参数会解析为 Web 服务器的根目录。
year 以 YYYY 格式表示的当前年份。

1.在FirstItemTemplate项目中,双击打开vstemplate文件,找到文件自动生成的<ProjectItem>,随后跟着添加多几个<ProjectItem>,具体以下:

    <!--safeitemname    用户在“添加新项”对话框中提供的名称,名称中移除了全部的不安全字符和空格-->
    <ProjectItem ReplaceParameters="true" TargetFileName="$safeitemname$.cs">Core\Entity.cs</ProjectItem>
    <ProjectItem ReplaceParameters="true" TargetFileName="Temp\I$safeitemname$AppService.cs">Application\IAppService.cs</ProjectItem>
    <ProjectItem ReplaceParameters="true" TargetFileName="Temp\$safeitemname$AppService.cs">Application\AppService.cs</ProjectItem>
    <ProjectItem ReplaceParameters="true" TargetFileName="Temp\$safeitemname$Dto.cs">Application\EntityDto.cs</ProjectItem>
    <ProjectItem ReplaceParameters="true" TargetFileName="Temp\$safeitemname$ListDto.cs">Application\EntityListDto.cs</ProjectItem>
    <ProjectItem ReplaceParameters="true" TargetFileName="Temp\Index.cshtml">UI\Index.cshtml</ProjectItem>
    <ProjectItem ReplaceParameters="true" TargetFileName="Temp\Index.js">UI\Index.js</ProjectItem>
    <ProjectItem ReplaceParameters="true" TargetFileName="Temp\$safeitemname$Controller.cs">UI\Controller.cs</ProjectItem>
    <ProjectItem ReplaceParameters="true" TargetFileName="Temp\I$safeitemname$Repository.cs">Infrastructure\IRepository.cs</ProjectItem>

2.对照在1中添加的配置新建相应文件,如Entity.cs、IAppService.cs,最终结构见下图。

3.利用模板参数replacementsDictionary实现自定义项模板,如Entity.cs类以下图,其它按照本身的需求实现,思路就是用replacementsDictionary里的值进行替换,若是你们有更好的思路,欢迎你们提出。

using Abp.Domain.Entities;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.Text;

namespace $rootnamespace$
{
    [Table("Abp$safeitemname$s")]
    public class $safeitemname$ : Entity<long>, IMayHaveTenant, IPassivable
    {
        //实现IMayHaveTenant,IPassivable
        public virtual int? TenantId { get; set; }
        public virtual bool IsActive { get; set; }

       //自定义的字段
       public virtual string $customField$ {get;set;}
    }
}

4.在WizardImplementation类的ProjectItemFinishedGenerating( )方法中,实现文件的放到指定的工程目录下。PS:目前的方法比较笨,主要实现思路是先根据模板生成文件,而后Copy一份到指定的目录,而后把源文件Delete。你们若有好的方法,请多多留言。代码以下:

   public void ProjectItemFinishedGenerating(ProjectItem projectItem)
        {
            //服务层
            if (projectItem.Name.IndexOf("AppService") > 0)
            {
                if (!projectItem.IsOpen) projectItem.Open();

                foreach (var item in _dte.Solution.Projects)
                {
                    var project = (Project)item;
                    //找到服务层的项目
                    if (project.Name.IndexOf("Application") > 0)
                    {
                        bool flagAppService = false;
                        ProjectItem folder = null;
                        foreach (var folderItem in project.ProjectItems)
                        {
                            var tmp = (ProjectItem)folderItem;
                            if (tmp.Name.IndexOf("AppService") > -1)
                            {
                                flagAppService = true;
                                folder = tmp;
                            }
                        }
                        //不存在文件夹则建立                 
                        if (!flagAppService)
                            folder = project.ProjectItems.AddFolder("AppService");

                        folder.ProjectItems.AddFromFileCopy(projectPath + @"AppService\" + projectItem.Name);
                    }
                }
            }
        }

5.继续按F5运行,打开Visual Studio【实验实例】,新建一个解决方案,包含两个工程,以下图:

6.在CenterInfo.Core工程中右键新建项,弹出添加新项对话框,找到FirstItemTemplate,命名为Depart。

7.弹出建立【Depart】实体对话框,这里主要模拟建立包含Name字段的实体类,单击肯定。

8.哇...最终生成以下图,搞了半天就这么点东西。

4.结语

       终于写到结语了,说实话写个技术博客真不容易(这篇博客花了2天的时间收集资料,1天的时间本身动手实践,而后几个小时的时间完成编写)......在第3小节说好的【经过Visual Studio扩展开发实现领域驱动开发】,哈哈,都是骗人的,只是为了吸引你们的眼球,好啦,坑我就挖到这里,剩下的由你们把这个坑补完。

      (后续有时间会把【经过Visual Studio扩展开发实现领域驱动开发】实现,期待着...)

相关文章
相关标签/搜索