¿Cuáles son las diferencias entre AssemblyVersion, AssemblyFileVersion y AssemblyInformationalVersion?

860

Hay tres atributos de versión de ensamblaje. ¿Qué son las diferencias? ¿Está bien si usoAssemblyVersion e ignoro el resto?


MSDN dice:

  • AsambleaVersión :

    Especifica la versión del conjunto que se atribuye.

  • AssemblyFileVersion :

    Indica a un compilador que use un número de versión específico para el recurso de versión del archivo Win32. No se requiere que la versión del archivo Win32 sea la misma que el número de versión del ensamblado.

  • AssemblyInformationalVersion :

    Define información de versión adicional para un manifiesto de ensamblado.


Este es un seguimiento de ¿Cuáles son las mejores prácticas para usar los atributos de ensamblaje?

Jakub Šturc
fuente

Respuestas:

907

AsambleaVersión

Dónde se verán otros ensamblajes que hacen referencia a su ensamblaje. Si este número cambia, ¡otros conjuntos tienen que actualizar sus referencias a su conjunto! Solo actualice esta versión, si rompe la compatibilidad con versiones anteriores. El AssemblyVersiones requerido.

Yo uso el formato: major.minor . Esto resultaría en:

[assembly: AssemblyVersion("1.0")]

Si sigue estrictamente a SemVer , esto significa que solo actualiza cuando los cambios principales cambian, por lo que 1.0, 2.0, 3.0, etc.

AssemblyFileVersion

Utilizado para el despliegue. Puede aumentar este número para cada implementación. Es utilizado por los programas de instalación. Úselo para marcar ensamblajes que tienen el mismoAssemblyVersion , pero se generan a partir de diferentes compilaciones.

En Windows, se puede ver en las propiedades del archivo.

AssemblyFileVersion es opcional. Si no se proporciona, se utiliza la versión de ensamblaje.

Uso el formato: major.minor.patch.build , donde sigo SemVer para las primeras tres partes y uso el número de compilación del servidor de compilación para la última parte (0 para la compilación local). Esto resultaría en:

[assembly: AssemblyFileVersion("1.3.2.254")]

Tenga en cuenta que System.Version nombra estas partes como major.minor.build.revision!

AssemblyInformationalVersion

La versión del producto del ensamblaje. Esta es la versión que usaría al hablar con los clientes o para mostrarla en su sitio web. Esta versión puede ser una cadena, como ' 1.0 Release Candidate '.

El AssemblyInformationalVersiones opcional. Si no se proporciona, se utiliza AssemblyFileVersion.

Yo uso el formato: major.minor [.patch] [revisión como cadena] . Esto resultaría en:

[assembly: AssemblyInformationalVersion("1.0 RC1")]
Rémy van Duijkeren
fuente
44
Para AssemblyFileVersion, "Si es posible, que MSBuild lo genere": ¿por qué? Simplemente explicaste una buena razón para controlarlo manualmente :)
mo.
3
La advertencia sobre el formato AssemblyInformationalVersion todavía existe en VS2010 hoy (21 de mayo de 2013) y su enlace está inactivo.
reinierpost
22
Desafortunadamente, la Clase de versión define major.minor[.build[.revision]]y no major.minor.revision.buildasí en la respuesta dada, los números de compilación y revisión se intercambiarían si estuviera utilizando las propiedades de la clase o System.Reflection.Assembly.GetExecutingAssembly().GetName().Versionpara detectar los números de compilación y revisión.
thinkOfaNumber
99
@thinkOfaNumber Tiene razón sobre la Clase de versión, pero esa es la forma de versiones de Microsoft. Personalmente, creo que es extraño no tener el número de compilación al final y es por eso que solo pongo mi formato como ejemplo, basado en el control de versiones semántico . Eres libre de usar la forma de Microsoft o tu propia forma, por supuesto.
Rémy van Duijkeren
66
Cabe señalar que para AssemblyInformationalVersion, si se omite, AssemblyFileVersionse utiliza. Entonces, AssemblyVersion si ambos se omiten.
Drazen Bjelovuk
588

El control de versiones de ensamblados en .NET puede ser una perspectiva confusa dado que actualmente hay al menos tres formas de especificar una versión para su ensamblaje.

Estos son los tres atributos principales de ensamblaje relacionados con la versión:

// Assembly mscorlib, Version 2.0.0.0
[assembly: AssemblyFileVersion("2.0.50727.3521")]
[assembly: AssemblyInformationalVersion("2.0.50727.3521")]
[assembly: AssemblyVersion("2.0.0.0")]

Por convención, las cuatro partes de la versión se denominan versión principal , versión secundaria , compilación y revisión .

El AssemblyFileVersionobjetivo es identificar de forma exclusiva una compilación del ensamblaje individual

Por lo general, configurará manualmente la versión de archivo de ensamblaje mayor y menor para reflejar la versión del ensamblaje, luego incrementará la compilación y / o revisión cada vez que su sistema de compilación compile el ensamblaje. AssemblyFileVersion debería permitirle identificar de forma exclusiva una compilación del ensamblado, de modo que pueda usarlo como punto de partida para depurar cualquier problema.

En mi proyecto actual, el servidor de compilación codifica el número de la lista de cambios de nuestro repositorio de control de código fuente en las partes de compilación y revisión de AssemblyFileVersion. Esto nos permite mapear directamente desde un ensamblado a su código fuente, para cualquier ensamblaje generado por el servidor de compilación (sin tener que usar etiquetas o ramas en el control de origen, o mantener manualmente cualquier registro de versiones publicadas).

Este número de versión se almacena en el recurso de versión Win32 y se puede ver al ver las páginas de propiedades del Explorador de Windows para el ensamblado.

Al CLR no le importa ni examina la versión del archivo de ensamblaje.

El AssemblyInformationalVersionpretende representar la versión de la totalidad de su producto

AssemblyInformationalVersion está destinado a permitir versiones coherentes de todo el producto, que puede consistir en muchos ensamblajes que se versionan de forma independiente, tal vez con políticas de versiones diferentes y potencialmente desarrollados por equipos dispares.

“Por ejemplo, la versión 2.0 de un producto puede contener varios ensamblajes; uno de estos conjuntos está marcado como versión 1.0 ya que es un nuevo conjunto que no se envió en la versión 1.0 del mismo producto. Por lo general, configura las partes principales y secundarias de este número de versión para representar la versión pública de su producto. Luego, incrementa las partes de construcción y revisión cada vez que empaqueta un producto completo con todos sus ensamblajes ". - Jeffrey Richter, [CLR a través de C # (Segunda edición)] p. 57

Al CLR no le importa ni examina la versión de información de ensamblaje.

Esta AssemblyVersiones la única versión que le interesa a CLR (pero le importa la totalidad AssemblyVersion)

AssemblyVersion es utilizado por el CLR para enlazar a ensamblados fuertemente nombrados. Se almacena en la tabla de metadatos de manifiesto AssemblyDef del ensamblado creado y en la tabla AssemblyRef de cualquier ensamblado que haga referencia a ella.

Esto es muy importante, porque significa que cuando hace referencia a un ensamblado con un nombre fuerte, está estrechamente vinculado a una versión de ensamblaje específica de ese ensamblaje. La versión de ensamblaje completa debe ser una coincidencia exacta para que el enlace tenga éxito. Por ejemplo, si hace referencia a la versión 1.0.0.0 de un ensamblado con nombre en tiempo de compilación, pero solo la versión 1.0.0.1 de ese ensamblaje está disponible en tiempo de ejecución, ¡el enlace fallará! (A continuación, deberá solucionar este problema utilizando la redirección de enlace de ensamblaje ).

Confusión sobre si todo AssemblyVersiontiene que coincidir. (Sí, lo hace)

Existe una pequeña confusión acerca de si la versión de ensamblaje completa tiene que coincidir exactamente para que se cargue un ensamblaje. Algunas personas tienen la falsa creencia de que solo las partes mayores y menores de la versión de la Asamblea tienen que coincidir para que la unión tenga éxito. Esta es una suposición sensata, sin embargo, en última instancia es incorrecta (a partir de .NET 3.5), y es trivial verificar esto para su versión del CLR. Simplemente ejecute este código de muestra .

En mi máquina, la segunda carga de ensamblaje falla, y las dos últimas líneas del registro de fusión dejan perfectamente claro por qué:

.NET Framework Version: 2.0.50727.3521
---
Attempting to load assembly: Rhino.Mocks, Version=3.5.0.1337, Culture=neutral, PublicKeyToken=0b3305902db7183f
Successfully loaded assembly: Rhino.Mocks, Version=3.5.0.1337, Culture=neutral, PublicKeyToken=0b3305902db7183f
---
Attempting to load assembly: Rhino.Mocks, Version=3.5.0.1336, Culture=neutral, PublicKeyToken=0b3305902db7183f
Assembly binding for  failed:
System.IO.FileLoadException: Could not load file or assembly 'Rhino.Mocks, Version=3.5.0.1336, Culture=neutral, 
PublicKeyToken=0b3305902db7183f' or one of its dependencies. The located assembly's manifest definition 
does not match the assembly reference. (Exception from HRESULT: 0x80131040)
File name: 'Rhino.Mocks, Version=3.5.0.1336, Culture=neutral, PublicKeyToken=0b3305902db7183f'

=== Pre-bind state information ===
LOG: User = Phoenix\Dani
LOG: DisplayName = Rhino.Mocks, Version=3.5.0.1336, Culture=neutral, PublicKeyToken=0b3305902db7183f
 (Fully-specified)
LOG: Appbase = [...]
LOG: Initial PrivatePath = NULL
Calling assembly : AssemblyBinding, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null.
===
LOG: This bind starts in default load context.
LOG: No application configuration file found.
LOG: Using machine configuration file from C:\Windows\Microsoft.NET\Framework64\v2.0.50727\config\machine.config.
LOG: Post-policy reference: Rhino.Mocks, Version=3.5.0.1336, Culture=neutral, PublicKeyToken=0b3305902db7183f
LOG: Attempting download of new URL [...].
WRN: Comparing the assembly name resulted in the mismatch: Revision Number
ERR: Failed to complete setup of assembly (hr = 0x80131040). Probing terminated.

Creo que la fuente de esta confusión probablemente se deba a que Microsoft originalmente tenía la intención de ser un poco más indulgente con esta coincidencia estricta de la versión completa de la Asamblea, al coincidir solo en las partes de la versión Mayor y Menor:

"Al cargar un conjunto, el CLR encontrará automáticamente la última versión de servicio instalada que coincida con la versión principal / secundaria del conjunto que se solicita". - Jeffrey Richter, [CLR a través de C # (Segunda edición)] p. 56

Este era el comportamiento en Beta 1 del 1.0 CLR, sin embargo, esta característica se eliminó antes de la versión 1.0 y no ha logrado volver a aparecer en .NET 2.0:

“Nota: acabo de describir cómo debe pensar en los números de versión. Desafortunadamente, el CLR no trata los números de versión de esta manera. [En .NET 2.0], el CLR trata un número de versión como un valor opaco, y si un ensamblaje depende de la versión 1.2.3.4 de otro ensamblaje, el CLR intenta cargar la versión 1.2.3.4 solamente (a menos que exista una redirección vinculante ) Sin embargo, Microsoft tiene planes de cambiar el cargador de CLR en una versión futura para que cargue la última compilación / revisión para una versión mayor / menor de un ensamblado. Por ejemplo, en una versión futura del CLR, si el cargador está tratando de encontrar la versión 1.2.3.4 de un ensamblado y existe la versión 1.2.5.0, el cargador recoge automáticamente la última versión de servicio. Este será un cambio muy bienvenido para el cargador de CLR. Por mi parte, no puedo esperar ". - Jeffrey Richter, [CLR a través de C # (Segunda edición)] p. 164 (El énfasis es mío)

Como este cambio aún no se ha implementado, creo que es seguro asumir que Microsoft ha retrocedido en este intento, y tal vez sea demasiado tarde para cambiarlo ahora. Traté de buscar en la web para averiguar qué sucedió con estos planes, pero no pude encontrar ninguna respuesta. Todavía quería llegar al fondo.

Así que le envié un correo electrónico a Jeff Richter y le pregunté directamente: supuse que si alguien sabía lo que sucedía, sería él.

Respondió dentro de las 12 horas, un sábado por la mañana, no menos, y aclaró que el cargador .NET 1.0 Beta 1 implementó este mecanismo de 'avance automático' para recoger la última compilación y revisión disponibles de un ensamblaje, pero este comportamiento fue revertido antes de .NET 1.0 enviado. Más tarde se intentó revivir esto, pero no llegó antes de que se enviara el CLR 2.0. Luego vino Silverlight, que tuvo prioridad para el equipo CLR, por lo que esta funcionalidad se retrasó aún más. Mientras tanto, la mayoría de las personas que vivían en los días de CLR 1.0 Beta 1 desde entonces se han mudado, por lo que es poco probable que esto vea la luz del día, a pesar de todo el arduo trabajo que ya se ha dedicado.

Parece que el comportamiento actual está aquí para quedarse.

También vale la pena señalar de mi discusión con Jeff que AssemblyFileVersion solo se agregó después de la eliminación del mecanismo de 'avance automático', porque después de 1.0 Beta 1, cualquier cambio en la AssemblyVersion fue un cambio importante para sus clientes, entonces hubo ningún lugar para almacenar de forma segura su número de compilación. AssemblyFileVersion es ese refugio seguro, ya que el CLR nunca lo examina automáticamente. Tal vez sea más claro de esa manera, tener dos números de versión separados, con significados separados, en lugar de tratar de hacer esa separación entre las partes Mayor / Menor (rompiendo) y Construir / Revisar (sin romper) de la Versión de la Asamblea.

El resultado final: piense detenidamente cuando cambie su AssemblyVersion

La moraleja es que si está enviando ensamblajes a los que otros desarrolladores harán referencia, debe tener mucho cuidado cuando cambie (y no) la versión de ensamblaje de esos ensamblajes. Cualquier cambio en la versión de ensamblaje significará que los desarrolladores de aplicaciones tendrán que volver a compilar con la nueva versión (para actualizar esas entradas de AssemblyRef) o usar redireccionamientos de enlace de ensamblaje para anular manualmente el enlace.

  • No cambie la versión de ensamblaje por una versión de servicio diseñada para ser compatible con versiones anteriores.
  • No cambiar el AssemblyVersion para un lanzamiento que se conoce tiene cambios de ruptura.

Simplemente eche otro vistazo a los atributos de la versión en mscorlib:

// Assembly mscorlib, Version 2.0.0.0
[assembly: AssemblyFileVersion("2.0.50727.3521")]
[assembly: AssemblyInformationalVersion("2.0.50727.3521")]
[assembly: AssemblyVersion("2.0.0.0")]

Tenga en cuenta que es el AssemblyFileVersion el que contiene toda la información de servicio interesante (es la parte de Revisión de esta versión que le dice en qué Service Pack está), mientras que el AssemblyVersion está arreglado en un viejo 2.0.0.0 aburrido. ¡Cualquier cambio en la versión de la Asamblea obligaría a cada aplicación .NET que haga referencia a mscorlib.dll a volver a compilar con la nueva versión!

Daniel Fortunov
fuente
99
Gran respuesta. Creo que el punto más importante que hizo, y lo que MS debería recomendar explícitamente, es hacer cambios en la versión de la Asamblea si y solo si la nueva versión rompe la compatibilidad con versiones anteriores.
mwolfe02
1
Una de las preguntas que me hago varias veces es cuándo debería cambiar cada uno de estos números de versión, sus puntos en la versión de la Asamblea agregaron una buena claridad a esto y toda la respuesta fue una lectura interesante.
RyanfaeScotland
Estoy viendo muchas respuestas que explican los conceptos detrás de estas tres cosas. Pero, ¿cómo se relacionan con los números de versión editables en las propiedades del proyecto? Cuando hace clic en Información de ensamblaje ... tiene la opción de cambiar dos versiones. Y al cambiar la Versión de ensamblaje, se cambia la carpeta donde se encuentra user.config, y al cambiar la Versión del archivo, se cambia el número de versión que se muestra al hacer clic con el botón derecho en el archivo exe e ir a sus propiedades. Entonces, ¿cómo corresponden esos dos números de versión a AssemblyVersion, AssemblyFileVersion y AssemblyInformationalVersion?
Kyle Delaney
El enlace a la publicación del blog que escribió originalmente da un 404. ¿Hay una nueva ubicación para eso?
Rob K
@RobK: Ah, disculpas. Ese sitio web no funciona, pero todo el contenido de la publicación del blog se reproduce en la respuesta para que no se pierda nada. Eliminaré el enlace roto ahora.
Daniel Fortunov
43

AssemblyVersionprácticamente permanece interno en .NET, mientras que AssemblyFileVersiones lo que Windows ve. Si va a las propiedades de un ensamblaje sentado en un directorio y cambia a la pestaña de versión, esto AssemblyFileVersiones lo que verá en la parte superior. Si ordena los archivos por versión, esto es lo que utiliza Explorer.

Los AssemblyInformationalVersionmapas a la "Versión del producto" y están destinados a ser puramente "utilizados por humanos".

AssemblyVersiones sin duda lo más importante, pero tampoco me saltaría AssemblyFileVersion. Si no proporciona AssemblyInformationalVersion, el compilador lo agrega por usted quitando la pieza de "revisión" de su número de versión y dejando el major.minor.build.

Bob King
fuente
23

AssemblyInformationalVersiony AssemblyFileVersionse muestran cuando ve la información de "Versión" en un archivo a través del Explorador de Windows al ver las propiedades del archivo. Estos atributos en realidad se compilan en un VERSION_INFOrecurso creado por el compilador.

AssemblyInformationalVersion es el valor de "Versión del producto". AssemblyFileVersiones el valor de "Versión del archivo".

El AssemblyVersiones específico de .NET conjuntos y se utiliza por el .NET conjunto cargador saber qué versión de un conjunto de carga / bind en tiempo de ejecución.

De estos, el único que es absolutamente requerido por .NET es el AssemblyVersionatributo. Desafortunadamente, también puede causar la mayoría de los problemas cuando cambia indiscriminadamente, especialmente si tiene un nombre sólido para sus ensamblajes.

Scott Dorman
fuente
9

Para mantener esta pregunta actualizada, vale la pena resaltar que AssemblyInformationalVersionNuGet utiliza y refleja la versión del paquete, incluido cualquier sufijo previo al lanzamiento.

Por ejemplo, una versión de ensamblaje de 1.0.3. * Empaquetada con el núcleo asp.net dotnet-cli

dotnet pack --version-suffix ci-7 src/MyProject

Produce un paquete con la versión 1.0.3-ci-7 que puede inspeccionar con reflexión usando:

CustomAttributeExtensions.GetCustomAttribute<AssemblyInformationalVersionAttribute>(asm);
KCD
fuente
7

Vale la pena señalar algunas otras cosas:

1) Como se muestra en el cuadro de diálogo Propiedades del Explorador de Windows para el archivo de ensamblaje generado, hay dos lugares llamados "Versión del archivo". El que se ve en el encabezado del cuadro de diálogo muestra AssemblyVersion, no AssemblyFileVersion.

En la sección Información de otra versión, hay otro elemento llamado "Versión del archivo". Aquí es donde puede ver lo que se ingresó como AssemblyFileVersion.

2) AssemblyFileVersion es solo texto sin formato. No tiene que ajustarse a las restricciones del esquema de numeración que hace AssemblyVersion (<build> <65K, por ejemplo). Puede ser 3.2. <Texto de etiqueta de lanzamiento>. <Fechahora>, si lo desea. Su sistema de construcción tendrá que completar los tokens.

Además, no está sujeto a la sustitución de comodines que es AssemblyVersion. Si solo tiene un valor de "3.0.1. *" En AssemblyInfo.cs, eso es exactamente lo que se mostrará en el elemento Información de otra versión-> Versión de archivo.

3) Sin embargo, no conozco el impacto sobre un instalador de usar algo diferente a los números de versión numéricos de archivos.

DavidM
fuente
2

Cuando se cambia la versión de ensamblaje de un ensamblaje, si tiene un nombre seguro, los ensamblajes de referencia deben volver a compilarse; de ​​lo contrario, el ensamblaje no se carga. Si no tiene un nombre seguro, si no se agrega explícitamente al archivo del proyecto, no se copiará en el directorio de salida cuando se compila, por lo que puede perder los ensamblajes dependientes, especialmente después de limpiar el directorio de salida.

linquizar
fuente
¡Esto es muy interesante! ¿Podría elaborar un poco sobre la parte "no se copiará al directorio de salida"? Quizás un enlace a donde se define este comportamiento. Nunca entendí por qué algunas dependencias indirectas se copiaban a veces, pero no siempre. Esto debe estar 100% relacionado con él.
julealgon