c# - requiere - migrar proyecto visual studio 2010 a 2015
Cómo hacer que Visual Studio 2017 acepte modificaciones al archivo csproj (1)
He desarrollado un generador de código para uso interno donde los activos de código (POCO) se generan a partir de interfaces C #. El proceso de generación de código agrega / quita programáticamente al archivo csproj. El flujo de trabajo es el siguiente: un desarrollador agrega una nueva interfaz C #, o elimina una interfaz C # existente en Visual Studio 2017. Si el desarrollador guarda primero el archivo del proyecto y luego ejecuta el generador de código, entonces todo funciona como se espera. Los activos generados por código se agregan al proyecto (o se eliminan) y Visual Studio refleja los cambios en consecuencia. Sin embargo, si el desarrollador no guarda el archivo csproj antes de ejecutar el generador de código y elimina una interfaz de C #, los activos generados por el código no se eliminarán del proyecto porque Visual Studio no acepta las modificaciones del archivo csproj.
Dentro del generador de código, estoy eliminando físicamente las referencias a los archivos generados por el código que se eliminan y estoy guardando el archivo csproj. Verifico que los archivos de referencia se eliminan del archivo csproj abriendo el csproj en el bloc de notas. Sin embargo, tan pronto como enfoco Visual Studio, Visual Studio reconoce que el archivo csproj ha cambiado y me pregunta si deseo descartar, sobrescribir, guardar como, etc. y los cambios realizados en el archivo csproj de mi proceso de generación de código se pierden. Visual Studio agrega las referencias a los archivos eliminados de nuevo en el archivo csproj. He intentado descartar, sobrescribir, guardar como, etc. y no consigo que Visual Studio acepte el archivo csproj recién modificado (que tiene las referencias a los archivos eliminados eliminados).
Aquí está mi código para eliminar los activos generados por el código:
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);
}
}
¿Es posible que Visual Studio simplemente acepte el nuevo archivo csproj? ¿Debo realizar algún ajuste en el archivo csproj al eliminar activos? Tener a Visual Studio en el archivo csproj modificado está dificultando la utilidad del generador de código para eliminar los activos generados por el código que ya no son necesarios (debido a la eliminación física de un archivo de interfaz C #).
EDITAR
Aquí hay un video que muestra el proceso de ejecución del generador T4 dentro de Visual Studio generando activos de C # basados en una interfaz de C #. Borro la interfaz de C # de origen, vuelvo a ejecutar el generador de código y el archivo del proyecto se actualiza en consecuencia, lo que hace que el proyecto se vuelva a cargar.
https://www.screencast.com/t/JWTE0LpkXZGX
El problema no es que el proyecto se vuelva a cargar. El problema es que el generador de código actualiza y guarda el archivo csproj fuera de Visual Studio, lo que hace que Visual Studio se confunda porque el archivo csproj ha cambiado. ¿Cómo se hace que Visual Studio acepte ''silenciosamente'' los cambios guardados en el archivo csproj?
Gracias por tu ayuda.
Modificar el archivo de proyecto por ti mismo mientras está cargado en Visual Studio no es una gran idea. Incluso si encuentra una manera de forzarlo para que vuelva a cargar el proyecto, todavía tendrá que volver a cargarlo, lo cual es una molestia importante.
Es mucho mejor acceder a EnvDTE
desde una plantilla T4 y modificar el archivo de proyecto a través de eso. Este objeto le da acceso al modelo de proyecto de Visual Studio.
Tenga en cuenta que el usuario todavía deberá guardar el archivo de proyecto modificado de forma predeterminada, ya que VS lo verá como sucio, pero este comportamiento es coherente con todas las demás modificaciones de archivos de proyecto que puede hacer a través de VS. Sin embargo, puede forzar a VS a guardar el proyecto si realmente lo necesita.
Esto es lo que debe hacer para acceder a VS, como se documenta aquí :
Establezca el atributo hostspecific
en true
:
<#@ template debug="false" hostspecific="true" language="C#" #>
Importar EnvDTE
:
<#@ assembly name="EnvDTE" #>
<#@ import namespace="EnvDTE" #>
Obtener el objeto dte
:
<#
var dte = (DTE)((IServiceProvider)Host).GetService(typeof(DTE));
#>
Y ahora tienes acceso completo a las API del proyecto de VS. Tenga en cuenta que con este enfoque, pierde la capacidad de ejecutar la plantilla fuera de Visual Studio.
Aquí hay un ejemplo completo de cómo agregar un archivo junto a su plantilla:
<#@ 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();
}
#>
Aquí está el resultado en el explorador de soluciones: