2011-05-10 15 views
5

He creado una plantilla de proyecto que contiene un csproj que contiene una importación que apunta a un archivo de proyecto donde enumero todas las ubicaciones de proyectos de terceros. Siempre uso esta plantilla de proyecto para crear proyectos en el mismo directorio relativo.¿Cómo uso una importación relativa en una plantilla csproj?

<?xml version="1.0" encoding="utf-8"?> 
<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> 
    <Import Project="../../../3rdParty/ThirdParty.targets" /> 
    ... 
    <ItemGroup> 
    <Reference Include="Library, Version=$(LibraryVersion), Culture=neutral, PublicKeyToken=$(LibraryPublicKeyToken), processorArchitecture=MSIL"> 
     <SpecificVersion>False</SpecificVersion> 
     <HintPath>$(LibraryDir)LibraryDll.dll</HintPath> 
    </Reference> 
    </ItemGroup> 
    ... 
</Project> 

El archivo csproj funciona correctamente en Visual Studio y al ejecutar msbuild desde el símbolo del sistema. Cuando intento crear un proyecto utilizando la plantilla de proyecto me sale el siguiente error:

C:\Users...\AppData\Local\Temp\534cylld.o0p\Temp\MyModule.csproj(3,3): The imported project "C:\Users...\AppData\Local\3rdParty\ThirdParty.targets" was not found. Confirm that the path in the declaration is correct, and that the file exists on disk.

Parece que Visual Studio está tratando de abrir el proyecto en una ubicación temporal en primer lugar. He intentado agregar $ (MSBuildProjectDirectory) a la ubicación de importación esperando que pueda obligarlo a usar la ubicación que pretendía, pero tampoco funcionó.

¿Alguna sugerencia?

+0

Estoy teniendo exactamente el mismo problema, excepto que mi archivo importado se usa para ejecutar una tarea de compilación personalizada. Necesito que esta ruta sea relativa porque es relativa a la jerarquía de mi carpeta de control de origen. – madd0

+0

@Christo: ¿Podría proporcionar el pah completo a un directorio desde el que está ejecutando compilación desde la línea de comandos? – sll

Respuesta

7

Debe establecer la propiedad CreateInPlace en true en el vstemplate. El documentation dice

Specifies whether to create the project and perform parameter replacement in the specified location, or perform parameter replacement in a temporary location and then save the project to the specified location.

Si desea rutas relativas al trabajo, se necesita el reemplazo de parámetros que se produzca en el lugar donde se va a crear el proyecto, no en una ubicación temporal.

1

He optado por una solución usando Wizards with Project Templates principalmente porque algunas de mis plantillas ya requieren asistentes.

he creado una clase base que se supone que todos mis otros asistentes para extender o que puede ser utilizado por sí mismo por sólo funcionalidad básica:

public class AddTargetsWizard : IWizard 
{ 
    private const string RELATIVE_PATH_TO_TARGETS = @"..\..\..\..\PATH\TO\Custom.Tasks.Targets"; 

    private const string TASK_NOT_FOUND_MESSAGE = @"A project of this type should be created under a specific path in order for the custom build task to be properly executed. 

The build task could not be found at the following location: 
    {0} 

Including the build task would result in unexpected behavior in Visual Studio. 

The project was created, but the build task WILL NOT BE INCLUDED. 
This project's builds WILL NOT benefit from the custom build task."; 

    private string _newProjectFileName; 

    private bool _addTaskToProject; 

    private Window _mainWindow; 

    public AddTargetsWizard() 
    { 
     this._addTaskToProject = true; 
    } 

    protected Window MainWindow 
    { 
     get 
     { 
      return this._mainWindow; 
     } 
    } 

    public virtual void BeforeOpeningFile(EnvDTE.ProjectItem projectItem) 
    { 
    } 

    public virtual void ProjectFinishedGenerating(EnvDTE.Project project) 
    { 
     this._newProjectFileName = project.FullName; 

     var projectDirectory = Path.GetDirectoryName(this._newProjectFileName); 

     var taskPath = Path.GetFullPath(Path.Combine(projectDirectory, RELATIVE_PATH_TO_TARGETS)); 

     if (!File.Exists(taskPath)) 
     { 
      MessageBox.Show(
       this.MainWindow, 
       string.Format(TASK_NOT_FOUND_MESSAGE, taskPath), 
       "Project Creation Error", 
       MessageBoxButton.OK, 
       MessageBoxImage.Error, 
       MessageBoxResult.OK, 
       MessageBoxOptions.None); 

       this._addTaskToProject = false; 
     } 
    } 

    public virtual void ProjectItemFinishedGenerating(EnvDTE.ProjectItem projectItem) 
    { 
    } 

    public virtual void RunFinished() 
    { 
     if (this._addTaskToProject) 
     { 
      var project = new Microsoft.Build.Evaluation.Project(this._newProjectFileName); 

      project.Xml.AddImport(RELATIVE_PATH_TO_TARGETS); 

      project.Save(); 
     } 
    } 

    public void RunStarted(object automationObject, Dictionary<string, string> replacementsDictionary, WizardRunKind runKind, object[] customParams) 
    { 
     var dte = (EnvDTE80.DTE2)automationObject; 

     var mainWindow = dte.MainWindow; 

     foreach (var proc in System.Diagnostics.Process.GetProcesses()) 
     { 
      if (proc.MainWindowTitle.Equals(mainWindow.Caption)) 
      { 
       var source = HwndSource.FromHwnd(proc.MainWindowHandle); 
       this._mainWindow = source.RootVisual as System.Windows.Window; 
       break; 
      } 
     } 

     this.OnRunStarted(automationObject, replacementsDictionary, runKind, customParams); 
    } 

    protected virtual void OnRunStarted(object automationObject, Dictionary<string, string> replacementsDictionary, WizardRunKind runKind, object[] customParams) 
    { 
    } 

    public virtual bool ShouldAddProjectItem(string filePath) 
    { 
     return true; 
    } 
} 

This walkthrough proporciona una muy buena explicación sobre cómo asociar el asistente para una plantilla de proyecto (o artículo).

Se dará cuenta de que estoy proporcionando un método virtual OnRunStarted para los magos niño que sería necesario para proporcionar funcionalidad adicional, como mostrar ventanas del asistente, poblando los reemplazos diccionario, etc.

Las cosas que no lo hacen me gusta sobre este enfoque y/o mi implementación:

  • Es mucho más complicado que una plantilla de proyecto simple.
  • Para que mis ventanas de asistente -todas WPF- sean ventanas modales reales con Visual Studio como propietario, no encontré mejor manera que utilizar el título de la instancia actual para determinar el HWND y el Window asociado.
  • Todo está bien cuando los proyectos se crean en la jerarquía de carpetas esperada, pero Visual Studio se comporta de forma extraña (es decir, si no se abren los cuadros de diálogo emergentes). Es por eso que elegí mostrar un mensaje de error y evitar insertar Import si la ubicación del proyecto actual no funciona con mi ruta relativa.

Si alguien tiene otras ideas, todavía soy todo oídos.

0

El comportamiento predeterminado es desempaquetar la plantilla en una carpeta temporal. Luego, los reemplazos de parámetros se realizan allí. De alguna manera, las rutas relativas se prueban y, en la ubicación temporal, los archivos no existen.

¿Intentó agregar la siguiente línea antes de importar?

<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> 
+0

La importación de Microsoft.CSharp.targets no hará nada para resolver el problema. – madd0

0

Creo que podría utilizar un environment variable lugar ... ¿Eso funcionaría en su situación?Y si tuviera que compartir las plantillas de proyecto entre desarrolladores, podría hacer algo sofisticado en un script de Powershell donde establecería la variable de entorno automáticamente o preguntando al desarrollador dónde está su directorio de plantillas.

[Environment]::SetEnvironmentVariable("3rdPartyTargets", "%ProgramFiles%/3rdParty/ThirdParty.targets", "User") 

Y luego en macro csproj:

<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> 
    <Import Project="$(3rdPartyTargets)" /> 
    ... 

Oh, espera. Eso funciona para C++, pero puede tener to use msbuild para un proyecto C#/vb.net.

Cuestiones relacionadas