How to get the current product version in C#? - c#

How can I programmatically get the current product version in C#?
My code:
VersionNumber = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString();
I am getting VersionNumber=1.0.0.0, but the current version is 1.0.0.12.

There are three versions: assembly, file, and product. To get the product version:
using System.Reflection;
using System.Diagnostics;
Assembly assembly = Assembly.GetExecutingAssembly();
FileVersionInfo fileVersionInfo = FileVersionInfo.GetVersionInfo(assembly.Location);
string version = fileVersionInfo.ProductVersion;

I got the answer to my question its Just give the reference to System.Deployment.Application and though it wont work in developement of the visual studio but it will work once the application is deployed.
//using System.Deployment.Application;
//using System.Reflection;
public string CurrentVersion
{
get
{
return ApplicationDeployment.IsNetworkDeployed
? ApplicationDeployment.CurrentDeployment.CurrentVersion.ToString()
: Assembly.GetExecutingAssembly().GetName().Version.ToString();
}
}

System.Reflection.Assembly.GetEntryAssembly().GetName().Version

Another approach to getting the product version (which is specified using the AssemblyInformationalVersionAttribute) is
private static string AssemblyProductVersion
{
get
{
object[] attributes = Assembly.GetExecutingAssembly()
.GetCustomAttributes(typeof(AssemblyInformationalVersionAttribute), false);
return attributes.Length == 0 ?
"" :
((AssemblyInformationalVersionAttribute)attributes[0]).InformationalVersion;
}
}

Try this:
var thisApp = Assembly.GetExecutingAssembly();
AssemblyName name = new AssemblyName(thisApp.FullName);
VersionNumber = "v. " + name.Version;
Also, see this Microsoft Doc on the AssemblyName.Version property.

In C# you need to use reflection and diagnostics
Assembly assembly = Assembly.GetExecutingAssembly();
FileVersionInfo fileVersionInfo = FileVersionInfo.GetVersionInfo(assembly.Location);
string version = fileVersionInfo.ProductVersion;

All these answers ask for the assembly with .GetExecutingAssembly().
If you have this code in a dll, it will return the dll version number.
Swap that call for GetCallingAssembly() to get the place in your code that wanted to know.
/// <summary>
/// Returns version like 2.1.15
/// </summary>
public static String ProductVersion
{
get
{
return new Version(FileVersionInfo.GetVersionInfo(Assembly.GetCallingAssembly().Location).ProductVersion).ToString();
}
}

var productVersion = FileVersionInfo.GetVersionInfo(typeof(SomeClassFromDesiredAssembly).Assembly.Location).ProductVersion;

I had the same issue as most of you. It would always show 1.0.0.0 unless you manually went in and updated assemblyInfo.cs to the version you wanted to display. I think we wanted to display the publish version-revision number under the project properties but that doesn't seem to be an option (from what I've read).
I'm not sure if back when these comments were made this existed, but now in the assemblyinfo.cs there is a way to do this automatically. I too was not content with having to manually update these with every publish.
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.*")]
That * auto-increments with each publish. It won't be the same as the publish number you see under the project properties, but it definitely increments and is definitely better than doing it by hand.
You then have a couple options to display it as mentioned above. I personally used this which I found on another site
Version version = Assembly.GetExecutingAssembly().GetName().Version;
lblRevision.Text = String.Format("{0}.{1}.{2}.{3}", version.Major, version.Minor, version.Build, version.Revision);

Related

Codegeneration at runtime from a string to console exe is not working in C# .NET6

I have some code which must be able to generated a console application at runtime (Codegeneration with System.CodeDom). I did this already a lot, but in NET 6 now I am struggling with that and the new API. In the code below I try to compile simply from a string. See below the static class with method Start() which then should generates the application.
The compilations seems fine, no errors at the end. But when starting the generated AppCodegenerated.exe, it shows some reference exception with System.Runtime.
Please help, any Idea? Already researched a lot but could not find any useful solution..
//-
I used the Visual Studio 2022 / NET 6 and theses Nuget's:
using Basic.Reference.Assemblies;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Text;
using System.Text;
namespace CompilerSimplified
{
public static class Compiler
{
public static bool Start()
{
string FileName = "AppCodegenerated";
string ExePath = AppDomain.CurrentDomain.BaseDirectory + #"\" + FileName + ".exe";
string code = #"using System; Console.WriteLine(""Hello.""); Console.ReadLine(); ";
// ------- References -------------
// .net platform references
List<MetadataReference> References = new List<MetadataReference>();
foreach (var item in ReferenceAssemblies.Net60) // ReferenceAssemblies from Nuget: Basic.Reference.Assemblies;
References.Add(item);
// or tried this: loop manually through system platform
//string[] fileEntries = Directory.GetFiles(#"C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\6.0.0\ref\net6.0\", "*.dll");
//foreach (string fileName in fileEntries)
// references.Add(MetadataReference.CreateFromFile(fileName));MetadataReference.CreateFromFile(fileName));
// ------- References END -------------
// delete existing file
if (File.Exists(ExePath))
File.Delete(ExePath);
// compiler options
CSharpCompilationOptions DefaultCompilationOptions =
new CSharpCompilationOptions(outputKind: OutputKind.ConsoleApplication, platform: Platform.AnyCpu)
.WithOverflowChecks(true).WithOptimizationLevel(OptimizationLevel.Release);
// encode soucre code
string sourceCode = SourceText.From(code, Encoding.UTF8).ToString();
// CSharp options
var parsedSyntaxTree = Parse(sourceCode, "", CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp10));
// compilation
var compilation = CSharpCompilation.Create(FileName, new SyntaxTree[] { parsedSyntaxTree }, references: References, DefaultCompilationOptions);
var result = compilation.Emit(ExePath);
// return
if (result.Success)
return true;
else
return false;
}
private static SyntaxTree Parse(string text, string filename = "", CSharpParseOptions options = null)
{
var stringText = SourceText.From(text, Encoding.UTF8);
return SyntaxFactory.ParseSyntaxTree(stringText, options, filename);
}
}
}
Above code runs fine without error and exports the AppCodegenerated.exe into the project /bin folder.
Execution of this generated AppCodegenerated.exe shows following on the output console:
Unhandled exception: System.IO.FileNotFoundException:
The file or assembly "System.Runtime, Version = 6.0.0.0, Culture = neutral,
PublicKeyToken = b03f5f7f11d50a3a" or a dependency on it was not found.
The system can not find the stated file.
It is not possible to codegenerate directly a console application like the initial approach above. One possible solution is to generate first a dll (what I mentioned above in the example code is working fine), and from there include that .dll into a .exe, from where the functionality can run.

Application version is not set during Form Load

I have a WinForm App, using C# and SQL.
I have a particular form Load Event that returns me currentversion of My app.
Here is how it looks.
public Version assm
{
get
{
return ApplicationDeployment.CurrentDeployment.CurrentVersion;
}
}
I'm using the assm function to get release details like major version, minor, build etc.
label1.Text = assm.Major.ToString();
label5.Text = assm.Minor.ToString();
label6.Text = assm.Build.ToString();
label7.Text = assm.Revision.ToString();
But while loading the form, it gives the "Application identity is not set" Exception on the line: return ApplicationDeployment.CurrentDeployment.CurrentVersion;
What could be the reason?
Furthermore is there any other way to get application version details?
If you set the AssemblyInformationalVersion attribute in your AssemblyInfo.cs, you can get that value using FileVersionInfo.ProductVersion. E.g.
Assembly assembly = Assembly.GetExecutingAssembly();
FileVersionInfo fileVersionInfo = FileVersionInfo.GetVersionInfo(assembly.Location);
string version = fileVersionInfo.ProductVersion;
The value you put in AssemblyInformationalVersion can be anything you like really, it's not restricted to major.minor, etc. So values such as "1.5 beta 1", is totally valid.
See MSDN for more info http://msdn.microsoft.com/en-us/library/system.diagnostics.fileversioninfo.productversion(v=vs.110).aspx
So to add the extra version info, you'll have an Assembly.cs that will include something like:
[assembly: AssemblyVersion("1.5.*")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.5 beta 1")]
You can get the assembly version using this:
public Version assm
{
get
{
return Assembly.GetExecutingAssembly().GetName().Version;
}
}
i use this:
public string GetVersion()
{
Version v = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version;
return " v." + v.Major + "." + v.Minor + "." + v.Build + "." + v.Revision;
}

Set AssemblyInfo Version numbers with MSI setup version

I am using a setup project to publish my projects. I want the version of each project to be the same as the setup version.
I want to change my setup version property in Visual Studio and after building, for all project versions to be updated from this property, is this possible?
Projects have Assembly & File version numbers: (not setup versions I edited your question accordingly)
Answer 1:
If you want to make the Setup projects version number set the Assembly & File version numbers you need to do it with a script/exe that gets triggered by the build.
This article on How To Update Assembly Version Number Automatically shows half the solution...
From the research I did it is not possible to use the SetupVersion in a PreBuildEvent. There isn't a $SetupVersion command for it: http://msdn.microsoft.com/en-us/library/42x5kfw4(v=vs.80).aspx
Having to change the PreBuildEvent each build as shown in this comment in the Code Project article using the -set: command is not ideal.
The solution we need is a PreBuildEvent to call the AssemblyInfoUtil.exe and have it read the "ProductVersion" from the vdproj project file. And then update the Assembly version number(s).
I have modified the code from the article to show you how to read the product version from the Setup.vdproj and this is how it can be called from a PreBuildEvent:
AssemblyInfoUtil.exe -setup:"C:\Program Files\MyProject1\Setup1\Setup1.vdproj" -ass:"C:\Program Files\MyProject1\AssemblyInfo.cs"
This is the modified code:
using System;
using System.IO;
using System.Text;
namespace AssemblyInfoUtil
{
class AssemblyInfoUtil
{
private static int incParamNum = 0;
private static string fileName = "";
private static string setupfileName = "";
private static string versionStr = null;
private static bool isVB = false;
[STAThread]
static void Main(string[] args)
{
for (int i = 0; i < args.Length; i++) {
if (args[i].StartsWith("-setup:")) {
string s = args[i].Substring("-setup:".Length);
setupfileName = int.Parse(s);
}
else if (args[i].StartsWith("-ass:")) {
fileName = args[i].Substring("-ass:".Length);
}
}
//Jeremy Thompson showing how to detect "ProductVersion" = "8:1.0.0" in vdproj
string setupproj = System.IO.File.ReadAllText(setupfileName);
int startPosOfProductVersion = setupproj.IndexOf("\"ProductVersion\" = \"") +20;
int endPosOfProductVersion = setupproj.IndexOf(Environment.NewLine, startPosOfProductVersion) - startPosOfProductVersion;
string versionStr = setupproj.Substring(startPosOfProductVersion, endPosOfProductVersion);
versionStr = versionStr.Replace("\"", string.Empty).Replace("8:",string.Empty);
if (Path.GetExtension(fileName).ToLower() == ".vb")
isVB = true;
if (fileName == "") {
System.Console.WriteLine("Usage: AssemblyInfoUtil
<path to :Setup.vdproj file> and <path to AssemblyInfo.cs or AssemblyInfo.vb file> [options]");
System.Console.WriteLine("Options: ");
System.Console.WriteLine(" -setup:Setup.vdproj file path");
System.Console.WriteLine(" -ass:Assembly file path");
return;
}
if (!File.Exists(fileName)) {
System.Console.WriteLine
("Error: Can not find file \"" + fileName + "\"");
return;
}
System.Console.Write("Processing \"" + fileName + "\"...");
StreamReader reader = new StreamReader(fileName);
StreamWriter writer = new StreamWriter(fileName + ".out");
String line;
while ((line = reader.ReadLine()) != null) {
line = ProcessLine(line);
writer.WriteLine(line);
}
reader.Close();
writer.Close();
File.Delete(fileName);
File.Move(fileName + ".out", fileName);
System.Console.WriteLine("Done!");
}
private static string ProcessLine(string line) {
if (isVB) {
line = ProcessLinePart(line, "<Assembly: AssemblyVersion(\"");
line = ProcessLinePart(line, "<Assembly: AssemblyFileVersion(\"");
}
else {
line = ProcessLinePart(line, "[assembly: AssemblyVersion(\"");
line = ProcessLinePart(line, "[assembly: AssemblyFileVersion(\"");
}
return line;
}
private static string ProcessLinePart(string line, string part) {
int spos = line.IndexOf(part);
if (spos >= 0) {
spos += part.Length;
int epos = line.IndexOf('"', spos);
string oldVersion = line.Substring(spos, epos - spos);
string newVersion = "";
bool performChange = false;
if (incParamNum > 0) {
string[] nums = oldVersion.Split('.');
if (nums.Length >= incParamNum && nums[incParamNum - 1] != "*") {
Int64 val = Int64.Parse(nums[incParamNum - 1]);
val++;
nums[incParamNum - 1] = val.ToString();
newVersion = nums[0];
for (int i = 1; i < nums.Length; i++) {
newVersion += "." + nums[i];
}
performChange = true;
}
}
else if (versionStr != null) {
newVersion = versionStr;
performChange = true;
}
if (performChange) {
StringBuilder str = new StringBuilder(line);
str.Remove(spos, epos - spos);
str.Insert(spos, newVersion);
line = str.ToString();
}
}
return line;
}
}
}
Answer 2:
To my way of thinking a better way is to use a Shared Assembly Info class rather than individual AssemblyInfo class files.
To implement this, create a file in the solution folder named SharedAssemblyInfo.cs and then add a link in each project to SharedAssemblyInfo.cs. You can also move the linked SharedAssemblyInfo.cs into the Properties folder so that it sits side-by-side with the AssemblyInfo.cs that is specific to each project in the solution, as shown below.
Here is a sample SharedAssemblyInfo.cs file:
using System;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyCompany("Saint Bart Technologies")]
[assembly: AssemblyProduct("Demo")]
[assembly: AssemblyCopyright("Copyright ? Saint Bart 2013")]
[assembly: AssemblyTrademark("")]
// Make it easy to distinguish Debug and Release (i.e. Retail) builds;
// for example, through the file properties window.
#if DEBUG
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyDescription("Flavor=Debug")] // a.k.a. "Comments"
#else
[assembly: AssemblyConfiguration("Retail")]
[assembly: AssemblyDescription("Flavor=Retail")] // a.k.a. "Comments"
#endif
[assembly: CLSCompliant(true)]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// Note that the assembly version does not get incremented for every build
// to avoid problems with assembly binding (or requiring a policy or
// <bindingRedirect> in the config file).
//
// The AssemblyFileVersionAttribute is incremented with every build in order
// to distinguish one build from another. AssemblyFileVersion is specified
// in AssemblyVersionInfo.cs so that it can be easily incremented by the
// automated build process.
[assembly: AssemblyVersion("1.0.0.0")]
// By default, the "Product version" shown in the file properties window is
// the same as the value specified for AssemblyFileVersionAttribute.
// Set AssemblyInformationalVersionAttribute to be the same as
// AssemblyVersionAttribute so that the "Product version" in the file
// properties window matches the version displayed in the GAC shell extension.
[assembly: AssemblyInformationalVersion("1.0.0.0")] // a.k.a. "Product version"
Here is a sample AssemblyInfo.cs file:
// Note: Shared assembly information is specified in SharedAssemblyInfo.cs
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("WindowsFormsApplication2")]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("ffded14d-6c95-440b-a45d-e1f502476539")]
So each time you want to change all projects Assembly info you can do it in one spot. I assume you would want to set the MSI Setup Version the same as the Assembly version number, one manual step.
Answer 3:
Consider switching to use MSBuild it has all these kinds of benefits but I'm not sure if you have the time to pick it up right now.
Answer 4:
Assemblies can auto-increment their build numbers using the following asterisk syntax within AssemblyInfo.cs:
[assembly: AssemblyVersion("1.0.0.*")]
This is a good method because the point of tracking a build number is
to be able to recognize different builds. Having a pre-build changing
build numbers defeats this purpose as the build has not yet occurred.
Answer 5:
The other CodeProject answer here assumes you want to update the ProductVersion, ProductCode, PackageCode in the Setup MSI Project file. I didn't interpret your question that way and according to this thread there are problems:
pre-build event to change setup project's ProductVersion doesn't take effect until after the build
Answer 6 (new):
There is a few TFS Build plugins to set "Assembly Info": https://marketplace.visualstudio.com/items?itemName=bleddynrichards.Assembly-Info-Task
https://marketplace.visualstudio.com/items?itemName=bool.update-assembly-info
https://marketplace.visualstudio.com/items?itemName=ggarbuglia.setassemblyversion-task
I don't know if this solves your problem perfectly but you could implement a common class with all the configmanagment informations like:
public class VersionInfo{
public const string cProductVersion = "1.0.0"
//other version info
}
After you can update all your AssemblyInfo.cs with the new class:
[assembly: AssemblyVersion(VersionInfo.cProductVersion)]
I hope this helps.

How to load an assembly from GAC with wildcards in version number

In our application, we have the need to dynamically load 3rd-party assemblies where we do not know in advance all released assembly version numbers. All we know is, for example, that the major version number for the assembly must be "12". On a PC, multiple versions of the same assembly may be installed, having both higher and lower major version numbers.
I.e. we would need something like
Assembly myAssembly = Assembly.Load("SampleAssembly, Version=12.*.*.*");
and if the assembly versions 11.1.2.3, 12.7.6.5, and 13.9.8.7 are installed, it should load version 12.7.6.5.
I.e. it should be possible to specify wildcards for version number components and it also should be possible to omit Culture and PublicKeyToken.
When we do this with Assembly.Load(), we get a FileNotFoundException.
We cannot use Assembly.LoadWithPartialName() because it always loads the assembly with the highest version number, but we want a specific major version number instead, which possibly is less than the greatest installed assembly version number.
Is it possible to do this?
You could manually list the content of the GAC and compare it to your wildcards as so
class Program
{
static void Main(string[] args)
{
var assemblyName = "SimpleAssembly";
var versionRegex = new Regex(#"^12\.");
var assemblyFile = FindAssemblyFile(assemblyName, versionRegex);
if (assemblyFile == null)
throw new FileNotFoundException();
Assembly.LoadFile(assemblyFile.FullName);
}
static FileInfo FindAssemblyFile(string assemblyName, Regex versionRegex)
{
var path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Windows), "assembly", "GAC_MSIL", assemblyName);
var assemblyDirectory = new DirectoryInfo(path);
foreach (var versionDirectory in assemblyDirectory.GetDirectories())
{
if (versionRegex.IsMatch(versionDirectory.Name))
{
return versionDirectory.GetFiles()[0];
}
}
return null;
}
}

How do I programmatically get the GUID of an application in C# with .NET?

I need to access the assembly of my project in C#.
I can see the GUID in the 'Assembly Information' dialog in under project properties, and at the moment I have just copied it to a const in the code. The GUID will never change, so this is not that bad of a solution, but it would be nice to access it directly. Is there a way to do this?
Try the following code. The value you are looking for is stored on a GuidAttribute instance attached to the Assembly
using System.Runtime.InteropServices;
static void Main(string[] args)
{
var assembly = typeof(Program).Assembly;
var attribute = (GuidAttribute)assembly.GetCustomAttributes(typeof(GuidAttribute),true)[0];
var id = attribute.Value;
Console.WriteLine(id);
}
Or, just as easy:
string assyGuid = Assembly.GetExecutingAssembly().GetCustomAttribute<GuidAttribute>().Value.ToUpper();
It works for me...
Another way is to use Marshal.GetTypeLibGuidForAssembly.
According to MSDN:
When assemblies are exported to type libraries, the type library is assigned a LIBID. You can set the LIBID explicitly by applying the System.Runtime.InteropServices.GuidAttribute at the assembly level, or it can be generated automatically. The Tlbimp.exe (Type Library Importer) tool calculates a LIBID value based on the identity of the assembly. GetTypeLibGuid returns the LIBID that is associated with the GuidAttribute, if the attribute is applied. Otherwise, GetTypeLibGuidForAssembly returns the calculated value. Alternatively, you can use the GetTypeLibGuid method to extract the actual LIBID from an existing type library.
You should be able to read the GUID attribute of the assembly via reflection. This will get the GUID for the current assembly:
Assembly asm = Assembly.GetExecutingAssembly();
object[] attribs = asm.GetCustomAttributes(typeof(GuidAttribute), true);
var guidAttr = (GuidAttribute) attribs[0];
Console.WriteLine(guidAttr.Value);
You can replace the GuidAttribute with other attributes as well, if you want to read things like AssemblyTitle, AssemblyVersion, etc.
You can also load another assembly (Assembly.LoadFrom and all) instead of getting the current assembly - if you need to read these attributes of external assemblies (for example, when loading a plugin).
For an out-of-the-box working example, this is what I ended up using based on the previous answers.
using System.Reflection;
using System.Runtime.InteropServices;
label1.Text = "GUID: " + ((GuidAttribute)Attribute.GetCustomAttribute(Assembly.GetExecutingAssembly(), typeof(GuidAttribute), false)).Value.ToUpper();
Alternatively, this way allows you to use it from a static class:
/// <summary>
/// public GUID property for use in static class </summary>
/// <returns>
/// Returns the application GUID or "" if unable to get it. </returns>
static public string AssemblyGuid
{
get
{
object[] attributes = Assembly.GetEntryAssembly().GetCustomAttributes(typeof(GuidAttribute), false);
if (attributes.Length == 0) { return String.Empty; }
return ((System.Runtime.InteropServices.GuidAttribute)attributes[0]).Value.ToUpper();
}
}
There wasn't any luck here with the other answers, but I managed to work it out with this nice one-liner:
((GuidAttribute)(AppDomain.CurrentDomain.DomainManager.EntryAssembly).GetCustomAttributes(typeof(GuidAttribute), true)[0]).Value
To get the appID you could use the following line of code:
var applicationId = ((GuidAttribute)typeof(Program).Assembly.GetCustomAttributes(typeof(GuidAttribute), true)[0]).Value;
For this you need to include the System.Runtime.InteropServices;
Use:
string AssemblyID = Assembly.GetEntryAssembly().GetCustomAttribute<GuidAttribute>().Value;
Or in VB.NET:
Dim AssemblyID As String = Assembly.GetEntryAssembly.GetCustomAttribute(Of GuidAttribute).Value

Categories