Visaul Studio Vsix 插件开入门 -net core项目自定义发布

2021-05-19  乐帮网

visual studio

我们可以通过开发VSIX插件来实现对Visaul Studio扩展一些额外功能。本篇文章旨在开发一个 项目发布 插件,来实现对Net core项目的一键发布,发布的同时我们可以自定义一些额外的参数。我需要的是右键项目,选择自定义发布,然后就把文件自动生成到我指定的上当,这里是 {solution}/build/{ProjectName}。核心思想就是在后台执行 donet push 命令来实现动态发布。

开发环境: Visaul Studio 2019 +  Windows 10
基础准备参考上一篇文章:https://lebang2020.cn/details/210519kr4izdl5.html
以学习为目的,同时我把常规的操作也写在了代码中,可能 你会感觉有许多代码并没有用。

(1)需要接上一篇文章:https://lebang2020.cn/details/210519kr4izdl5.html 在这个项目中我们改造一下来实现我们的功能。

(2)我们需要修改一下菜单的位置,之前是在 Tool 下添加了菜单,修改VktVSIXProjectPackage.vsct文件,如下:

 <Groups>
      <Group guid="guidVktVSIXProjectPackageCmdSet" id="MyMenuGroup" priority="0x0600">
        <Parent guid="guidSHLMainMenu" id="IDM_VS_CTXT_PROJNODE"/>
      </Group>
    </Groups>

(3)修改命令类文件PublishCommand.cs ,这里分几步。

首先我把执行cmd命令的方法贴出来,这个是用来执行 donet publish 命令的。

public static string ExecuteInCmd(string cmdline)
        {
            using (System.Diagnostics.Process process = new System.Diagnostics.Process())
            {
                process.StartInfo.FileName = "cmd.exe";
                process.StartInfo.UseShellExecute = false;
                process.StartInfo.RedirectStandardInput = true;
                process.StartInfo.RedirectStandardOutput = true;
                process.StartInfo.RedirectStandardError = true;
                process.StartInfo.CreateNoWindow = true;

                process.Start();
                process.StandardInput.AutoFlush = true;
                process.StandardInput.WriteLine(cmdline + "&exit");

                //获取cmd窗口的输出信息  
                string output = process.StandardOutput.ReadToEnd();

                process.WaitForExit();
                process.Close();

                return output;
            }
        }

再次,我们在项目中右键,此时就需要获取项目文件的路径,甚至获取项目中的配置,来动态生成命令再执行。
核心代码如下:

ThreadHelper.ThrowIfNotOnUIThread();

            var dte =  package.GetServiceAsync(typeof(DTE)).ConfigureAwait(false).GetAwaiter().GetResult() as DTE2;
            if (dte == null)
                throw new Exception("Unable to find EnvDTE.DTE");

            Array activeSolutionProjects = (Array)dte.ActiveSolutionProjects;
            if (activeSolutionProjects == null)
                throw new Exception("DTE.ActiveSolutionProjects returned null");

            UIHierarchy uih = (UIHierarchy)dte.Windows.Item(EnvDTE.Constants.vsWindowKindSolutionExplorer).Object;
            Array selectedItems = (Array)uih.SelectedItems;
            string projectName = string.Empty;
            EnvDTE.Project selectedProject1 = null;
            if (null != selectedItems)
            {
                foreach (UIHierarchyItem selItem in selectedItems)
                {
                    Project project = selItem.Object as Project;
                    if (project != null)
                    {
                        selectedProject1 = project;
                        //ProjectItem prjItem = project.ProjectItems as ProjectItem;
                        string filePath;
                        if (project.Properties != null)
                        {
                            filePath = project.Properties.Item("FullPath").Value.ToString();
                        }
                        else
                        {
                            filePath = project.FullName;
                        }
                    }
                    
                    projectName = project.Name;

                }
            }
            else
            {
                throw new Exception("selected item is null");
            }

            EnvDTE.Project selectedProject2 = null;

            foreach (var p in activeSolutionProjects)
            {
                if (((EnvDTE.Project)p).Name.Equals(projectName))
                {
                    selectedProject2 = (EnvDTE.Project)p;
                }
            }

            EnvDTE.Project dteProject = (EnvDTE.Project)activeSolutionProjects.GetValue(0);
            if (dteProject == null)
                throw new Exception("DTE.ActiveSolutionProjects[0] returned null");


            XmlDocument xmlDoc = new XmlDocument();

            xmlDoc.Load(selectedProject1.FullName); 
            XmlElement xmlRoot = xmlDoc.DocumentElement;

        

            var buildAction = new Action<string,string>((filePath,buildPath) =>
            {
                string cmd = $"dotnet publish {filePath}  -f netcoreapp3.1 -c Debug -o {buildPath} --no-self-contained";
                ExecuteInCmd(cmd);

            });

            if (xmlRoot.HasAttributes)
            {
                var sdkNode = xmlRoot.Attributes.GetNamedItem("Sdk");
                if (sdkNode != null)
                {
                    if(sdkNode.Value== "Microsoft.NET.Sdk.Web")
                    {
                        //正是我的菜
                        System.IO.DirectoryInfo dir = System.IO.Directory.GetParent(Path.GetDirectoryName( selectedProject1.FullName));
                        string buildPath = Path.Combine( dir.FullName,"build", selectedProject1.Name);
                        buildAction(selectedProject1.FullName, buildPath);
                    }
                }
            }

(4)最终运行效果图如下

001

选择菜单后,就会动态执行publish操作。

最后提供示例源码下载链接: https://pan.baidu.com/s/1E4I_rFMiz_7yrEAlaYpTbw 

公众号二维码

关注我的微信公众号
在公众号里留言交流
投稿邮箱:1052839972@qq.com

庭院深深深几许?杨柳堆烟,帘幕无重数。
玉勒雕鞍游冶处,楼高不见章台路。
雨横风狂三月暮。门掩黄昏,无计留春住。
泪眼问花花不语,乱红飞过秋千去。

欧阳修

付款二维码

如果感觉对您有帮助
欢迎向作者提供捐赠
这将是创作的最大动力