65.9K
CodeProject 正在变化。 阅读更多。
Home

使用项目模板和向导扩展

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.38/5 (7投票s)

2012年5月30日

CPOL

6分钟阅读

viewsIcon

44020

创建自定义项目模板,让您的团队可以用于快速开发。

引言

项目模板和项模板是 Visual Studio 中隐藏的开发宝藏。它们不仅可以缩短开发时间,还能强制实施任何架构概念,尤其是在大型项目中。

这不是我第一次尝试撰写关于项目模板的文章,但我正在尝试解决我在最近工作中开发的所有内容。未来,我可能会扩展这篇文章以涵盖未来的方面。

背景

项目模板和项模板为企业解决方案提供了通用的项目结构。当您在一个或多个解决方案中拥有多个相似的项目时,项目模板非常有用。它提供了通用的项目引用、类结构、默认实现等等。

在此处获取有关项目和项模板的更多信息:此处

Using the Code

在本文中,我们将创建一个带有向导扩展的自定义项目模板。您可以在 MSDN 网站上找到更多关于项目模板的信息:此处。我们将使用向导扩展在创建项目时获取用户的输入。

在我们的解决方案中,我们将假定所有项目都实现了 MyProjectTemplate.BaseProject 类和 IDisposable 接口。

using MyProjectTemplate.BaseProject;
namespace MyExternalService
{
    public class ExternalService : BaseService, IDisposable
    {
    }
}

创建基础项目模板

要创建项目模板,我们需要一个基础项目模板,其中我们引用外部引用、自定义类、自定义外部文件(将在向导中输入文件)。可以将其扩展到各种组合,如配置文件、命名空间等。

我们可以使用项目模板属性来修改此项目及其类。

创建项目

创建一个项目并添加所有必需的引用,包括 MyProjectTemplate.DLL

您还需要将 Request.XMLResponse.XML 添加到资源文件夹中。

添加默认类

现在向项目中添加一个类 MyExternalService,并为其实现 BaseServiceIDisposable

using MyProjectTemplate.BaseProject;
 
namespace MyExternalService
{
    public class MyExternalService : BaseService, IDisposable
    {
 
        public override string Action
        {
            get { return "POST"; }
        }
 
        public override bool ValidateRequest(object context, object request)
        {
            if (!base.ValidateRequest(context, request)) return false;
 
            //Do customized request validation

            return true;
        }
 
        public override int SLA
        {
            get { return 30; }
        }
 
        public override int Timeout
        {
            get { return 20; }
        }
 
        protected override string RequestXML
        {
            get { return "MyExternalService.Resources.Request.XML"; }
        }
 
        protected override string ResponseXML
        {
            get { return "MyExternalService.Resources.Response.XML"; }
        }
 
        protected override string TargetURL
        {
            get { return "https:///MyExternalService"; }
            // do the default request header mapping using requestHeader
        }
 
        public void Dispose()
        {
            //Release local XML file
        }
    }
}  

确保项目能够编译,以便当您创建模板时,您创建的项目不会引入任何错误。

替换项目中的参数

现在我们的项目已准备好替换参数。

在上面的类中,将命名空间和类名 MyExternalService 替换为 $projectname$。您也可以在 RequestXMLResponseXML 属性中替换 $projectname$,以便新属性引用新创建项目中的 XML 文件。

在替换完上述类中的参数后,我们的项目将如下所示:

using MyProjectTemplate.BaseProject;
namespace $projectname$
{
    public class $projectname$ : BaseService, IDisposable
    { 
        public override string Action
        {
            get { return "POST"; }
        }
 
        public override bool ValidateRequest(object context, object request)
        {
            if (!base.ValidateRequest(context, request)) return false;
 
            //Do customized request validation

            return true;
        }
 
        public override int SLA
        {
            get { return 30; }
        }
 
        public override int Timeout
        {
            get { return 20; }
        }
 
        protected override string RequestXML
        {
            get { return "$projectname$.Resources.Request.XML"; }
        }
 
        protected override string ResponseXML
        {
            get { return "$projectname$.Resources.Response.XML"; }
        }
 
        protected override string TargetURL
        {
            get { return "https:///MyExternalService"; }
            // do the default request header mapping using requestHeader
        }
 
        public void Dispose()
        {
            //Release local XML file
        }
    }
} 

注意:现在不用担心,您将无法编译项目,但目前是可以的。

导出项目模板

现在选择此项目,然后在 Visual Studio 的“文件”菜单中单击“导出模板”,此时应该会出现“导出模板向导”。

在“导出模板向导”中选择项目,然后单击“下一步”。

提供模板名称、描述、图标和默认预览图像,然后单击“完成”按钮。

将项目导出为项目模板后,您导出的项目现在应该出现在 Visual Studio 的“添加/创建项目”列表中的“项目模板”列表中。

此项目模板仍然是基础的,并且不接受来自用户的输入,例如 XML 文件、URL、超时等。

要为项目模板实现更多自定义,您需要使用向导扩展,在该扩展中,您将创建一个窗体来输入用户的输入,最终将其用于使用项目模板创建新项目。

您可以在 Visual Studio 2005 项目和项模板 中找到详细实现。

创建向导扩展

如前一节所述,要在创建新项目时添加用户输入,我们将添加一个向导扩展,它使用输入窗体。

要创建向导扩展,我们必须添加一个类库项目。在此练习中,我们将执行以下强制性功能。

  • 添加一个继承自 IWizard 接口的类,该接口是 Microsoft.VisualStudio.TemplateWizard 命名空间的一部分。
  • 添加一个 Windows 窗体,并提供诸如“打开文件对话框”、“文本框”和“提交”按钮之类的输入字段。
  • 创建一个强类型程序集(使用强密钥),并将其注册到 GAC。

添加一个属性类来存储用户的输入。

添加一个仅具有 get/set 属性(DTO)的 ProjectProperty 类。此类将有助于存储和传输用户输入数据从窗体。您可以根据自己的需求自定义此类。

public class ProjectProperty
{
    public string Method = "POST";
    public string RequestSchemaFilePath = "";
    public string RequestSchemaFile = "";
    public string ResponseSchemaFilePath = "";
    public string ResponseSchemaFile = "";
    public int SLA = 20;
    public int TimeOut = 15;
    public string ExactTargetURL = @"https://MyWebservice.com/AddCustomer.asmx";
}   

添加一个包含所有自定义输入的 Windows 窗体。

添加一个包含所有自定义控件的 Windows 窗体,并公开一个类型为 ProjectProperty 的属性。这样,当用户提交窗体时,向导就可以从公开的属性中获取控件值。

public ProjectProperty ESInterfaceProject
{
    get { return this.projectProperty; }
}

private void btnSubmit_Click(object sender, EventArgs e)
{
    int.TryParse(txtSLA.Text, out this.projectProperty.SLA);
    int.TryParse(txtTimeout.Text, out this.projectProperty.TimeOut);
    this.projectProperty.ExactTargetURL = txtTargetURL.Text;
    this.projectProperty.Method = txtMethod.Text;
    this.Close();
} 

实现 IWizard 接口。

添加一个实现 IWizard 接口的类。

namespace MyProjectTemplate
{
    public class MyCustomWizard : IWizard
    {
    }
}  

IWizard 实现 RunStarted 方法,从此方法显示您的 Windows 窗体,并将所有自定义值(ProjectProperty)映射到 replacementsDictionary 集合。

public void RunStarted(object automationObject, Dictionary<string, 
string> replacementsDictionary, WizardRunKind runKind, object[] customParams)
{
    try
    {
        // Display a form to the user. The form collects 
        // input for the custom message.
        inputForm = new SchemaForm();
        inputForm.ShowDialog();
        
        //customMessage = inputForm.get_CustomMessage();
        
        // Add custom parameters.
        replacementsDictionary.Add("$path1$",
            inputForm.ESInterfaceProject.RequestSchemaFilePath);
        replacementsDictionary.Add("$path2$",
            inputForm.ESInterfaceProject.ResponseSchemaFilePath);
        replacementsDictionary.Add("$file1$",
            inputForm.ESInterfaceProject.RequestSchemaFile);
        replacementsDictionary.Add("$file2$",
            inputForm.ESInterfaceProject.ResponseSchemaFile);
        replacementsDictionary.Add("$method$",
            inputForm.ESInterfaceProject.Method);
        replacementsDictionary.Add("$sla$",
            inputForm.ESInterfaceProject.SLA.ToString());
        replacementsDictionary.Add("$timeout$",
            inputForm.ESInterfaceProject.TimeOut.ToString());
        replacementsDictionary.Add("$targeturl$",
            inputForm.ESInterfaceProject.ExactTargetURL);
            
        EnvDTE.DTE dte = automationObject as EnvDTE.DTE;
        
        string solutionPath = System.IO.Path.GetDirectoryName(dte.DTE.Solution.FullName);
        string projectPath = System.IO.Path.GetDirectoryName(dte.DTE.FullName);
        
        replacementsDictionary.TryGetValue("$projectname$", out projectPath);
        
        projectPath = solutionPath + "\\" + projectPath;
        
        string xsdPath = projectPath + @"\Resources";
        
        replacementsDictionary.Add("$xsdpath$",
            xsdPath);
            
        this._xsdPath = xsdPath;
        
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.ToString());
    }
} 

将文件添加到项目中

您无法在 RunStarted 方法中将文件添加到项目结构中,因为在 RunStarted 方法执行时,项目结构已在Temp 文件夹中创建,并且 DTE 正在尝试从Temp 文件夹中读取不存在的文件。

另一个问题是您无法在项目目录中创建任何文件和文件夹,因为在创建文件/文件夹时,IO 会创建项目文件夹,并在 RunStarted 方法之后,DTE 会出现错误,因为它已经拥有项目文件夹,并且它假设项目已经创建。

因此,最终的解决方案是,您需要在项目创建完成后复制文件,这可以通过实现 RunFinished 方法来实现,该方法在 DTE 完成项目创建任务时执行。

public void RunFinished()
{
    // To copy a folder's contents to a new location:
    // Create a new target folder, if necessary.
    if (!System.IO.Directory.Exists(_xsdPath))
    {
        System.IO.Directory.CreateDirectory(_xsdPath);
    }
    // copy files
    System.IO.File.Copy(inputForm.ESInterfaceProject.RequestSchemaFilePath, _xsdPath + 
    "\\" + inputForm.ESInterfaceProject.RequestSchemaFile, true);
    System.IO.File.Copy(inputForm.ESInterfaceProject.ResponseSchemaFilePath, _xsdPath + 
    "\\" + inputForm.ESInterfaceProject.ResponseSchemaFile, true);
}

注册到 GAC

使用强密钥编译上述 DLL 后,将其注册到 GAC。这是一个强制性步骤,因为项目模板可以访问 GAC。

再次更新项目模板

现在我们已经准备好了使用 IWizard 接口的自定义向导扩展。在本节中,我们将向项目中添加替换参数。

在项目模板类中更新参数后,它将如下所示:

using MyProjectTemplate.BaseProject;
namespace $projectname$
{
    public class $projectname$  : BaseService, IDisposable
    {
 
        public override string Action
        {
            get { return "$method$"; }
        }
 
        public override bool ValidateRequest(object context, object request)
        {
            if (!base.ValidateRequest(context, request)) return false;
 
            //Do customized request validation

            return true;
        }
 
        public override int SLA
        {
            get { return $sla$; }
        }
 
        public override int Timeout
        {
            get { return $timeout$; }
        }
 
        protected override string RequestXML
        {
            get { return "$projectname$.Resources.$file1$"; }
        }
 
        protected override string ResponseXML
        {
            get { return "$projectname$.Resources.$file2$"; }
        }
 
        protected override string TargetURL
        {
            get { return "$targeturl$"; }
            // do the default request header mapping using requestHeader
        }
 
        public void Dispose()
        {
            //Release local XML file
        }
    }
} 

导出项目

现在,以与之前导出相同的方式再次导出上述项目。

更新 .vstemplate 文件

现在更新 .vstemplate 文件,并使用向导扩展进行更新。

在记事本中打开 .vstemplate 文件,并添加以下代码,然后保存。

<VSTemplate Version="3.0.0" 
xmlns="http://schemas.microsoft.com/developer/vstemplate/2005" 
Type="Project">
  <TemplateData>
    ...
  </TemplateData>
  <TemplateContent>
    ...
  </TemplateContent>
  <WizardExtension>
    <Assembly>MyProjectTemplate, Version=1.0.0.1, 
Culture=Neutral, PublicKeyToken=27092cf962afb8d7</Assembly>
    <FullClassName>MyProjectTemplate.MyCustomWizard</FullClassName>
  </WizardExtension>

</VSTemplate>    

将其压缩并保存在“我的导出模板”位置。

现在,从“我的导出模板”位置压缩整个项目模板和 .csprj 文件。

最后

我们的自定义项目模板(带有向导扩展)几乎准备就绪。如果一切就绪,您将在 Visual Studio 的“添加/创建项目”菜单中看到项目模板。

当您创建一个新项目时,系统将提示用户输入文件和其他输入,这些信息将用于生成类和项目。您可能需要手动将Resources 文件夹包含到项目文件中(我正在处理此部分,以使其自动创建,完成后将通知您)。

通过这种方式,您可以自定义任意数量的组合,并且还可以在Config 文件、XML 文件等中使用。

代码

即将推出……我将在几天内更新代码。

© . All rights reserved.