Tom*_*eck 17 c# msbuild microsoft.build visual-studio-2017
我开发了一个内部使用的代码生成器,其中代码资产(POCO)是基于C#接口生成的.代码生成过程以编程方式将项目添加/删除到csproj文件.工作流程如下:开发人员在Visual Studio 2017中添加新的C#接口或删除现有的C#接口.如果开发人员首先保存项目文件然后运行代码生成器,那么一切都按预期工作.代码生成的资产可以添加到项目中(或删除),Visual Studio会相应地反映这些更改.但是,如果开发人员在运行代码生成器之前未能保存csproj文件,并且已删除了C#接口,则代码生成的资产不会从项目中删除,因为Visual Studio不接受csproj文件修改.
在代码生成器中,我实际上删除了对已删除的代码生成文件的引用,并保存了csproj文件.我通过在记事本中打开csproj来验证是否从csproj文件中删除了引用的文件.但是,只要我将Visual Studio引入焦点,Visual Studio就会识别出csproj文件已更改并询问我是否要丢弃,覆盖,另存为等,并且我的代码生成过程对csproj文件所做的更改将丢失.Visual Studio将对已删除文件的引用添加回csproj文件.我已经尝试了丢弃,覆盖,另存为等,我没有让Visual Studio接受新修改的csproj文件(删除了已删除文件的引用).
这是我删除代码生成资产的代码:
using Microsoft.Build.Evaluation;
using Microsoft.Build.Logging;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
public static void RemoveGeneratedFilesFromProject(String projectPath)
{
UnloadAnyProject();
var project = ProjectCollection.GlobalProjectCollection.LoadedProjects.FirstOrDefault(pr => pr.FullPath == projectPath);
//ATTEMPT TO SAVE PROJECT IN CASE DEVELOPER DID NOT...
project.Save();
//GET A LIST OF ITEMS CONTAINING PATH TO CODE-GENERATED ASSETS ("Generated\API")
IList<ProjectItem> generatedItemsList = project.GetItems("Compile").Where(item => item.EvaluatedInclude.Contains(@"Generated\Api")).ToList();
foreach (var item in generatedItemsList)
{
project.RemoveItem(item);
}
//SAVE PROJECT TO REFLECT ALL OF THE CODE GENERATED ITEMS REMOVED FROM PROJECT FILE
project.Save();
UnloadAnyProject();
}
private static void UnloadAnyProject()
{
ProjectCollection projcoll = ProjectCollection.GlobalProjectCollection;
foreach (Project project in projcoll.LoadedProjects)
{
ProjectCollection mypcollection = project.ProjectCollection;
mypcollection.UnloadProject(project);
}
}
Run Code Online (Sandbox Code Playgroud)
是否可以让Visual Studio只接受新的csproj文件?在删除资产时,我需要对csproj文件进行一些设置吗?让Visual Studio对修改后的csproj文件犹豫不决会妨碍代码生成器去除不再需要的代码生成资产(源于物理删除C#接口文件).
编辑
这是一个视频,显示在Visual Studio中运行T4生成器的过程,该生成器基于C#接口生成C#资产.我删除源C#接口,重新运行代码生成器,并相应地更新项目文件,导致重新加载项目.
https://www.screencast.com/t/JWTE0LpkXZGX
问题不在于项目重新加载.问题是代码生成器更新并将csproj文件保存在Visual Studio之外,这会导致Visual Studio混乱,因为csproj文件已更改.你如何让Visual Studio"默默地"接受保存到csproj文件的更改?
谢谢你的帮助.
在加载到 Visual Studio 时自行修改项目文件并不是一个好主意。即使你找到了强制它重新加载项目的方法,它仍然需要重新加载它,这是一个很大的麻烦。
最好EnvDTE从 T4 模板访问,并通过它修改项目文件。此对象使您可以访问 Visual Studio 的项目模型。
请注意,默认情况下,用户仍需要保存修改后的项目文件,因为 VS 会将其视为脏的,但此行为与您可以通过 VS 进行的所有其他项目文件修改一致。不过,如果您确实需要,您可以强制 VS 保存该项目。
以下是访问 VS 所需的操作,如此处所述:
将hostspecific属性设置为true:
<#@ template debug="false" hostspecific="true" language="C#" #>
Run Code Online (Sandbox Code Playgroud)
进口EnvDTE:
<#@ assembly name="EnvDTE" #>
<#@ import namespace="EnvDTE" #>
Run Code Online (Sandbox Code Playgroud)
获取dte对象:
<#
var dte = (DTE)((IServiceProvider)Host).GetService(typeof(DTE));
#>
Run Code Online (Sandbox Code Playgroud)
现在您可以完全访问 VS 的项目 API。请注意,使用这种方法,您将无法在 Visual Studio 之外执行模板。
以下是如何在模板旁边添加文件的完整示例:
<#@ template debug="false" hostspecific="true" language="C#" #>
<#@ assembly name="EnvDTE" #>
<#@ import namespace="EnvDTE" #>
<#@ output extension=".txt" #>
<#
// Get the DTE
var dte = (DTE)((IServiceProvider)Host).GetService(typeof(DTE));
// Find the currently running template file in the project structure
var template = dte.Solution.FindProjectItem(Host.TemplateFile);
// Write something to a dummy file next to the template
var filePath = System.IO.Path.ChangeExtension(Host.TemplateFile, "foo");
System.IO.File.WriteAllText(filePath, "Hello, world!");
// Add the file as a subitem of the template
var fileItem = dte.Solution.FindProjectItem(filePath);
if (fileItem == null)
{
template.ProjectItems.AddFromFile(filePath);
// If you really want to, you can force VS to save the project,
// though I wouldn't recommend this
template.ContainingProject.Save();
}
#>
Run Code Online (Sandbox Code Playgroud)
这是解决方案资源管理器中的结果:
| 归档时间: |
|
| 查看次数: |
1000 次 |
| 最近记录: |