• 如何扩展Visual Studio 的编译时功能


    很多时候会想在vs编译的时候自定义一些事情或者动作,

    例如:

      拷贝生成的文件到特定的目录。

      部署程序到测试目录或者环境,例如注册到windows服务,更新GAC等。

      根据编译环境生成特定的配置文件(例如web.config) PS: 身在一个复杂环境, 这是我最想要的功能。

      自动执行外部exe。

      同步DLL和其他资源文件。

    1.最简单的自然是用Visual Studio自带的编译事件,这东西使用方便,又是Visual Studio自带的功能,就是功能弱了一点(好吧 其实是很弱)

    将项目生成的DLL文件拷贝到特定目录,(如果你想拷贝一整个文件夹 用xcopy; 当然,熟悉命令行的人可以弄出更多的玩法)

    如下图所示




    2.另外一种比较推荐的方式是自定义编译扩展(可以执行C#代码...功能强大多了), 看下面这个项目文件的最后几句 (项目文件就是 项目名.csproj)

      <Import Project="..\..\Build\Tasks\Build.tasks" />
    <Target Name="BeforeBuild">
    <Message Text="Start Automatic Generate Configuration File, Source File: $(ProjectDir)web.config" Importance="high">
    </Message>
    <ConfigurationEnvironmentTask TemplateFile="$(ProjectDir)web.template.config" TargetFile="$(ProjectDir)web.config" DataSource="$(EnvironmentName).config" />
    </Target>
    </Project>

    这几句话的意思是

    1. 包含一个task文件 (该文件包含了ConfigurationEnvironmentTask 的定义,这是一个自定开发的类,其主要作用是根据环境生成web.config文件)

    2.输出一行提示信息 Start Automatic..... (该信息将显示在Output Window)

    3. 调用ConfigurationEnvironmentTask 并传入一些参数(TemplateFile 等都是自己定义的参数)

    Build.tasks的文件内容其实很简单,主要就是说明了这个task定义在哪里 (Build.dll)

    <?xml version="1.0" encoding="utf-8"?>
    <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
    <UsingTask AssemblyFile="Build.dll" TaskName="Build.ConfigurationEnvironmentTask"/>
    </Project>



    接下来的重点就是如何实现这个Task了,以下是Build.dll的关键代码

    View Code
    namespace Build
    {
    #region namespace

    using System.Globalization;
    using System.IO;
    using System.Xml;
    using Microsoft.Build.Framework;
    using Microsoft.Build.Utilities;

    #endregion

    #region Standard Config File Sections

    /// <summary>
    /// this class generate config / xml file by template
    /// </summary>
    public class ConfigurationEnvironmentTask : Task
    {
    #region Public Propreties

    /// <summary>
    /// Gets or Sets template file path (full path : C:\web.config)
    /// </summary>
    [Required]
    public ITaskItem TemplateFile { get; set; }

    /// <summary>
    /// Gets or Sets traget file path, will automatic overwrite this file (full path : C:\web.config)
    /// </summary>
    [Required]
    public ITaskItem TargetFile { get; set; }

    /// <summary>
    /// Gets or Sets configuration file, will get settings from this path (full path : C:\web.config , relative path: dev.config)
    /// </summary>
    [Required]
    public ITaskItem DataSource { get; set; }

    #endregion

    /// <summary>
    /// execute replace logic
    /// </summary>
    /// <returns>ture successful, false failure</returns>
    public override bool Execute()
    {
    string templateContent = File.ReadAllText(this.TemplateFile.ToString());

    XmlDocument xmldoc = new XmlDocument();
    string fileName = null;
    string fileFolder = null;

    if (Path.IsPathRooted(this.DataSource.ToString()))
    {
    fileFolder = Path.GetDirectoryName(this.DataSource.ToString());
    }
    else
    {
    fileFolder = Path.GetDirectoryName(this.TargetFile.ToString());
    }

    fileName = Path.GetFileName(this.DataSource.ToString());
    if (fileName == null || string.IsNullOrEmpty(fileName) || fileName.ToLower(CultureInfo.CurrentCulture).Trim() == ".config")
    {
    fileName = @"local.config";
    }

    this.Log.LogMessage("DataSource:" + this.DataSource.ToString());
    this.Log.LogMessage("IsPathRooted:" + Path.IsPathRooted(this.DataSource.ToString()));
    this.Log.LogMessage("fileFolder:" + fileFolder);
    this.Log.LogMessage("fileName:" + fileName);

    if (!File.Exists(fileFolder + @"\" + fileName))
    {
    throw new FileNotFoundException("Can not find File :" + fileFolder + @"\" + fileName);
    }

    xmldoc.Load(fileFolder + @"\" + fileName);

    foreach (XmlNode node in xmldoc.SelectNodes("/Settings/*"))
    {
    templateContent = templateContent.Replace("$(" + node.Name + ")", node.InnerText).Trim(new char[] { ' ', '\r', '\n', '\t' });
    }

    File.WriteAllText(this.TargetFile.ToString(), templateContent);
    return true;
    }
    }

    #endregion Standard Config File Sections
    }

    代码写得很烂,这不是生产环境的code

    关键就是Execute这个方法,

    大意就是根据指定的config文件读取出键值对,将web.config中类似于 $(key)的内容替换掉

    PS:在正式环境中,其实我们是用放在一个网站上的一个文件和环境变量实现的

    当然在这个方法中你想干嘛干嘛,修改配置文件也好,发邮件也好,自动备份也好...



    对了 记得让你的项目引用Build.dll (推荐dll和task文件放在同一个目录)

    然后点击编译或者Ctrl+Shift+B吧



    本文中的所有代码在Visual Studio 2010和 MSBuild Extenstion 4.0 编译和运行成功

    此外MS Build Exenstion中的一些功能很不错,而且网上也有很多第三方的Task都挺不错的, 例如部署IIS网站,FTP等,有兴趣可以试试,也许能简化不少工作

  • 相关阅读:
    pip 安装指定版本
    译文:A Robust and Modular Multi-Sensor Fusion ApproachApplied to MAV Navigation
    泡泡一分钟:Perception-aware Receding Horizon Navigation for MAVs
    泡泡一分钟: A Linear Least Square Initialization Method for 3D Pose Graph Optimization Problem
    泡泡一分钟:LandmarkBoost: Efficient Visual Context Classifiers for Robust Localization
    泡泡一分钟:Visual Odometry Using a Homography Formulation with Decoupled Rotation and Translation Estimation Using Minimal Solutions
    小程序在同一行
    oracle分页查询原理浅析
    css实现圆形头像
    纯css控制文字2行显示多余部分隐藏
  • 原文地址:https://www.cnblogs.com/PurpleTide/p/2200419.html
Copyright © 2020-2023  润新知