2017-09-29 3 views
17

코드 자산 (POCO)이 C# 인터페이스를 기반으로 생성되는 내부 용 코드 생성기를 개발했습니다. 코드 생성 프로세스는 프로그래밍 방식으로 항목을 csproj 파일에 추가/제거합니다. 워크 플로는 다음과 같습니다. 개발자가 새 C# 인터페이스를 추가하거나 Visual Studio 2017에서 기존 C# 인터페이스를 제거합니다. 개발자가 프로젝트 파일을 먼저 저장 한 다음 코드 생성기를 실행하면 모든 것이 예상대로 작동합니다. 코드 생성 자산은 프로젝트에 추가되거나 제거되므로 Visual Studio는 그에 따라 변경 내용을 반영합니다. 그러나 코드 생성기를 실행하기 전에 개발자가 csproj 파일을 저장하지 못하고 C# 인터페이스를 삭제 한 경우 Visual Studio에서 csproj 파일 수정 내용을 허용하지 않기 때문에 코드 생성 자산이 프로젝트에서 제거되지 않습니다.Visual Studio 2017에서 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); 
     } 
    } 

는 새 csproj 파일을 받아 단지 비주얼 스튜디오를 가질 수 있습니다 :

여기에 코드를 생성 자산을 제거하기위한 내 코드입니까? 자산을 제거 할 때 csproj 파일에 필요한 설정이 있습니까? 수정 된 csproj 파일에서 Visual Studio를 사용하면 더 이상 필요하지 않은 코드 생성 자산을 제거하기위한 코드 생성기의 유용성이 저하됩니다 (C# 인터페이스 파일을 물리적으로 삭제하여 발생).

EDIT

여기서 C# 1 인터페이스에 기초하여 C# 1 자산을 생성하는 비주얼 스튜디오 내부 T4 생성기를 실행하는 처리를 나타내는 동영상. 소스 C# 인터페이스를 삭제하고 코드 생성기를 다시 실행하면 프로젝트 파일이 업데이트되어 프로젝트가 다시로드됩니다.

https://www.screencast.com/t/JWTE0LpkXZGX

이 문제는 프로젝트가 다시로드됩니다 것이 아니다. 문제는 코드 생성기를 업데이트하고 csproj 파일을 Visual Studio 외부에 저장하기 때문에 csproj 파일이 변경되어 Visual Studio가 혼란스럽게됩니다. Visual Studio에서 csproj 파일에 저장된 변경 내용을 '자동으로'받아 들일 수있는 방법은 무엇입니까?

도움 주셔서 감사합니다.

+0

당신은 코드 생성기를 실행하는


다음 템플릿 옆에 파일을 추가하는 방법에 대한 전체 예제입니다 독립 실행 형 exe/도구로 빌드 프로세스 또는 외부에서 msbuild 대상에서? 대부분의 생성 방식은 msbuild에 통합되므로 프로젝트 파일을 편집 할 필요없이 VS에서 디자인 타임 빌드 중에도 코드를 동적으로 추가 할 수 있습니다. –

+0

기본적으로 project.Save()에 대한 첫 번째 호출은 VS에 아무런 영향을 미치지 않습니까? – stijn

+0

T4 파일로 작성된 독립 실행 형 코드 생성기입니다. MS 빌드와 T4를 통합하는 방법을 잘 모르겠습니다. 첫 번째 project.save()는 Visual Studio에 영향을 미치지 않는 것 같습니다. 두 번째 저장은 오래된 코드 자산을 제거한 후에 발생하며 VS는 다시로드하라는 메시지를받습니다. 하지만 그것은 VS가 코드 생성기의 범위 안에로드/수정/저장되었던 csproj 파일과는 다른 메모리의 프로젝트 버전을 가지고있는 것으로 보입니다. –

답변

2

Visual Studio에로드되는 동안 직접 프로젝트 파일을 수정하는 것은 좋은 생각이 아닙니다. 강제로 프로젝트를 다시로드하는 방법을 찾더라도 여전히 다시로드해야하므로 큰 불편을 겪습니다.

T4 템플릿에서 EnvDTE에 액세스하고이를 통해 프로젝트 파일을 수정하는 것이 훨씬 좋습니다. 이 개체를 사용하면 Visual Studio 프로젝트 모델에 액세스 할 수 있습니다.

VS로 인해 더티로 표시되므로 수정 된 프로젝트 파일을 기본적으로 저장해야하지만이 동작은 VS를 통해 수행 할 수있는 다른 모든 프로젝트 파일 수정과도 일치합니다. VS가 정말로 필요한 경우 프로젝트를 저장하도록 강요 할 수 있습니다.여기

당신이 documented here로, VS에 액세스하기 위해 수행해야 할 작업은 다음과 같습니다 설정

hostspecific 속성 true에 :

<#@ assembly name="EnvDTE" #> 
<#@ import namespace="EnvDTE" #> 

dte 객체를 가져옵니다 :

<#@ template debug="false" hostspecific="true" language="C#" #> 

가져 오기 EnvDTE :

<# 
    var dte = (DTE)((IServiceProvider)Host).GetService(typeof(DTE)); 
#> 

이제 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(); 
    } 
#> 

솔루션 탐색기에 결과 것 :

result

관련 문제