背景

  这段时间公司新做了一个支付系统,里面有N个后台服务,每次有更新修改,拷贝打包发布包“不亦乐乎”。。。于是我想要不要自己定制个打包插件。

  部分朋友可能会认为,有现成的可以去找一个,干嘛不用持续集成工具啊。

  1、公司没用,也不打算用

  2、自己想折腾下,好奇

  因此主要是分享这次的学习过程和结果。

涉及知识点

  大概构想下,选择需要打包的项目-重新编译-拷贝生成文件到指定目录-OK,剩下就是交给测试去做了。

  1、Visual Studio Package 初步使用

  2、.Net 执行Dos命令

  3、MSBuild简单运用

  4、File.Copy的使用

下载安装

  Visual Studio 2013 SDK包的下载地址:http://www.microsoft.com/en-us/download/details.aspx?id=40758&fa43d42b-25b5-4a42-fe9b-1634f450f5ee=True

  完毕后,在新建项目-C#-扩展性,可以见到Visual Studio Package模板选项(见下图)

  

第一个vs插件程序

  下一步,勾选Menu Command;下一步,修改Command Name;下一步,取消单元测试,Finish。恭喜,您的第一个插件程序就这么诞生了。

  编译后,到生成目录下,执行.vsix文件,安装完后,重启VS,点击[工具]就会见到您的插件工具。同时你也可以在扩展与更新界面进行对您的插件进行卸载。

项目文件简介

  初建项目,有很多文件,有几个下面是需要了解一下的。

  1、PackingTools.vsct

  2、PackingToolsPackage.cs

  3、source.extension.vsixmanifest

  PackingTools.vsct

     vsct是个Xml文件,它用来对插件按钮进行配置的。

     Group是组节点,项目初建,它的Parent为IDM_VS_MENU_TOOLS,对于这个我们可以查看  您的vs安装目录\Visual Studio2013\VSSDK\VisualStudioIntegration\Common\Inc\vsshlids.h,打开文件,我们可以看到除IDM_VS_MENU_TOOLS以外还有IDM_VS_MENU_ADDINS、IDM_VS_MENU_HELP等等,我们尝试改成IDM_VS_MENU_HELP。

      Buttons节点下,可以添加多个Button信息,我们尝试添加一个Button进去,同时GuidSymbol加多一个IDSymbol进去。修改对应新按钮的id 和 priority。

      

      我们启动F5,调试看看,插件按钮位置变了,也是我们第一次修改了按钮布局。

      

  PackingToolsPackage.cs

      插件程序的入口,我们细看代码,发现在Initialize方法里,就对批量打包这个按钮进行事件绑定,我们尝试一下,把MenuItemCallback里的逻辑删了,展示一个wpf窗体出来。

      添加新建项-添加wpf窗体后,需要在项目里新引用一个System.Xaml.dll才能编译通过。

      接着,我们在PackingToolsPackage.cs的MenuItemCallback的方法里写new MainWindow().Show(),F5运行->点击批量打包,则会弹出下图。

      

      主界面就这么出来了,当然,你可以单例一个窗体,不用new。。。 

 

   source.extension.vsixmanifest

      对Visual Studio 扩展的配置,如:文件模板,项目工程模板,依赖程序集,Visual Studio 工具包logo,VS安装的版本等等。

读取已打开的项目信息

  这个其实并没什么特别难的逻辑,只是开始找资料花了一些时间,直接上代码。

 private void MenuItemCallback(object sender, EventArgs e)
         {
             IVsSolution pSolution = GetService(typeof(SVsSolution)) as IVsSolution;

             if (pSolution != null)
             {
                 ];
                 uint aa;
                 //通过这个方法取到打开解决方案的项目信息
                 pSolution.GetProjectFilesInSolution((uint)__VSGETPROJFILESFLAGS.GPFF_SKIPUNLOADEDPROJECTS,
                     (uint)__VSGETPROJFILESFLAGS.GPFF_SKIPUNLOADEDPROJECTS, projectArray, out aa);

                 //转换信息,让girdView展示
                 var projectList =
                     projectArray.ToList()
                         .Where(a => a.Contains(".csproj")).Select(a => new ProjectList
                         {
                             Name = Path.GetFileNameWithoutExtension(a),
                             Path = a
                         }).ToList();

                 MainForm.GetInstance(projectList).Show();
             }
         }

  对于IVsSolution这个接口的命名空间下,还有各种各样的类,对Visual Studio Package开发有兴趣的同学可以去看看。传送门

MSBuild的使用

  Microsoft Build Engine 是MSBuild的全称,是一个独立的存在生成平台,不需要依赖vs,但是vs的生成、发布等等功能都是基于MSBuild去构建的,它能读取.sln、.csproj、.pubxml等xml文件里的参数进行生成解决和项目。这里就不做过多的介绍和深入,有需要可以点击这里进行查看文档

  MSBuild.exe在C:\Windows\Microsoft.NET\Framework\v4.0.30319 这个路径下,值得注意的是Framework 的位数和版本,这个影响选择MSBuild.exe的路径。

  尝试一下,打开cmd,输入-> C:\Windows\Microsoft.NET\Framework\v4.0.30319 "您的项目文件路径" /t:Rebuild /p:Configuration=Release /p:VisualStudioVersion=12.0

  

  这句话指,用msbuild重新生成Release版本,注意项目路径是有双引号的。

  然而,我们需要在.net程序里使用这段dos指令,因此我们写编写一个dos指令帮助类

 #region Dos指令帮助类
     /// <summary>
     /// Dos指令帮助类
     /// </summary>
     public class DosCommanHelper
     {
         #region 执行指令
         /// <summary>
         /// 执行指令
         /// </summary>
         /// <param name="command">指令</param>
         /// <param name="seconds">最长等待时间(秒)</param>
         /// <returns></returns>
         )
         {
             var output = "";
             if (string.IsNullOrWhiteSpace(command))
                 return output;

             var process = new Process(); //创建进程对象
             var startInfo = new ProcessStartInfo
             {
                 FileName = "cmd.exe", //设定需要执行的命令
                 Arguments = "/C " + command, //“/C”表示执行完命令后马上退出
                 UseShellExecute = false, //不使用系统外壳程序启动
                 RedirectStandardInput = false, //不重定向输入
                 RedirectStandardOutput = true, //重定向输出
                 CreateNoWindow = true //不创建窗口
             };

             process.StartInfo = startInfo;
             try
             {
                 if (process.Start())
                 {
                     )
                     {
                         process.WaitForExit();
                     }
                     else
                     {
                         process.WaitForExit(seconds * );
                     }
                     output = process.StandardOutput.ReadToEnd();
                 }
             }
             catch (Exception e)
             {
                 Console.WriteLine(e);
             }
             finally
             {
                 process.Close();
             }
             return output;
         }
         #endregion
     }
     #endregion

拷贝生成文件

  从上面我们已经读取到了解决方案对应的项目信息,包括路径,新建的项目默认生成到.csproj文件目录下的bin/Release里。

  我们利用Path.GetDirectoryName和Path.Combine方法,获取对应路径,再自己编写文件操作帮助类,对应Release里的文件复制到指定位置。

 #region 文件操作帮助类
     /// <summary>
     /// 文件操作帮助类
     /// </summary>
     public static class FilesHelper
     {
         #region 复制文件
         /// <summary>
         /// 复制文件
         /// </summary>
         /// <param name="fromPath">原路径</param>
         /// <param name="toPath">新路径</param>
         /// <returns></returns>
         public static bool CopyFiles(string fromPath, string toPath)
         {
             try
             {
                 if (!Directory.Exists(fromPath))
                     throw new Exception("no fromPath");

                 if (Directory.Exists(toPath))
                     Directory.Delete(toPath, true);

                 Directory.CreateDirectory(toPath);

                 var fromfiles = Directory.GetFiles(fromPath).ToList();
                 fromfiles.ForEach(file =>
                 {
                     var newFile = Path.Combine(new[] { toPath, Path.GetFileName(file) });
                     File.Copy(file, newFile, true);
                 });

                 var fromFolders = Directory.GetDirectories(fromPath).ToList();
                 fromFolders.ForEach(folder =>
                 {
                     var destDir = Path.Combine(new[] { toPath, Path.GetFileName(folder) });
                     CopyFiles(folder, destDir);
                 });

                 return true;
             }
             catch
             {
                 return false;
             }
         }
         #endregion
     }
     #endregion

  最后我们只需要完善发布按钮事件,获取列表选择项->获取打包到的指定路径->遍历列表项数据->执行MSBuild指令->复制文件到指定路径->完毕

  private void Button_Click_1(object sender, RoutedEventArgs e)
         {
             var list = MyListView.SelectedItems.Cast<ProjectList>().ToList();

             var fromPath = PathLabel.Content;

             list.ForEach(item =>
             {
                 DosCommanHelper.ExeCommand(string.Format(@"C:\Windows\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe {0} /t:Rebuild /p:Configuration=Release /p:VisualStudioVersion=12.0", item.Path));

                 var theFileOfDirectoryName = Path.GetDirectoryName(item.Path);
                 var toPath = Path.Combine(theFileOfDirectoryName, @"bin\Release");
                 FilesHelper.CopyFiles(fromPath.ToString(), Path.Combine(toPath, item.Name));
             });
         }

完毕

  源码我这里没有提供,还是希望读了这篇文章感兴趣的小伙伴动手折腾下,Visual Studio Package还可以做模版开发等等,我也没太多的去深入了解,感兴趣的可以去google一下关键字Visual Studio Package、vssdk、vsix、插件开发。

  以上纯属自己初步折腾的结果,为了写文章弄出来的简单demo,还有很多可优化的地方,例如各种验证判断,插件按钮的动态显示、读取项目的类型过滤、web项目的发布,文件过滤复制等等。。。。

  本篇文章有什么写错的或者更好的建议麻烦大家在评论写给我,我会一一补充修改。如果对大家有帮助,还希望推荐一下,谢谢。

Visual Studio Package 插件开发的更多相关文章

  1. Visual Studio Package 插件开发之自动生成实体工具

    前言 这一篇是VS插件基于Visual Studio SDK扩展开发的,可能有些朋友看到[生成实体]心里可能会暗想,T4模板都可以做了.动软不是已经做了么.不就是读库保存文件到指定路径么…… 我希望做 ...

  2. SSMS2008插件开发(2)--Microsoft Visual Studio 2008插件开发介绍

    原文:SSMS2008插件开发(2)--Microsoft Visual Studio 2008插件开发介绍 由于开发SSMS2008插件是通过VS2008进行的,有必要先介绍一下VS2008的插件开 ...

  3. visual studio 插件开发

    插件的定义 所谓插件,就是根据平台接口开发的第三方程序.第一次听到这个名词很是不了解,听了解释也不是很明白,那我们来举个例子,比如说一辆房车,现在里面只有基本的一些设施,但是你现在想在顶部有一个晒太阳 ...

  4. Working with Data &#187; Getting started with ASP.NET Core and Entity Framework Core using Visual Studio &#187;迁移

    Migrations¶ 4 of 4 people found this helpful The Contoso University sample web application demonstra ...

  5. 扩展Visual Studio IDE

    安装visual studio 2012 SDK 下载visual studio SDK. 安装可能遇到的问题 安装时报错:Visual Studio 2012 Install Fails: Prog ...

  6. 关于Visual Studio 未能加载各种Package包的解决方案

    问题: 打开Visual Studio 的时候,总提示未能加载相应的Package包,有时候还无法打开项目,各种提示 解决方案: 进入用户目录 C:\Users\用户名\AppData\Local\M ...

  7. Visual Studio 2015无法进行Package Restore的原因和解决方案

    这篇文章是记录在我的当前电脑上面,安装Visual Studio 2015 Community Edition出现的无法进行Package Restore的问题,很可能在你的电脑上面无法重现.我的环境 ...

  8. Microsoft Visual Studio 2008 未能正确加载包“Visual Web Developer HTML Source Editor Package” | “Visual Studio HTM Editor Package”

    在安装Microsoft Visual Studio 2008 后,如果Visual Studio 2008的语言版本与系统不一致时,比如:在Windows 7 English System 安装Vi ...

  9. Visual Studio 2008 Package Load Failure:未能正确加载包“Microsoft.VisualStudio.Xaml”

    在安装好Visual Studio 2008后,启动Visual Studio 2008 发现如下提示: 包加载失败 未能正确加载包“Microsoft.VisualStudio.Xaml”( GUI ...

随机推荐

  1. 使用jedis操作redis

    一 连通性 1. 简单代码测试连通性 Jedis jedis = new Jedis(".......", 6379); String keys = "name" ...

  2. mysql常用函数汇总

    一.数学函数ABS(x)   返回x的绝对值BIN(x)   返回x的二进制(OCT返回八进制,HEX返回十六进制)CEILING(x)   返回大于x的最小整数值EXP(x)   返回值e(自然对数 ...

  3. mysql-4 数据检索(2)

    用通配符进行过滤 like操作符  %通配符   %可以匹配任意字符 SELECT prod_id , prod_name FROM products WHERE prod_name LIKE 'je ...

  4. Javascript题库

    一.填空题 JavaScript有两种引用数据类型 :__数组___.__对象__. Javascript通过__setTimeout___延迟指定时间后,去执行某程序. Javascript里Str ...

  5. 另类angularjs应用

    回顾 上一篇文章主要讲解了创建兼容任意浏览器(主要是ie的一些奇葩问题)的angularjs web应用,但是项目开发中其实更重要的还是在功能的模块化.代码自动压缩上面,这样项目在后期维护或者功能的重 ...

  6. 第一次div1做出3道题

    第一次div1做出3道题! 再接再厉! 哈利路亚!

  7. Java多线程之新类库中的构件CyclicBarrier

    1.类说明: 一个同步辅助类,它允许一组线程互相等待,直到到达某个公共屏障点 (common barrier point).在涉及一组固定大小的线程的程序中,这些线程必须不时地互相等待,此时 Cycl ...

  8. C Primer Plus(第五版)3

    第三章 数据和 C 在本章中你将学习下列内容: 1. 关键字: int, short, long, unsigned, char, float, double, _Bool, _Complex, _I ...

  9. 让nginx支持PHP

    MAC为例 1.安装nginx brew install nginx 2.查找nginx配置文件在什么地方 find /|grep nginx.conf 3.修改配置文件nginx.conf cd / ...

  10. Sublime Text2 中Emmet(之前叫Zencoding)插件安装以及使用

    一.添加插件之前先 下载Package Control 按 Ctrl+`(就是~这个键) 复制下面的代码 确认 重新启动sublime text2 import urllib2,os;pf='Pack ...