基于Visual Studio 2005,为你的开发团队建立可重用的项目及文件项模板

基于Visual Studio 2005,为你的开发团队建立可重用的项目及文件项模板

作者:Matt Milner

这篇文章将讨论如下话题:
  • 了解已经存在的模板
  • 建立自定义模板
  • 个性化模板
  • 扩展向导
这篇文章将涉及到如下知识:
Visual Studio 2005, XML
文章相关代码下载: CodeTemplates.exe (139 KB)
Browse the Code Online
在我多年从事.NET开发生涯中,我经常听到如下的需求:“如果我们能够创建自己的项目类型或者文件类型,然后公司所有相关开发者都能使用这个模板那就太好了。”很多开发组织都想建立符合自身需求的可以重用的项目或者文件模板,比如我们熟知的在Visual Studio 2005中自带的Web Site项目模板、WebForm文件。很幸运的是,Visual Studio 2005采用了一种新的管理项目及文件模板的模型,这不仅仅让自定义模板成为了可能,并且也使建立自定义模板的过程变的相对简单,这篇文章的后续章节将详细介绍有关Visual Studio 2005中模板的相关知识。
在过去,用户其实已经可以建立自定义模板了,但是这可不是一件容易的事情,建立模板需要大量的相关知识,如:熟悉文档结构、Javascript文件、严格的文件夹命名规范,并且还需要一些小技巧( a little bit of magic)才能让一个模板文件正常运行。但是基于Visual Studio 2005的模板模型,用户仅仅需要建立一个包含模板文件及基于XML格式的元数据文件(用于描述模板文件内容的数据),并把它们统一放在一个zip文件中就可以了。通过这样的方式你可以建立独立的文件项模板:如网页文件(Web Page), 代码文件(C#, Visual Basic等),或者配置文件(Configuration);通过统一的方式,你也可以建立一个项目模板,网站模板;通过统一的方式,你还可以建立包含多个项目的解决方案模板。事实上,在Visual Studio 2005中包含的众多模板文件同样也是基于这样一种模板建立机制。
了解已经存在的模板
学习模板最好的方法无外乎认真了解一下Visual Studio 2005内已经存在的模板。你可以通过如下方式来查找用户自定义模板存放的位置,打开Visual Studio 2005, 从最上方的菜单中选择“工具”->“选项”-> “项目和解决方案”-> “常规”,这样就可以看到文件项模板及项目模板文件保存的文件路径(这里的路径可以使用任何符合“通用命名规则(UNC)”的路径) (如图1所示)。一般的,这些路径都保存在“我的文档(My Documents)”文件夹中。而那些Visual Studio 2005中本身自带(build in templates)的模板文件将默认放在Visual Studio 2005的安装目录下:【Visual Studio 安装目录】/Common7/IDE/ItemTemplates/对应语言(如:Visual C#, Visual Basic)/[Number]/*.zip;
图1 模板文件存放位置设置界面 (可以设置自定义模板文件存放路径)
当将模板包(包含模板相关文件的zip文件)放到用户自定义模板文件存放路径下时(可以直接放在ItemTemplates或者ProjectTemplates目录下,也可以放在对应语言的目录下),对应的模板将会出现在对应类别的选择框内。你可以先使用本文章的例子来进行一个测试(可通过文章开始的链接进行下载)。在将包含模板文件的zip文件放到对应的存放路径下后,启动Visual Studio 2005,然后从菜单中依次选择“文件”-> “新建”-> “项目”,然后你会发现你添加的自定义模板已经显示在“我的模板”类别下(如图2所示)。如果选择了此模板,那么系统将会建立一个新的项目,这个项目中将包含对应模板文件中包含的各个文件项。
图 2 你的自定义模板显示在“我的模板”(My Template)项下
 
好了,现在我们知道了什么?
首先,我们现在知道了用户自定义模板的存放路径是可以配置的,由于路径支持UNC(统一命名规则)我们可以设想一下,我们将自定义模板都放在一个公共的文件服务器上,那么各项目组成员可以通过设置自定义模板存放路径来获取统一的自定义模板信息。并且如果以后有新的模板,或者模板文件内容出现了更新,那么也可以通过这种方式做到一次部署,所有使用模板的项目组都同步更新的目的。
其次,由于模板仅仅实现其模板的功能(单一职责原则),它本身仅有初始化的作用,但是其不被修改。所以模板文件可以方便的重复利用。相较于原来的“复制-粘帖”的传统方式,这是具有优势的,因为如果采用“复制-粘帖”的方式,那么模板在传递过程中很可能被修改,这样后来的使用者将无法使用一个“干净”的模板了(可能拷贝过来的模板中已经包含了本不属于模板的代码了)。
建立自定义模板
学习现有的模板是一个好的开始,但是针对大多数开发者来说他们更想知道如何建立属于他们自己的模板。Visual Studio 2005已经在集成开发环境(IDE)中内嵌了建立模板的辅助工具。一旦你建立了模板,你还可以对其进行扩展和修改。在模板中最容易建立的是“文件项模板”(单个文件的模板,下同)。那我们现在就开始做一个“文件项模板”吧。
首先打开包含你希望将其转化为模板文件的项目,然后从菜单中选择“文件”-> “导出模板”,这样就会启动“导出模板”向导,如图3所示
图 3 导出一个文件项模板
向导首先让你选择需要导出作为模板的文件需要包含的引用文件(一般为.dll程序集文件)。这些引用文件允许当对应模板文件的文件项添加到项目中时,对应的引用文件也添加到项目中。向导中将列举所有默认引用的程序集及当前项目中引用的程序集以供选择。
除了对依赖程序集的引用,“导出向导”还可以智能的导出文件相关的资源文件。比如:如果导出一个.aspx的网页文件作为模板,那么此网页文件对应的页面后台代码文件(CodeBehind File)、资源文件(.resx)也会同时被导出成模板。在将文件项模板转化为对应的文档时,“导出向导”程序同时会在其中添加一些占位符(PlaceHolder),比如类的名称(Class Name)、命名空间名称(Namespace Name)等,这样在不同的项目中这些替换符将被替换成满足具体项目的具体值。比如,你根据模板BusinessObjectClass建立文件项,那么你在新建文件项的时候可以指定类的名称,而不一定是要命名为:BusinessObjectClass。
 
在“导出向导”中还可以为导出模板选择“模板名称”、“模板描述”以及“模板图标”。并且在向导的最后,你还可以选择是否“安装模板”。在“导出模板”后,模板文件(zip文件)将建立到路径“My Documents/Visual Studio 2005/My Exported Templates/”下。但是将模板文件放在此目录下Visual Studio 2005是无法找到的(你在新添文件项的时候在对话框中将无法找到你导出的模板文件)。要想使用模板,必须将此zip文件拷贝放置到在Visual Studio 2005中指定的文件夹中,一般地路径为:My Documents/Visual Studio 2005/Templates/ItemTemplates/。如果在向导的最后你选择了“自动将模板导出到Visual Studio中”的选择框(CheckBox),那么在完成模板导出后,“导出向导”会自动将把生成的模板文件(zip文件)自动拷贝一份到Visual Studio 2005中配置的模板路径下,这样在新添项的时候就可以使用导出的模板了。
 
在“导出向导”完成以后不立刻安装模板主要是出于可能需要人为的对模板内容进行修改的目的,如:我们可能还需要往模板文件的zip文件添加文件,比如:我们建立了一个Master Page的模板,但是我们可以往其中添加CSS文件以便Master Page在建立的时候能够按照指定的样式进行展示,同时因为我们向模板中增加了CSS文件我们还需要同步更新元数据,这是属于“个性化”模板的问题范畴,我们将在文章的后续部分进行讨论。
 
如果你需要建立“项目模板”(我们前面建立的是文件项模板),那么建立的过程基本是一样的。只是在向导中不需要明确指定项目依赖的程序集(assembly),因为项目依赖的程序集信息可以从项目本身的信息中获取(bin文件夹下对程序集的依赖关系)。实际上要说项目模板和文件项模板的不同就在于,项目模板可以建立一个新的项目,但是文件项模板只能在原有的项目中进行添加。
 
个性化模板
 
看到了吧?在Visual Studio 2005中建立模板文件是一件非常轻松的事情。但是就像很多时候一样,默认的方式往往不能完全满足特定的需求。但是很幸运的是的,模板文件其实就是一个包含一些列文件的压缩文件(zip),其中包含了模板文件及一个元数据文件。所以我们也可以很方便的修改其中的内容以达到修改和扩展的目的
 
模板文件的元数据文件是一个XML格式的文件,其中定义了模板文件中应该包含的文件(和文件清单manifest很相似)。
 
 
首先我们注意到的是元数据文件的文件结构,从大体上看文档结构分为VSTemplate根节点和TemplateDataTemplateContent两个子节点。VSTemplate根节点,将TemplateData和TemplateContent内容组合在一起,成为一个整体,并且通过属性Type确定了此模板的类型是针对“文件项”(Item)还是针对"项目"(Project)。因为XML中定义了命名空间(xmlns, xmlnamespace),那么所有开发者在编辑此模板的时候都可以获得Visual Studio 2005智能感知功能的支持,这样可以提高针对.vstemplate文件的编写效率。
 
<TemplateData>节点包含了在使用模板添加新项中对话框显示的信息(就是在项目或者解决方案中添加新项后弹出的对话框)。比如:模板的名称(Name)、描述(Description)模板文件显示的图标(Icon)这些信息都直接显示在添加对话框中。默认名称(DefaultName)用于定义新建文件的默认名称,项目类型(ProjectType)和项目子类型(ProjectSubType)分别用于标识此模板对应的项目类型和编程语言(这里ProjectType和ProjectSubType根据项目类型不同有稍许不同),如上图(图4)中所示ProjectType = web, ProjectSubType = CSharp,那么说明此模板仅能应用于基于编程语言C#的网站项目。
 
图5 列举了其他可供选择的元数据文件的配置节信息,其中也包含了前面提到的一些配置节。
 
<TemplateContent>  配置节是用来定义模板中包含的文件引用的程序集等信息。其中的信息在使用“导出向导”时自动生成,一般不需要修改。
 
每个Zip压缩包中包含的文件都被称为ProjectItem(当然除了包含元数据信息的.vstemplate文件除外),在元数据文件中每个ProjectItem对应一个<ProjectItem>配置节。除了列举所有Zip中包含的文件清单外,ProjectItem配置节中的属性还可以被用来确定一个文件项(ProjectItem)是否还有子类型(subtype),标识一个文件中的占位符是否应该被替换,标识目标文件的名称是否和源文件的名称相同。SubType属性可能的取值为:Form | Component,这个将影响Visual Studio在打开此文件时正确的进行显示。(注意:SubType只有针对VSTemplate.Type = "Item"的模板才有,对于VSTemplate.Type = "Project"的模板是没有这个属性的,在MSDN上其解释为:指定多文件项模板中某个项的子类型。此值用于确定 Visual Studio 用来打开此项的编辑器)
 
ReplaceParameters 属性如果设置为true, 那么在根据模板生成具体文件的时候系统会自动替换其中你的占位符,如:命名空间(namespace)、类名(class Name)等信息,这样模板的内容就具有动态性。如果没有将此属性设置为true,那么在根据模板建立文件的时候,模板内的内容将和zip包中对应文件的内容完全一样,不会有任何改变,这样模板就完全是一个静态的模板了。
 
TargetFileName 属性可以设置为一个常量,也可以是一个参数化的变量,如:$fileinputname$就会将输入的文件名称作为模板生成的具体文件名。
 
建立项目模板的过程和建立文件项模板的过程非常相似,但是还是存在一些细微的差别。首先,因为是针对项目的文档,所有 ProjectItem配置节都隶属于Project配置节。而Project配置节中的属性用于确定建立项目的相关信息。图6是一个项目模板元数据文件内容的简单示例。
 
 
应该注意到的是,在Porject配置节下,除了具有我们已经知道的<ProjectItem>文件,还具有<Folder>配置节,<Folder>配置节顾名思义就是用来标识此项目中具有文件夹及文件夹的信息。这些文件夹将在使用模板建立项目的时候被使用到。同时在项目模板中的<TemplateData>也具有不同的配置节信息,这些信息在图7中进行了展示。
 
网站项目(Web Projects)相较于其他的项目(如:类库项目)具有一定的特殊性(它使用不同的向导进行模板建立),在模板元数据文件中,其他项目的ProjectType 一般用来确定语言,ProjectSubType用于确定类型(如:Windows,Office,DataBase等)。但是在网站项目(web项目)ProjectType为web, 用ProjectSubType用于确定语言。

建立解决方案模板(多个项目)
 
 
除了为单个项目建立模板外,有时候我们需要为针对某个问题领域的解决方案建立模板。比如,很常见的情况,一个开发团队可能不希望仅仅只通过一个网站项目(Web Project)来完成整个项目,他们可能更希望有一个模板可以建立整个解决方案的框架,如:一个解决方案中包含网站、业务逻辑、数据访问三个项目。一种做法是,可能针对这三个项目分别建立项目模板,然后让开发者在建立解决方案的时候逐一的进行项目的添加。另外一种做法,就是一次性将整个解决方案的框架搭建好。
 
包含多个项目的解决方案模板同样也是一个zip文件(而不是多个zip文件),但是其中的玄机就在于包含元数据的文件信息(.vstemplate),在模板中包含了一个解决方案的元数据文件,然后其中包含的所有项目本身也会有自己的元数据文件。解决方案的元数据文件中的TemplateData配置节中包含了指向其子项目元数据文件的信息。图8 展示了一个简单的解决方案元文件的例子,这个解决方案中包含了三个项目:网站项目、业务逻辑层、数据访问层。
 
 
Figure 9 Solution Folder 
 
 
首先注意到根节点<VSTemplate>中的属性Type = "ProjectType",这表示是此模板是一个包含多个项目的解决方案模板。然后我们看到配置节<ProjectCollection>,里面包含了解决方案中包含的三个项目,每个项目对应一个配置节<ProjectTemplateLink>, 其中ProjectName为新建项目的名称;配置节中包含的路径指向项目元数据文件的路径。这个路径是一个相对路径,各个项目的参照路径为文件在zip文件中的相对路径。上面的图8图9通过不同的方式表示了同一个zip模板文件,可以对照一下。(如何利用Visual Studio 2005建立模板文件尚不清楚)

提供向导信息
 
OK,  到目前为止我们讨论的都是建立各种各样的模板,但是想让一个模板能被广泛的应用,好的向导是必不可少的。为了方便使用向导,一种做法是为模板文件进行良好的注释,但是这种方法需要用户查到每个对应的模板文件中然后阅读对应的注释才能知道如何使用这个模板。Visual Studio 2005中提供了一种更加好的做法,它不仅仅是提供了用户可能需要的文档,并且它可以确保当基于模板的新项被添加后对应的说明信息将会显示出来。
 
无论是项目模板还是文件项模板,ProjectItem配置节中的一些属性可以让一些帮助文件方便的向用户展示。如:
OpenInEditor 属性:可供设置值为:0,1,true, false。如果设置为true, 那么Visual Studio 2005会根据文件类型选择对应的编辑器进行打开,比如:如果项目中包含XML文件,那么此文件将被XML编辑器 (XML editor)打开。
OpenInWebBrowser 属性:可供设置值为:0,1,true,false。允许将文本文件或者HTML文件在Web浏览器中打开。这是一种提供帮助文档比较好的方法,你可以在你的模板中增加HTML格式的帮助文档,这样只要在使用你的模板那么帮助文档就会自动打开,这样可以让用户方便的得到帮助。
OpenInHelpBrowser  属性:同样也是接受: 0,1,true,false。允许将文件自动打开到“帮助”查看器中。
以上这些标记为true|1的文件项将会在模板加载以后,对应的文件项会处于打开状态(在Visual Studio 2005中直接显示,而不是需要双击对应的文件才能进行显示)。以上是将文件显示在不同载体的属性。
 
除了可以设定打开文档的方式,也可以通过ProjectItem的OpenOrder属性来设定对应文档的显示顺序。OpenOrder中的数字越小那么打开的优先级就越高,并且打开文件的选项卡将显示的越靠前(选项卡靠左)

参数替换(Parameter Replacement)
 
到目前为止,我们举的例子中间涉及到的参数替换主要是模板中的名称(如:项目名称、类名称、命名空间名称等)。这些需要动态替换的值在模板中是以一些占位符(PlaceHolder)的方式存在的,有些占位符存在于元数据文件中,有些则存在于模板文件本身的内容中。在通过模板生成对应具体文件时,系统会将具体的值(如:用户输入的文件名称)替换文件中对应的占位符。Visual Studio 2005中已经内置了一些有用的占位符,同样你也可以定义自己的占位符。
 
如果需要通知Visual Studio 2005在建立文件进行替换,那么对应的项目(Project)或者文件项(ProjectItem)配置节中都需要将ReplaceParameters配直节属性设置为True(事实上也就是<Project>和<ProjectItem>这两个配置节是使用替换最多的地方)。当在利用Visual Studio 2005建立基于某个特定模板的具体文件时,生成向导首先检查<Project>和<ProjectItem>中属性ReplaceParameters设置为true的项,然后对对应的文件项进行处理,然后根据替换值字典(将替换值替换成对应的值)将文件内容中已知的占位符 (PlaceHolder)设置为具体值。图10的表格中就展示了一些Visual Studio 2005中内置的占位符。
如果以上的占位符不能满足要求的话,用户可以自定义占位符,这些占位符同样可以在元数据文件、模板文件在使用。要添加自定义占位符那么首先你需要在.vstemplate文件中的<TemplateContent>的配置节中增加<CustomParameters>子配置节,<CustomParameters>中具有两个属性,分别为:name, value(如图11所示), 其中name是占位符标识,而value是其替换的值,并且占位符的名称必须符合如此格式:$parametername$。(感觉自定义的占位符有点像常变量)

扩展向导 (Extending the Wizard)
如果以上提到的所有方式(包括:通过修改.vstemplate文件内容,新增自定义的占位符)都不能满足你对模板的需求,那么可能就需要通过编写一些代码的方式来实现对应的需求。你可以编写一个扩展向导(wizard extension)并在元数据文件中进行配置。比如:考虑这样一种情况,你可能有一些模板文件项包括在zip文件中,在通过模板生成对应的文件项时,可能你需要动态的包括一些文件,也可能需要动态剔除一些文件。在这种情况下,通过扩展向导可以更改传统的添加新项目和新文件项的方式,通过你编写的代码来决定是包括/剔除哪些模板文件,并且你也可以通过扩展向导动态的向.vstemplate文件中添加自定义的占位符。(实际上将从模板产生具体文件可以看成是一个如同ASP.NET页面生命周期一样,是一个管道,在管道中分为各个阶段,各个阶段通过一定的方式暴露了一些插槽,我们可以自定义的实现一些符合这些插槽规范的处理代码,这样在管道的处理过程中就可以看成是进行了应用的扩展)
创建向导扩展你需要通过Visual Studio建立一个类库项目(.NET Library Project)并且在项目中引用Microsoft.VisualStudio.TemplateWizardInterface.dll及EnvDTE.dll程序集。在类库项目中建立一个类,这个类要实现Microsoft.VisualStudio.TemplateWizardInterface.IWizard接口。以下就是这个接口的定义。
 
public interface IWizard
{
    void BeforeOpeningFile(EnvDTE.ProjectItem projectItem) ;
    void ProjectFinishedGenerating(EnvDTE.Project project);    
    void ProjectItemFinishedGenerating(EnvDTE.ProjectItem projectItem);
    void RunFinished();
    void RunStarted(object automationObject, 
        Dictionary<string, string> replacementsDictionary,
        WizardRunKind runKind, 
        object[] customParameters);
    bool ShouldAddProjectItem(string filePath);
}
其中:
BeforeOpeningFile: 在打开模板中的项之前运行自定义向导逻辑;
ProjectFinishedGenerating: 当项目已完成生成时运行自定义向导逻辑;
ProjectItemFinishedGenerating: 当项目项已完成生成时运行自定义向导逻辑;
RunFinished: 当向导已完成所有任务时运行自定义向导逻辑; (用于在向导完成以后实现一些清理工作)
RunStarted: 在模板向导运行的开头运行自定义向导逻辑; (主要用于在启动向导前进行初始化)
ShouldAddProjectItem: 指示是否应将指定的项目项添加到项目中。(这里可以进行裁剪加载到项目中文件项)
 
为了在模板中使用扩展向导,你必须在完成了扩展向导以后修改.vstemplate文件的相关内容,需要在内容中增加WizardExtension的配置节,配置节中将包含程序集信息和类的完全命名(FullClassName)。配置节的结构如图12所示。当生成项目或者文件项的向导运行的时候,配置的扩展向导将同时被加载,并且IWizard接口中定义的方法也会在对应的时间中被调用,从而影响整个根据模板向导生成文件的过程。

结论
Visual Studio 2005中对建立模板的功能和方式进行了很大的改进,建立可重用的,动态的模板可以为建立统一风格的,健壮的系统打下良好的基础。通过单一的zip文件和基于XML格式的.vstemplate元数据定义文件使对模板的修改和自定义变得更加直观和方便。另外, Visual  Studio 2005的“导出模板”功能使模板的初始建立非常简单。本文最开始也提供了一些简单的模板进行下载,同样你也可以通过MSDN中Visual Studio Template Schema的相关章节内容得到有关自定义模板的更多相关知识。

作者简介:
Matt Milner is an independent software consultant specializing in Microsoft technologies including .NET, Web services, XML, and BizTalk Server. As an instructor for Pluralsight, Matt teaches courses on Web services, BizTalk Server and ASP.NET. Matt lives in Minnesota with his wife Kristen and his son Max.

阅读更多
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页