How to Manually Set Assembly Version - c#

This one is giving me such a headache. We used to put things in the project properties under [assembly: AssemblyVersion("1.0.0.0")] I am totally fine with change so I do not care where it is. I understand they are going to a new standard for versions as well, also totally fine.
Plenty of documents out there point to the project.json file which is clearly a waste as this is no longer a legit file. More recent say add the following to your .csproj file:
<PropertyGroup>
<VersionPrefix>1.2.3</VersionPrefix>
<VersionSuffix>alpha</VersionSuffix>
</PropertyGroup>
Also a total waste. Only because I can not seem to be able to read it. The following always gives me 1.0.0.0.
PlatformServices.Default.Application.ApplicationVersion
Not to mention when I right-click in File Explorer and click Properties, then Details tab also always says 1.0.0.0.
So, how I can set the version of each assembly within my solution AND then read them later at runtime?

On method is to set either of these values in your project file:
<PropertyGroup>
<Version>1.3.5.7</Version>
<FileVersion>2.4.6.8</FileVersion>
</PropertyGroup>
And read them like this:
var fileVersion = Assembly.GetEntryAssembly()
.GetCustomAttribute<AssemblyFileVersionAttribute>()
.Version;
var informationalVersion = Assembly.GetEntryAssembly()
.GetCustomAttribute<AssemblyInformationalVersionAttribute>()
.InformationalVersion;
It's worth noting that setting these value in the .csproj file does autogenerate (so don't try to edit it) a file similar to the legacy AssemblyInfo.cs containing something like this:
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
using System;
using System.Reflection;
//snip
[assembly: System.Reflection.AssemblyFileVersionAttribute("2.4.6.8")]
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.2.3")]
// Generated by the MSBuild WriteCodeFragment class.

Turns out this started working when .Net Core 2.0 came out. When you right-click on the Project and then click Properties there is a UI for it as seen below:
The Package Version, Assembly Version and Assembly File Version correspond to the Version, AssemblyVersion and FileVersion settings in the .csproj file respectively:
<PropertyGroup>
<Version>1.1.0</Version>
<AssemblyVersion>1.1.0.9</AssemblyVersion>
<FileVersion>1.1.0.9</FileVersion>
</PropertyGroup>
I then created a utility method in each project of my solution that does the following:
public static VersionInformationModel GetVersionInformation() {
var Result = new VersionInformationModel {
Version = Assembly.GetExecutingAssembly().GetName().Version.ToString(),
BuildDate = System.IO.File.GetLastWriteTime(Assembly.GetExecutingAssembly().Location),
Configuration = Assembly.GetExecutingAssembly().GetCustomAttribute<AssemblyConfigurationAttribute>().Configuration,
TargetFramework = Assembly.GetExecutingAssembly().GetCustomAttribute<System.Runtime.Versioning.TargetFrameworkAttribute>().FrameworkName,
};
return Result;
}
So on an admin page of my site, I can know when version and other particulars about each project as it stands on whatever server I am looking at.

Related

GitVersion: Copyright attribute missing when publishing a single file with *GenerateAssemblyInfo* set to *false*

I am using GitVersion in my WPF-project. When publishing my app I use profile setting Produce single file which I want to stick to. Publish only runs successfully if I set im my .csproj-file:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
</PropertyGroup>
</Project>
I also have set the Copyright information in my .csproj-file:
<Copyright>Copyright © ...</Copyright>
With GenerateAssemblyInfo set to true I can read the
Copyright attribute in my code by reflection:
var copyRightAttribute = (AssemblyCopyrightAttribute)Assembly.GetExecutingAssembly().GetCustomAttribute(typeof(AssemblyCopyrightAttribute));
Also in file-details it is visible:
With GenerateAssemblyInfo set to false publishing the Singe
file runs successfully but Copyright is missing in code and in file
details.
How can I have all at the same time?
Use GitVersion AND
publish a Single file AND
access Copyright attribute in code AND
see Copyright in file-details
When you disable automatic AssemblyInfo generation,
then you will need to include an AssemblyInfo.cs file yourself into your project,
holding the AssemblyCopyrightAttribute and others.
The ones in the .csproj file will not be considered anymore when it contains an <GenerateAssemblyInfo>false</GenerateAssemblyInfo>.
Note that this also includes the version numbers and more.
An AssemblyInfo.cs example:
using System.Reflection;
[assembly: AssemblyCopyright("Your Copyright Goes Here")]
[assembly: AssemblyTitle("Your Title")]
[assembly: AssemblyDescription("Your Description")]
[assembly: AssemblyVersion("1.0.0")]
[assembly: AssemblyFileVersion("1.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]

Xml Doc comments in c# embedded resources on .NET (Core)

I've got a c# project migrated from .NET framework to .NET Core (and then .NET 5).
We haven't touched our .resx files at all in a couple of years, but now that I updated a .resx file, the Resources.Designer.cs files got re-generated (good), dropping all the previously-included Xml Doc (bad, produces large diff, also losing information).
How do I instruct my Resx build step to retain/generate XML Doc like in the old times?
Originally this code was written and generated with Visual Studio on Windows, and we now use Rider on Macs
EDIT: looks like it's not specific to .NET 5, but rather to Windows+VS vs. Mac+Rider pairing, as a Windows dev on my team regenerated those comments on top of my changes.
How do I get this on Mac/Linux without Visual Studio?
Old file portion:
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace Resources {
using System;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
public class Resources {
...
/// <summary>
/// Looks up a localized string similar to About.
/// </summary>
public static string About {
get {
return ResourceManager.GetString("About", resourceCulture);
}
}
NEW file portion:
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace Resources {
using System;
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")]
[System.Diagnostics.DebuggerNonUserCodeAttribute()]
[System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
public class Resources {
...
public static string About {
get {
return ResourceManager.GetString("About", resourceCulture);
}
}
The file in question goes down from 12k LOC to 8k LOC, which is a lot of comments lost, and makes things harder to work with.
I don't know if this will work for you as a solve, but my suggestion would be that when there is an OS / Tooling issue, fire up Docker and execute the MSBUILD command manually from a Windows Docker image. I suggest this since your WinDev coworker is regenerating the missing comments.
MSBUILD Commands
The only gotcha that came to mind that wouldn't work is like the one linked below, where they are still needing to specify the Configuration type and that the Project (.CSPROJ file) was set to "building" documentation on that configuration. Document generation was "build" and Visual Studio "Configuration" specific.
For example, if Docs were built when the Project build was initiated with "Debug" and "Any CPU" set as the configuration then that is the same one you need to invoke in the MSBUILD CLI with the necessary parameters like
That would look sort of like this (going by sketchy memory).
msbuild.exe MyProject.csproj `
/p:Configuration=Debug `
/p:Platform="Any CPU" `
/p:GenerateDocumentation `
/p:DocumentationFile="MyProject.xml"
Stackoverflow - MSBUILD XML Docs
This can all be scripted so its pretty much start a Docker image, POSH script the build document generation, then copy document to local host. A bit clunky, but you only have to do it when you are all finished and ready to push it up.

How to public sign a project with MSBuild

I have a C# .NET Framework project which I sign using a .pfx file on my local system. In the .csproj file the following properties are set:
<PropertyGroup>
<SignAssembly>true</SignAssembly>
</PropertyGroup>
<PropertyGroup>
<AssemblyOriginatorKeyFile>keyfile.pfx</AssemblyOriginatorKeyFile>
</PropertyGroup>
This file is part of an open source project. I'm trying to create a pipeline which runs on certain commits. When I commit something, the original *.pfx can be installed using the password which is stored as a GitHub secret. The problem is that when forked repos make a pull request, the pipeline fails, because the GitHub secrets are not available to them.
Long story short, I found out that I can use public signing for this purpose. However, when I try to build my project using
msbuild src\TcBlackCore\TcBlackCore.csproj -t:Rebuild -p:DelaySign=false -p:PublicSign=true -p:Configuration=Release -p:Platform=AnyCPU -p:TreatWarningsAsErrors=true
I get the following error:
CS7102: Compilation options 'PublicSign' and 'CryptoKeyContainer' can't both be specified at the same time
I couldn't find any information on this error code except for one GitHub issue which mentions:
ERR_MutuallyExclusiveOptions CS7102
What are the mutually exclusive options here? The DelaySign should be set to the docs. And what should I do to get the public signing to work such that forked repos can be build?
> msbuild -version
Microsoft (R) Build Engine version 15.9.21+g9802d43bc3 for .NET Framework
The problem with public sign is that while the compiler applies a public key, is doesn't actually signs the assembly. It is like a 'mark' on the assembly.
In your case, you cannot use both CryptoKeYContainer and PublicSign at the same time because they are doing almost identical things, thus the compiler prompts the error.
for your purpose I would recommend using the DelaySign - as Microsoft docs states:
Use DelaySign - If you want a fully signed assembly. Use DelaySign
if you only want to place the public key in the assembly
For reference the tag is:
<DelaySign>true</DelaySign>

.net Core parse csproj file to object

The problem- We can parse a csproj file in some ways, but most of the information is not in the file, but is either by default or affected by other properties.
I want to work against csproj files and solution- get project dependencies, get properties and items (things like 'TargetFramework', compiled files..)
The TargetFramework can be a tag with value, or 'TargetFrameworks' tag with multi-values that parsed to 'TargetFramework'.
The old solution- MSBuild provide a microsoft.build.evaluation library to work with csproj file, but this library compiled to net471, and cause errors when we use it in netcoreapp.
What will be the solution for the problem, in .net core projects?
For .Net Core Microsoft.Build NuGet Package works as below:
var projectRootElement = ProjectRootElement.Open(csprojPath);
projectRootElement.AddProperty("Version", "3.4.5");
projectRootElement.Save();
If Version exists it overrides it. If not exist adds new property name is "Version" and value is "3.4.5".
Also you can get all properties which defined in .csproj
var projectRootElement = ProjectRootElement.Open(csprojPath);
foreach (var property in projectRootElement.Properties)
{
Console.WriteLine($"Name: {property.Name} - Value: {property.Value}");
}
Tested in .NetCore 5.0

How do I auto-increment nuget package version using VSTS build process?

In this video from MSDN at the 3:34 second mark, the presenter shows how to append the Build ID to a nuget's version. In the MSBuild arguments, he specifies:
/t:pack /p:PackageVersion=1.0.$(Build.BuildId)
So, when the project is built by VSTS, the nuget assembly's revision number is using the build id.
I would like to do something similar. Instead of hard coding the 1.0 in the build definition, I'd like to retrieve that from .csproj file. I am using the new .csproj file which stores nuget information.
For example, I'd like to specify in the csproj:
<Version>0.0.1-beta</Version>
Then, VSTS would append the BuildID and generate the assembly version as 0.0.0.1-beta.49 (49 being the build id)
I ended up doing the opposite of what Shayki Abramczyk suggested.
I use a task called "Variables Task Pack". It can be found here (and is free at the time of this answer): https://marketplace.visualstudio.com/items?itemName=YodLabs.VariableTasks#qna
Using this task, I set two variable: $(BuildId) and $(ReleaseType). See the settings snapshots at the end of the answer.
Then, in my CSPROJ project file, I modified the nuget version to use the two environment variables. Here's a clip of the project file:
<PropertyGroup>
<Version>0.0.0.0$(BuildId)$(ReleaseType)</Version>
<FileVersion>0.0.0.0$(BuildId)$(ReleaseType)</FileVersion>
...
</PropertyGroup>
IMPORTANT: Notice the extra 0 in front of $(BuildId). I had to add that in order to build locally. Without it, the build failed with an incorrect version format error.
Now, after building, I get the buildid as my revision number and release type appended.
Here are the screen shots showing configuration of both variables.
You can create a Power Shell script that retrieves the version from csproj file, then add the version to a new environment variable with this command: Set-VstsTaskVariable
For Example:
$csprojId = $retrivedIdfromTheFile
Set-VstsTaskVariable -Name "CSPROJ_ID" -Value $csprojId
Now you can use the CSPROJ_ID variable on the MSBuild arguments:
/p:PackageVersion=$(CSPROJ_ID).$(Build.BuildId)

Categories