8

Estoy usando la solución al this question para aplicar cambios de configuración al App.config en un proyecto de Winforms. También tengo un proyecto de instalador para el proyecto que crea un archivo instalable * .msi. El problema es que el archivo de configuración incluido en los instaladores es el archivo de configuración original sin transformar. Por lo tanto, no estamos obteniendo las cadenas de conexión de producción en el instalador de producción a pesar de que el archivo de configuración para el proyecto winforms construido tiene todas las transformaciones correctas aplicadas.¿Puedo forzar al proyecto del instalador a usar el archivo .config de la solución integrada en lugar del original?

¿Hay alguna manera de forzar al proyecto del instalador a usar el resultado de la compilación del proyecto?

+0

¡Hola! ¿Has resuelto tu problema? Si necesita ayuda, solo infórmeme e intentaré ayudarlo. ;) –

+0

Gracias. Tu reseña se ve bastante bien. No he tenido la oportunidad de probarlo todavía, aunque espero hacerlo en los próximos días. Te avisaré si encuentro algún problema. Gracias por incluir esos detalles. – recursive

Respuesta

8

Como está gastando una gran cantidad de reputación, traté de dar lo mejor de mí, y dediqué un poco de mi tiempo, no solo a poner mis manos en la abundancia ... sino que también obtuve algo más: ¡conocimiento! =)

En primer lugar: es imposible hacer que el Proyecto de instalación apunte a otro archivo app.config utilizando la opción Primary output. Entonces mi solución va a ser un que funcione alrededor de. Espero que lo encuentres útil en tu situación.

general:

La idea básica es:

  • Retire la app.config forzada de la configuración del proyecto;
  • Agregue un archivo que apunta al app.config, manualmente;
  • Use MSBuild para entrar en el archivo vdproj, y cámbielo para que coincida con la salida real de la aplicación.config transformada.

Algunos inconvenientes son:

  • El proyecto de instalación sólo se actualiza, si el proyecto de construcción se despliega. ahhh ... ¡no es un verdadero inconveniente!
  • Necesita MSBuild 4.0 ... ¡esto también se puede solucionar!
  • Necesita una tarea personalizada, llamada FileUpdate ... es de código abierto y tiene instalador.

Permite trabajar:

1) Ir a su proyecto de instalación y seleccione el objeto de salida principal, haga clic derecho y seleccione Propiedades. Allí encontrará Exclude Filter ... agregue un filtro para *.config, por lo que eliminará la aplicación de código fijo.

2) Haga clic derecho en su proyecto de instalación en el Explorador de soluciones -> Agregar -> Archivo ... seleccione cualquier archivo que termine con .config.

3) Descargar MSBuild Community Tasks Project, yo recomiendo el instalador msi.

4) Descarga de su proyecto (la csproj) y reemplazar el código de la otra pregunta con éste:

Código:

<UsingTask TaskName="TransformXml" AssemblyFile="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v10.0\Web\Microsoft.Web.Publishing.Tasks.dll" /> 
    <Import Project="$(MSBuildExtensionsPath)\MSBuildCommunityTasks\MSBuild.Community.Tasks.Targets" /> 
    <Target Name="AfterCompile" Condition="exists('app.$(Configuration).config')"> 
    <!-- Generate transformed app config in the intermediate directory --> 
    <TransformXml Source="app.config" Destination="$(IntermediateOutputPath)$(TargetFileName).config" Transform="app.$(Configuration).config" /> 
    <!-- Force build process to use the transformed configuration file from now on. --> 
    <ItemGroup> 
     <AppConfigWithTargetPath Remove="app.config" /> 
     <AppConfigWithTargetPath Include="$(IntermediateOutputPath)$(TargetFileName).config"> 
     <TargetPath>$(TargetFileName).config</TargetPath> 
     </AppConfigWithTargetPath> 
    </ItemGroup> 
    <PropertyGroup> 
     <SetupProjectPath>$(MSBuildProjectDirectory)\$(IntermediateOutputPath)$(TargetFileName).config</SetupProjectPath> 
    </PropertyGroup> 
    <!-- Change the following so that this Task can find your vdproj file --> 
    <FileUpdate Files="$(MSBuildProjectDirectory)\..\Setup1\Setup1.vdproj" 
        Regex="(.SourcePath. = .8:).*\.config(.)" 
        ReplacementText="$1$(SetupProjectPath.Replace(`\`,`\\`))$2" /> 
    <FileUpdate Files="$(MSBuildProjectDirectory)\..\Setup1\Setup1.vdproj" 
        Regex="(.TargetName. = .8:).*\.config(.)" 
        ReplacementText="$1$(TargetFileName).config$2" /> 
    </Target> 

5) se debe cambiar el código anterior, por lo que puede encontrar su archivo vdproj. He colocado un comentario en el código, que indica dónde debe realizar el cambio.

6) Se feliz!

Ahora, cada vez que genere el proyecto principal, el MSBuild va a cambiar el proyecto de instalación, de modo que utilice el archivo app.config correcta. Puede tener inconvenientes, pero esta solución se puede pulir y mejorar. Si necesita dejar un comentario, intentaré responder lo antes posible.

Recursos he usado

MSBuild 4.0 se necesita porque necesito utilizar la función Reemplazar de cadena, para reemplazar sencillo "\" duplicar "\" en la ruta. Consulte MSBuild Property Functions para obtener información sobre el uso de la función en MSBuild.

he aprendido acerca de la FileUpdate Task en esta otra pregunta. El proyecto oficial es MSBuild Community Tasks Project.

Estos dos temas son importantes para mis hallazgos:

Trying to include configuration specific app.config files in a setup project

Problems with setup project - am I thick?

5

Otra solución que he encontrado es no utilizar las transformaciones, pero sólo hay un archivo de configuración distinto, por ejemplo, app.Release.config. A continuación, agregue esta línea a su archivo csproj.

<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' "> 
    <AppConfig>App.Release.config</AppConfig> 
    </PropertyGroup> 

Esto forzará el proyecto de implementación de utilizar el archivo de configuración correcta al empaquetar.

+1

¡Agradable! Muy simple en comparación con lo anterior. –

1

Basado de la respuesta de Alec, aquí es un elemento similar que se puede utilizar junto con las transformaciones y aún así obtener su máximo beneficio:

<ItemGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> 
    <Content Include="$(OutputPath)$(AssemblyName).dll.config"> 
     <InProject>false</InProject> 
     <Link>$(AssemblyName).dll.config</Link> 
    </Content> 
    </ItemGroup> 

De esta manera, se puede utilizar el SlowCheetah transforma o el built-in unos para transformar su archivo .config, y luego ir a su Proyecto de implementación de Visual Studio (u otro) e incluir el contenido del proyecto afectado en su página Agregar -> Proyecto de salida ... fácilmente, con cambios mínimos.

+0

Ni siquiera necesita 'Condición ='. –

1

Ninguna de las soluciones anteriores o cualquier artículo que funcionó para mí en el proyecto de implementación/configuración. Pasé muchos días para encontrar la solución correcta. Finalmente, este enfoque funcionó para mí.

Pre REQUISITOS utilidad

He usado llama cct.exe para transformar archivos de forma explícita. Puede descargar desde aquí http://ctt.codeplex.com/

He usado instalador personalizado en el proyecto de instalación para capturar eventos de instalación.

Siga estos pasos para lograr la transformación aplicación de configuración

1) Añadir los archivos de configuración deseados a su proyecto y modificar el archivo .csproj como estos

<Content Include="app.uat.config"> 
    <DependentUpon>app.config</DependentUpon> 
</Content> 
<Content Include="app.training.config"> 
    <DependentUpon>app.config</DependentUpon> 
</Content> 
<Content Include="app.live.config"> 
    <DependentUpon>app.config</DependentUpon> 
</Content> 

Los he añadido como contenido para que se pueden copiar en el directorio de salida.

2) Agregue cct.exe a su proyecto que descargó.

3) Añadir instalador encargo a su proyecto que debería tener este aspecto

[RunInstaller(true)] 
    public partial class CustomInstaller : System.Configuration.Install.Installer 
    { 
    string currentLocation = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); 
    string[] transformationfiles = Directory.GetFiles(Path.GetDirectoryNam(Assembly.GetExecutingAssembly().Location), "app.*.config"); 

    public CustomInstaller() 
    { 
     InitializeComponent(); 
     // Attach the 'Committed' event. 
     this.Committed += new InstallEventHandler(MyInstaller_Committed); 
     this.AfterInstall += new InstallEventHandler(CustomInstaller_AfterInstall); 

    } 


    void CustomInstaller_AfterInstall(object sender, InstallEventArgs e) 
    { 
     try 
     { 

      Directory.SetCurrentDirectory(currentLocation); 
      var environment = Context.Parameters["Environment"]; 
      var currentconfig = transformationfiles.Where(x => x.Contains(environment)).First(); 

      if (currentconfig != null) 
      { 
       FileInfo finfo = new FileInfo(currentconfig); 
       if (finfo != null) 
       { 
        var commands = string.Format(@"/C ctt.exe s:yourexename.exe.config t:{0} d:yourexename.exe.config ", finfo.Name); 

        using (System.Diagnostics.Process execute = new System.Diagnostics.Process()) 
        { 
         execute.StartInfo.FileName = "cmd.exe"; 
         execute.StartInfo.RedirectStandardError = true; 
         execute.StartInfo.RedirectStandardInput = true; 
         execute.StartInfo.RedirectStandardOutput = true; 
         execute.StartInfo.UseShellExecute = false; 
         execute.StartInfo.CreateNoWindow = true; 
         execute.StartInfo.Arguments = commands; 
         execute.Start(); 
        } 

       } 
      } 
     } 
     catch 
     { 
      // Do nothing... 
     } 


    } 

    // Event handler for 'Committed' event. 
    private void MyInstaller_Committed(object sender, InstallEventArgs e) 
    { 
     XmlDocument doc = new XmlDocument(); 
     var execonfigPath = currentLocation + @"\yourexe.exe.config"; 
     var file = File.OpenText(execonfigPath); 
     var xml = file.ReadToEnd(); 
     file.Close(); 
     doc.LoadXml(FormatXmlString(xml)); 
     doc.Save(execonfigPath); 

     foreach (var filename in transformationfiles) 
      File.Delete(filename); 

    } 



    private static string FormatXmlString(string xmlString) 
    { 
     System.Xml.Linq.XElement element = System.Xml.Linq.XElement.Parse(xmlString); 
     return element.ToString(); 
    } 

} 

Aquí estoy usando dos controladores de eventos CustomInstaller_AfterInstall en el que yo estoy cargando el archivo de configuración correcta y transformadora. En MyInstaller_Committed Estoy borrando los archivos de transformación que no necesitamos en la máquina cliente una vez que aplicamos se ha aplicado. También estoy sangrando el archivo transformado porque cct simplemente transforma elementos que estaban alineados feos.

4) Abra su proyecto de configuración y agregue el archivo de contenido de salida del proyecto para que la configuración pueda copiar los archivos de configuración como app.uat.config, app.live.config etc. en la máquina del cliente.

En el paso anterior, este fragmento cargará todos los archivos de configuración disponibles, pero necesitamos de alimentación correcta archivo de transformación

string[] transformationfiles = Directory.GetFiles(Path.GetDirectoryNam 

(Assembly.GetExecutingAssembly().Location), "app.*.config"); 

Para que he añadido de diálogo de configuración de la interfaz de usuario en el proyecto para obtener la configuración actual. El cuadro de diálogo ofrece opciones para que el usuario seleccione un entorno como "Live" "UAT", "Test", etc. Ahora pase el entorno seleccionado a su instalador personalizado y fíltrelos.

Configure UI to allow user to select option

enter image description here

enter image description here

llegará a ser extenso artículo si me explico sobre cómo añadir diálogo, cómo configurar parametros etc así que por favor google ellos. Pero la idea es transformar el entorno seleccionado por el usuario. La ventaja de este enfoque es que puede usar el mismo archivo de instalación para cualquier entorno.

Aquí está el resumen:

Añadir archivos de configuración

Añadir CCT exe

Añadir instalador personalizado

Aplicar transformación en exe.config bajo después de instalar evento

archivos de transformación Eliminar en la máquina del cliente

proyecto de instalación modificar de una manera tal que

set up should copy all config files(project output content) and cct.exe into output directory 

configure UI dialog with radio buttons (Test,Live,UAT..) 

pass the selected value to custom installer 

solución podría ser largo, pero no tienen otra opción, porque MSI siempre una copia app.config y no se preocupa por los eventos y transformaciones de construcción del proyecto. slowcheetah sólo funciona con ClickOnce no proyecto de instalación

4

he logrado esto de una manera diferente sin necesidad de herramientas externas:

he añadido un evento posterior a la generación que copiar los archivos de destino en un directorio 'neutral' (la raíz de la carpeta/bin en el proyecto) y luego agregó este archivo al .vdproj. El proyecto de implementación recoge ahora sea cual sea la versión más reciente incorporado es:

mensaje Comando Build:

copy /y "$(TargetDir)$(TargetFileName).config" "$(ProjectDir)bin\$(TargetFileName).config" 

Esto funcionó para lo que necesitaba sin necesidad de herramientas externas, y funciona muy bien con las transformaciones SlowCheetah.

2

que combinan lo mejor de las siguientes respuestas para obtener una solución totalmente funcional sin necesidad de utilizar ningún herramientas externas en absoluto:

1. Configuración app.config transformaciones

Fuente: https://stackoverflow.com/a/5109530

En resumen:

añadir manualmente los archivos .config adicionales para cada configuración de generación y editar el archivo de proyecto prima para incluirlos similar a esto:

<Content Include="App.config" /> 
<Content Include="App.Debug.config" > 
    <DependentUpon>App.config</DependentUpon> 
</Content> 
<Content Include="App.Release.config" > 
    <DependentUpon>App.config</DependentUpon> 
</Content> 

A continuación, se incluyen los siguientes XML al final del archivo de proyecto, justo antes del cierre </project> etiqueta:

<UsingTask TaskName="TransformXml" AssemblyFile="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v$(VisualStudioVersion)\Web\Microsoft.Web.Publishing.Tasks.dll" /> 
<Target Name="AfterCompile" Condition="exists('app.$(Configuration).config')"> 
    <TransformXml Source="app.config" Destination="$(IntermediateOutputPath)$(TargetFileName).config" Transform="app.$(Configuration).config" /> 
    <ItemGroup> 
    <AppConfigWithTargetPath Remove="app.config" /> 
    <AppConfigWithTargetPath Include="$(IntermediateOutputPath)$(TargetFileName).config"> 
     <TargetPath>$(TargetFileName).config</TargetPath> 
    </AppConfigWithTargetPath> 
    </ItemGroup> 
</Target> 

Finalmente editar los archivos .config adicionales para incluir la respectiva transformations para cada configuración de construcción:

<?xml version="1.0" encoding="utf-8"?> 
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform"> 
    <!-- transformations here--> 
</configuration> 

2. Incluir el .config adecuado en el proyecto de instalación

En primer lugar, añadir un comando en caso postbuild de su proyecto principal para mover el archivo .config adecuado transformado en un lugar neutral (por ejemplo, bin\ el directorio principal):

copy /y "$(TargetDir)$(TargetFileName).config" "$(ProjectDir)bin\$(TargetFileName).config" 

(Fuente: https://stackoverflow.com/a/26521986)

Abrir el proyecto de instalación y haga clic en el "Resultado principal ..." nodo para mostrar la ventana de propiedades. Allí, agregue un ExludeFilter "*.config" para excluir el archivo predeterminado (no transformado) .config.

(Fuente: https://stackoverflow.com/a/6908477)

Por último agregar el archivo .config transformado (desde el evento postbuild) para el proyecto de instalación (Añadir> Archivo).

Hecho.

Ahora puede agregar libremente las configuraciones de compilación y las correspondientes transformaciones de configuración y su proyecto de instalación siempre incluirá el .config apropiado para la configuración activa.

0

La pregunta es antigua, pero la siguiente podría ayudar a mucha gente.

Me basta con utilizar Wix WiFile.exe para reemplazar el archivo en cuestión en el msi de esta manera (por el bien de este ejemplo, que llamamos su MSI yourPackage.msi):

Paso 1. A partir de comando ejecución rápida: WiFile.exe "yourPackage.msi"/x "app.exe.config." Lo anterior extraerá el archivo app.exe.config "incorrecto" del msi y lo colocará en el mismo directorio que su msi;

Paso 2. Coloque el nuevo archivo de configuración (prod) (debe tener el mismo nombre que el archivo extraído: app.exe.config) en la misma ubicación que su msi; Esto significa que está sobrescribiendo el archivo app.exe.config que acaba de extraerse en el paso 1 anterior, con su nuevo archivo de configuración de producción;

Paso 3. Desde el símbolo del sistema ejecute: WiFile.exe "yourPackage.msi"/u "app.exe.config."

¡ESO ES TODO!

Lo anterior se puede hacer en unos segundos. Puede automatizar la tarea si lo desea, por ejemplo, ejecutándola como un lote o de lo contrario.

Después de ejecutar el paso 3 anterior, su msi contendrá el nuevo archivo de configuración, que ahora se instalará en sus clientes cuando ejecuten la configuración.

Cuestiones relacionadas