visual tutorial studio solucion publicar proyecto microsoft instalador deploy crear c# .net visual-studio deployment visual-studio-2005

c# - tutorial - Determine la versión del ensamblaje durante un evento posterior a la construcción



visual studio 2017 clickonce project (8)

Digamos que quería crear un archivo de texto estático que se incluye con cada lanzamiento. Quiero que el archivo se actualice con el número de versión de la versión (como se especifica en AssemblyInfo.cs ), pero no quiero tener que hacerlo manualmente.

Esperaba poder usar un evento posterior a la compilación y alimentar el número de versión a un archivo por lotes como este:

call foo.bat $(AssemblyVersion)

Sin embargo, no puedo encontrar ninguna variable o macro adecuada para usar.

¿Hay alguna manera de lograr esto que me he perdido?


Como solución, escribí una aplicación de consola administrada que toma el destino como parámetro y devuelve el número de versión.

Todavía estoy interesado en escuchar una solución más simple, pero estoy publicando esto en caso de que alguien más lo encuentre útil.

using System; using System.IO; using System.Diagnostics; using System.Reflection; namespace Version { class GetVersion { static void Main(string[] args) { if (args.Length == 0 || args.Length > 1) { ShowUsage(); return; } string target = args[0]; string path = Path.IsPathRooted(target) ? target : Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName) + Path.DirectorySeparatorChar + target; Console.Write( Assembly.LoadFile(path).GetName().Version.ToString(2) ); } static void ShowUsage() { Console.WriteLine("Usage: version.exe <target>"); } } }


Creo que lo mejor que puedes hacer es mirar MSBuild y MsBuild Extension Pack . Deberías poder editar tu archivo de solución para que ocurra un evento de compilación posterior y escribir en tu archivo de prueba.

Si esto es demasiado complicado, simplemente podría crear un pequeño programa que inspeccione todos los ensamblajes en su directorio de salida y lo ejecute en compilación posterior, podría pasar el directorio de salida usando el nombre de la variable ... por ejemplo, en el evento de compilación posterior. ..

AssemblyInspector.exe "$ (TargetPath)"

class Program { static void Main(string[] args) { var assemblyFilename = args.FirstOrDefault(); if(assemblyFilename != null && File.Exists(assemblyFilename)) { try { var assembly = Assembly.ReflectionOnlyLoadFrom(assemblyFilename); var name = assembly.GetName(); using(var file = File.AppendText("C://AssemblyInfo.txt")) { file.WriteLine("{0} - {1}", name.FullName, name.Version); } } catch (Exception ex) { throw; } } } }

También puede pasar la ubicación del archivo de texto ...


De eso lo que entiendo ...

Necesitas un generador para eventos de compilación posteriores.

1. Paso: escribir un generador

/* * Author: Amen RA * # Timestamp: 2013.01.24_02:08:03-UTC-ANKH * Licence: General Public License */ using System; using System.IO; namespace AppCast { class Program { public static void Main(string[] args) { // We are using two parameters. // The first one is the path of a build exe, i.e.: C:/pathto/nin/release/myapp.exe string exePath = args[0]; // The second one is for a file we are going to generate with that information string castPath = args[1]; // Now we use the methods below WriteAppCastFile(castPath, VersionInfo(exePath)); } public static string VersionInfo(string filePath) { System.Diagnostics.FileVersionInfo myFileVersionInfo = System.Diagnostics.FileVersionInfo.GetVersionInfo(filePath); return myFileVersionInfo.FileVersion; } public static void WriteAppCastFile(string castPath, string exeVersion) { TextWriter tw = new StreamWriter(castPath); tw.WriteLine(@"<?xml version=""1.0"" encoding=""utf-8""?>"); tw.WriteLine(@"<item>"); tw.WriteLine(@"<title>MyApp - New version! Release " + exeVersion + " is available.</title>"); tw.WriteLine(@"<version>" + exeVersion + "</version>"); tw.WriteLine(@"<url>http://www.example.com/pathto/updates/MyApp.exe</url>"); tw.WriteLine(@"<changelog>http://www.example.com/pathto/updates/MyApp_release_notes.html</changelog>"); tw.WriteLine(@"</item>"); tw.Close(); } } }

2. Paso: Utilizándolo como un comando de compilación posterior en nuestro IDE

Después de que la aplicación se ejecuta satisfactoriamente para usted:

En su IDE de desarrollo, use la siguiente línea de comando para eventos de compilación posteriores.

C:/Projects/pathto/bin/Release/AppCast.exe "C:/Projects/pathto/bin/Release/MyApp.exe" "c:/pathto/www.example.com/root/pathto/updates/AppCast.xml"


Empecé a agregar un proyecto independiente que se compila por última vez y a agregar un evento de compilación posterior a ese proyecto que se ejecuta solo. Luego solo realizo mis pasos de creación de programas programáticamente allí.

Hace que sea mucho más fácil hacer cosas como esta. Luego puede inspeccionar los atributos de ensamblaje del ensamblaje que desee. Hasta ahora está funcionando bastante impresionante.


Esta respuesta es una modificación menor de la respuesta de Brent Arias. Su PostBuildMacro funcionó bastante bien para mí hasta una actualización de versión de Nuget.exe.

En las versiones recientes, Nuget recorta partes no significativas del número de versión del paquete para obtener una versión semántica como "1.2.3". Por ejemplo, la versión de ensamblado "1.2.3.0" está formateada por Nuget.exe "1.2.3". Y "1.2.3.1" tiene el formato "1.2.3.1" como se esperaba.

Como necesito inferir el nombre de archivo del paquete exacto generado por Nuget.exe, uso ahora esta macro adaptada (probada en VS2015):

<Target Name="PostBuildMacros"> <GetAssemblyIdentity AssemblyFiles="$(TargetPath)"> <Output TaskParameter="Assemblies" ItemName="Targets" /> </GetAssemblyIdentity> <ItemGroup> <VersionNumber Include="$([System.Text.RegularExpressions.Regex]::Replace(&quot;%(Targets.Version)&quot;, &quot;^(.+?)(/.0+)$&quot;, &quot;$1&quot;))" /> </ItemGroup> </Target> <PropertyGroup> <PostBuildEventDependsOn> $(PostBuildEventDependsOn); PostBuildMacros; </PostBuildEventDependsOn> <PostBuildEvent>echo HELLO, THE ASSEMBLY VERSION IS: @(VersionNumber)</PostBuildEvent> </PropertyGroup>

ACTUALIZACIÓN 2017-05-24: Corregí la expresión regular de esta manera: "1.2.0.0" se traducirá a "1.2.0" y no a "1.2" como se ha codificado previamente.

Y para responder a un comentario de Ehryk Abr, puede adaptar la expresión regular para mantener solo una parte del número de versión. Como ejemplo para mantener "Major.Minor", reemplace:

<VersionNumber Include="$([System.Text.RegularExpressions.Regex]::Replace(&quot;%(Targets.Version)&quot;, &quot;^(.+?)(/.0+)$&quot;, &quot;$1&quot;))" />

Por

<VersionNumber Include="$([System.Text.RegularExpressions.Regex]::Replace(&quot;%(Targets.Version)&quot;, &quot;^([^/.]+)/.([^/.]+)(.*)$&quot;, &quot;$1.$2&quot;))" />


Necesitaba exactamente esto para poner automáticamente el número en el archivo Léame en la carpeta de salida. Al final, como lo demostró Winston Smith, una pequeña herramienta externa es una muy buena solución para eso, y tiene la ventaja de que puedes formatearla como quieras.

Esta aplicación genera la versión formateada en la consola. Lo usé en mis eventos posteriores a la construcción para construir el archivo Léame llamándolo con >> para redirigir su salida al archivo Léame.

public class GetVerNum { static void Main(String[] args) { if (args.Length == 0) return; try { FileVersionInfo ver = FileVersionInfo.GetVersionInfo(args[0]); String version = "v" + ver.FileMajorPart.ToString() + "." + ver.FileMinorPart; if (ver.FileBuildPart > 0 || ver.FilePrivatePart > 0) version += "." + ver.FileBuildPart; if (ver.FilePrivatePart > 0) version += "." + ver.FilePrivatePart; Console.Write(version); } catch { } } }

Mis eventos posteriores a la construcción:

<nul set /p dummyset=My Application > "$(ProjectDir)/Readme/readme-header.txt" "$(ProjectDir)/Readme/GetVersionNumber.exe" "$(TargetPath)" >>"$(ProjectDir)/Readme/readme-header.txt" echo by Nyerguds>>"$(ProjectDir)/Readme/readme-header.txt" echo Build date: %date% %time% >> "$(ProjectDir)/Readme/readme-header.txt" echo.>>"$(ProjectDir)/Readme/readme-header.txt" copy /b "$(ProjectDir)/Readme/readme-header.txt" + "$(ProjectDir)/Readme/readme-body.txt" "$(TargetDir)/$(ProjectName).txt"

Puse todo el léame generando cosas relacionadas en la carpeta / Readme / de mi proyecto; la aplicación que contiene el código anterior, y el "readme-body.txt" que contiene las cosas reales del léame.

  • Primera línea: cree el archivo "readme-header.txt" en la carpeta / Readme / de mi proyecto y coloque el nombre del programa dentro de él. (El <nul set /p dummyset= es un truco que encontré aquí: Windows batch: echo without new line ). También podría almacenar esta cadena en otro archivo de texto y simplemente copiar eso en "readme-header.txt" en su lugar.
  • Segunda línea: ejecute la aplicación de recuperación del número de versión con el archivo exe recién generado como parámetro y agregue su salida al archivo de encabezado.
  • Tercera línea: agregue cualquier otra cosa (en este caso, créditos) al archivo de encabezado. Esto también agrega un salto de línea hasta el final.

Estos tres juntos le dan un archivo "readme-header.txt" con "Mi aplicación v1.2.3 por Nyerguds", seguido de un salto de línea. Luego agrego la fecha de compilación y otra línea abierta, y copio el archivo de encabezado y el archivo de cuerpo léame juntos en un archivo en la carpeta de compilación final. Tenga en cuenta que utilizo específicamente la copia binaria, de lo contrario, da resultados extraños. Debe asegurarse de que el archivo del cuerpo no contenga una marca de orden de bytes UTF-8 al comienzo, o que obtenga bytes extraños en su archivo final.


Si (1) no desea descargar o crear un ejecutable personalizado que recupera la versión del ensamblado y (2) no le importa editar el archivo de proyecto de Visual Studio, entonces hay una solución simple que le permite usar una macro que se ve así:

@ (Objetivos -> ''% (Versión)'')

@(VersionNumber)

Para lograr esto, descarga tu proyecto. Si el proyecto en algún lugar define una propiedad <PostBuildEvent>, córtela del proyecto y guárdela temporalmente en otro lugar (¿Bloc de notas?). Luego, al final del proyecto, justo antes de la etiqueta final, coloque esto:

<Target Name="PostBuildMacros"> <GetAssemblyIdentity AssemblyFiles="$(TargetPath)"> <Output TaskParameter="Assemblies" ItemName="Targets" /> </GetAssemblyIdentity> <ItemGroup> <VersionNumber Include="@(Targets->''%(Version)'')"/> </ItemGroup> </Target> <PropertyGroup> <PostBuildEventDependsOn> $(PostBuildEventDependsOn); PostBuildMacros; </PostBuildEventDependsOn> <PostBuildEvent>echo HELLO, THE ASSEMBLY VERSION IS: @(VersionNumber)</PostBuildEvent> </PropertyGroup>

Este fragmento tiene un ejemplo <PostBuildEvent> ya en él. No se preocupe, puede restablecerlo a su evento real posterior a la construcción después de haber vuelto a cargar el proyecto.

Ahora, tal como prometió, la versión de ensamblaje está disponible para su evento de compilación posterior con esta macro:

@(VersionNumber)

¡Hecho!


Si prefiere crear scripts, estos métodos también pueden funcionar para usted:

Si está utilizando el evento posterior a la compilación, puede usar la herramienta filever.exe para extraerlo del ensamblado ya construido:

for /F "tokens=4" %%F in (''filever.exe /B /A /D bin/debug/myapp.exe'') do ( set VERSION=%%F ) echo The version is %VERSION%

Obtenga filever.exe desde aquí: http://support.microsoft.com/kb/913111

Si está utilizando el evento de precompilación, puede sacarlo del archivo AssemblyInfo.cs de la siguiente manera:

set ASMINFO=Properties/AssemblyInfo.cs FINDSTR /C:"[assembly: AssemblyVersion(" %ASMINFO% | sed.exe "s//[assembly: AssemblyVersion(/"/SET CURRENT_VERSION=/g;s//")/]//g;s//./*//g" >SetCurrVer.cmd CALL SetCurrVer.cmd DEL SetCurrVer.cmd echo Current version is %CURRENT_VERSION%

Utiliza la herramienta de línea de comandos de unix sed, que puedes descargar de muchos lugares, como aquí: http://unxutils.sourceforge.net/ - iirc, que funciona bien.