Defining console app version, and referencing version information from app - c#

I have a .NET 5.0 console application. How can I create a version resource and then display that version in my application?
In the past, I have seen an AssemblyInfo.cs file. But I don't see anything like that in my new project.

I had to solve this problem recently: how do you know which version of a tool is deployed? And how can you automate the version number, so you don't accidentally use an old version?
In the past, that information was stored as attributes in AssemblyInfo.cs. In .NET Core, those attributes are now generated by project properties at runtime.
Andrew Lock explains how the various properties like Version, VersionPrefix, VersionSuffix,AssemblyVersion FileVersion, PackageVersion, InformationalVersion are used.
The most important ones are Version, VersionPrefix and VersionSuffix. That's because Version is used as the default for the other ones. Version in turn can be calculated as VersionPrefix-VersionSuffix if there's no explicit value.
Quoting the article:
The Version property is the value most commonly set when building .NET Core applications. It controls the default values of all the version numbers embedded in the build output, such as PackageVersion and AssemblyVersion so it's often used as the single source of the app/library version.
If you use System.Commandline, the version info displayed by --version is the InformationalVersion whose default comes from Version.
The default VersionPrefix is 1.0.0 and the default suffix is empty, resulting in version 1.0.0.
*Formulas
The nice thing is that the properties can have formulas. I was able to automatically generate a date-related version number simply by adding this to a csproj that contains no other version information
<VersionSuffix>$([System.DateTime]::UtcNow.ToString(`yyyyMMdd-HHmm`))</VersionSuffix>
Each time I build my tools now I get versions like 1.0.0-2021061501836
Overriding the properties
The project values can be overridden during build, either by specifying an explicit version suffix, or specifying an explicit value for the project properties, eg :
dotnet build --configuration Release --version-suffix preview2-final
Or
dotnet build --configuration Release /p:Version=1.2.3-preview2-final
This way, an automated release pipeline can specify a new version that overrides anything set in the project file

Related

How to fix Visual Studio 2022 Warning CA1416 "Call site reachable by all platforms" but "only supported on: 'windows'"?

So I have a C# class library project that I only intend to use on Windows. It contains some classes that use the System.Drawing.Image class which is only available on Windows. After upgrading to Visual Studio 2022 and setting the target framework to .NET 6.0 I'm seeing a bunch of warnings that say:
CA1416 "This call site is reachable on all platforms. 'SomeClass.SomeMethod' is only supported on: 'windows'.
See screenshot below for some examples:
In some sense, it's cool that VS2022 has scanned the library and found all the platform specific code that I'm using in the library. But I'd like to tell VS that I only plan to use the library on windows and it can mute all those warnings.
First I checked the Target framework option in the properties of the project but didn't seen any windows specific targets.
Then I decided to edit the project's .csproj directly and changed the Target framework from
<TargetFramework>net6.0</TargetFramework>
to
<TargetFramework>net6.0-windows</TargetFramework>
But, sadly, even after a recompile, that didn't make the warnings go away either. So then I did some reading on the CA1416 warnings and sure enough it says in the Microsoft Docs that the target framework moniker is ignored for assessing this warning, however, VS does add an attribute to the project based on the TFM that influences this warning, but it only does so if the project is configured to generate the AssemblyInfo.cs file on the fly. But, alas, my project's AssemblyInfo.cs is maintained as a actual file rather then having it auto generated at build time.
So at this point, I'm ready to punt the ball and just disable CA1416 warnings for my project. So in the project's .proj file I added CA1416 for both the release and debug builds like so:
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<NoWarn>1701;1702;CA1416;</NoWarn>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<NoWarn>1701;1702;CA1416;</NoWarn>
</PropertyGroup>
One would think that would be the end of those pesky warnings. (sigh)
As it turns out, after rebuilding the project the warnings still show up. Got any suggestions? I'm all ears.
I had success removing the CA1416 warnings by adding the following decorator to the top of the containing class:
[System.Runtime.Versioning.SupportedOSPlatform("windows")]
I'm only on VS2019 and using .net 5, but it may work for you. I tried this with VS2019 .net5 console project (top of class Program) and a .net5 class library (top of the class).
I added the System.Common.Drawing nuget package.
My code included:
string inputPath = #"C:\mypath\mypng.png";
Image i = Image.FromFile(inputPath);
Update:
Targeting Windows worked fine until one of our developers tried to start the solution on his Apple computer using Visual Studio 2022 for Mac Preview 1.
https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca1416
Reading .NET 6 Breaking changes Microsoft has a section about System.Drawing.Common.
https://learn.microsoft.com/en-us/dotnet/core/compatibility/core-libraries/6.0/system-drawing-common-windows-only
Their recommendations are the following:
To use these APIs for cross-platform apps, migrate to one of the
following libraries:
ImageSharp
[SkiaSharp][2]
[Microsoft.Maui.Graphics][3]
Alternatively, you can enable support for non-Windows platforms by
setting the System.Drawing.EnableUnixSupport runtime configuration
switch to true in the runtimeconfig.json file:
{
"runtimeOptions": {
"configProperties": {
"System.Drawing.EnableUnixSupport": true
}
}
}
This configuration switch was added to give cross-platform apps that
depend heavily on this package time to migrate to more modern
libraries. However, non-Windows bugs will not be fixed. In addition,
we may completely remove support for non-Windows platforms in a future
release, even if you enable it using the runtime configuration switch.
Note
Despite the name of the runtime switch,
System.Drawing.EnableUnixSupport, it applies to various non-Windows
platforms, such as macOS and Android, which can generally be
considered flavors of Unix.
Even though Microsoft.Maui.Graphics is in preview and is considered an experimental library I tried to use it given that Microsoft has the library as a recommended action library.
It seemed really promising at first but then I encountered a bug in their IImage Downsize method.
https://github.com/dotnet/Microsoft.Maui.Graphics/issues/247
Until that is fixed my temporary solution is using Target framework .NET 6, Target OS (none) and then use Exclude specific warnings as errors given that we have enabled Treat warnings as errors.
I have also created a runtimeconfig.template.json in our web project root with the following values:
{
"runtimeOptions": {
"configProperties": {
"System.Drawing.EnableUnixSupport": true
}
}
}
Original:
You can suppress the warning with dotnet_diagnostic.CA1416.severity = none but imao if you only intend to use it on Windows you should set Target OS to Windows for the project which will fix the warning.
https://learn.microsoft.com/en-us/dotnet/core/compatibility/code-analysis/5.0/ca1416-platform-compatibility-analyzer
Source:
https://stackoverflow.com/a/70272543/3850405
One way to solve this issue is to create an .editorconfig for the solution and then add the following line to that .editorconfig file:
dotnet_diagnostic.CA1416.severity = none
This will make all "Validate platform compatibility" warnings go away.
Similar to what #RonC did, I was able to solve the problem by adding a Rule to my .ruleset file:
<Rules AnalyzerId="Microsoft.Analyzers.ManagedCodeAnalysis" RuleNamespace="Microsoft.Rules.Managed">
<Rule Id="CA1416" Action="None"/>
</Rules>
Just keep in mind that this will apply to the whole project for which the ruleset file is used.

dotnet.exe CLI - Check if a newer nuget version is available

I developed a (non-public) nuget-tool. The installation was very easy:
dotnet tool install dotnet-mytoolname -g
My colleagues will also install these tool by the command.
In future I will release new versions of dotnet-mytoolname. Consumers will update it easy with dotnet.exe.
Now my problem:
If a developer runs an outdated version of that tool then I will hint it in console output (something like "a newer version is available").
How I can check with dotnet.exe if a new version is available?
The command below would do it but only for nuget.org. But our nuget-tool is not hosted on nuget.org but on a private azure-devops server.
dotnet tools search dotnet-mytoolname
The nuget-tool dotnet-mytoolname is a C# console-project.
Have you any ideas how I can check within that project if a newer version is available on azure-devops?
Thank you DavidG. Posting your suggestions as an answer to help other community members.
Installing dotnet outdated application will help you in resolving your issue
install .Net core and run the following command
dotnet tool install --global dotnet-outdated-tool
Here is how it will use
Usage: dotnet outdated [options] <Path>
Arguments:
Path The path to a .sln, .csproj or .fsproj file, or to a directory containing a .NET Core solution/project. If none is specified, the current directory will be used.
Options:
--version Show version information
-?|-h|--help Show help information
-i|--include-auto-references Specifies whether to include auto-referenced packages.
-pre|--pre-release <PRERELEASE> Specifies whether to look for pre-release versions of packages. Possible values: Auto (default), Always or Never.
-vl|--version-lock <VERSION_LOCK> Specifies whether the package should be locked to the current Major or Minor version. Possible values: None (default), Major or Minor.
-t|--transitive Specifies whether it should detect transitive dependencies.
-td|--transitive-depth <TRANSITIVE_DEPTH> Defines how many levels deep transitive dependencies should be analyzed. Integer value (default = 1)
-u|--upgrade[:<TYPE>] Specifies whether outdated packages should be upgraded. Possible values for <TYPE> is Auto (default) or Prompt.
-f|--fail-on-updates Specifies whether it should return a non-zero exit code when updates are found.
-inc|--include <FILTER_INCLUDE> Specifies to only look at packages where the name contains the provided string. Culture and case insensitive. If provided multiple times, a single match is enough to include a package.
-exc|--exclude <FILTER_EXCLUDE> Specifies to only look at packages where the name does not contain the provided string. Culture and case insensitive. If provided multiple times, a single match is enough to exclude a package.
-o|--output <OUTPUT_FILENAME> Specifies the filename for a generated report. (Use the -of|--output-format option to specify the format. JSON by default.)
-of|--output-format <OUTPUT_FILE_FORMAT> Specifies the output format for the generated report. Possible values: json (default) or csv.
-ot|--older-than <NUMBER_OF_DAYS> Only include package versions that are older than the specified number of days.
Check this link which will give you complete information about dotnet outdated packages.

What is the difference between various MSBuild version properties, such as Version, VersionPrefix, and VersionSuffix?

Building projects with MSBuild 15 and Microsoft.NET.Sdk allows users to specify half a dozen version properties. What is the difference between each of these and what is the right way to use them?
Version
VersionPrefix
VersionSuffix
AssemblyVersion
FileVersion
PackageVersion
And to be clear, I'm talking about "properties" as MSBuild properties that are defined in the file (as below)
<PropertyGroup>
<Version>1.2.0</Version>
</PropertyGroup>
...or on command line as msbuild.exe /p:Version=1.2.0
Also, setting these values explicitly will override the defaults.
VersionPrefix
Format: major.minor.patch
Examples: 14.2.4, 0.1.0, 99.99.99
Meaning: The normal part of the semver version number. This is used to determine the beginning of the Version value.
Default: "1.0.0"
VersionSuffix
Format: [0-9A-Za-z-.]* (arbitrary string)
Examples: alpha, beta, build0123, rc4-build201701, rc.1, rc-1
Meaning: The pre-release label of the version number. Used to determine the ending of a Version value.
Default: (empty)
Version
Format: major.minor.patch[-prerelease]
Examples: 5.3.9-beta, 0.0.1-alpha-01, 0.0.1-alpha.1, 2.0.0
Meaning: This property is the most commonly used property in user projects. Other version properties look to this value as a default. It is also used to generate the value of System.Reflection.AssemblyInformationalVersionAttribute. The preprelease value is optional.
Default: VersionPrefix if VersionSuffix is empty. VersionPrefix-VersionSuffix if VersionSuffix is not empty.
Note: setting Version explicitly will override any VersionPrefix or VersionSuffix settings.
Also, this typically follows SemVer rules. See http://semver.org/ for details
PackageVersion
Format: major.minor.patch[-prerelease]
Meaning: Used to generate the package version when producing a NuGet package from an MSBuild project.
Default: matches Version
AssemblyVersion
Format: major.minor.patch.revision
Examples: 4.5.6.2, 1.0.0.0
Meaning: Used to generate the value of System.Reflection.AssemblyVersionAttribute. The compiler uses this to determine the final AssemblyVersion value, an essential part of assembly identity. See https://msdn.microsoft.com/en-us/library/51ket42z(v=vs.110).aspx#Anchor_0
Default: matches Version without the prerelease label.
FileVersion
Format major.minor.patch.buildnumber
Examples: 1.0.0.43952, 0.1.0.0
Meaning: Used to generate the value of System.Reflection.AssemblyFileVersionAttribute. This is not required to match AssemblyVersion. It is common to add a build number to this version.
Default: matches AssemblyVersion
InformationalVersion
Format: any
Meaning: Used to generate the value of System.Reflection.AssemblyInformationalVersionAttribute. This attribute can contain any additional version information.
Default: matches Version
I would like to expand on the answer which was already given above to Visual Studio. If you got here because you were wondering how this all works in Visual Studio 2022 (and earlier), this is a short explanation as I could not find any official docs on the matter.
If you create a .net core Console app, and go to Project Properties, you will see a section "Package --> General" that covers versioning. It is populated with default values which are shown beneath each element.
Here is a screenshot of one of the elements with it's default value. So what is "$(VersionPrefix)"? As discussed above, it is one of the properties that can be set. But note there is no place in the UI to set this, but you can set it directly in the project file by editing it.
So let's do that now:
After saving the file, you now see the following:
But that's not really very useful for a version number. So lets add a Suffix to the project file.
<VersionSuffix>5-beta</VersionSuffix>
But now the version looks like this:
But that's not really what we want, so lets add a version number to the center:
And this give us this in the file explorer:
So, to recap: The UI is just writing to the Project File. No magic there. But how does it get consumed from the project file? Well, actually, there is a file being created in the background called .AssemblyInfo.cs. It looks like this:
[assembly: System.Reflection.AssemblyCompanyAttribute("ConsoleApp2")]
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
[assembly: System.Reflection.AssemblyFileVersionAttribute("2.3.5.0")]
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("2.3.5-beta")]
[assembly: System.Reflection.AssemblyProductAttribute("ConsoleApp2")]
[assembly: System.Reflection.AssemblyTitleAttribute("ConsoleApp2")]
[assembly: System.Reflection.AssemblyVersionAttribute("2.3.5.0")]
And that file is being consumed by the compiler when the project is compiled.
If you wanted to, you could skip all of the UI and project files, and just create the AssemblyInfoFile directly. But when you do that, you lose the VersionPrefix and VersionSuffix functionality and you have to do it manually.

Asp.Net 5 Semantic Versioning

It seems that versioning works differently than in previous versions of .Net. The project.json seems to use semantic versioning (from what I have seen online) with the format Major.Minor.Patch-Special.
Does this replace the Assembly version idea or add to it? Or does it just get used with Nuget.
How does one access the version during runtime. I came across Nuget.SemanticVersion object online in the Microsoft.Framework.Runtime package but I can't find out how to retrieve it in code.
Is there a programmatic way to update this value on a build or just custom scripts?
I wouldn't say that versioning has changed in a particularly dramatic way. In a version number x.y.z, the "x" means "big changes / breaking changes," the "y" means "minor additions and fixes," and the "z" means "very minor fixes." That's pretty close to what Semantic Versioning (SemVer) states.
In a project.json-based project, there is only one place to specify the version, and that's in the project.json file itself. That one version is a SemVer (e.g. x.y.z-prerel) and is used for the NuGet package version and the assembly version, and the assembly informational version. If you've explicitly set the assembly version or informational version in the assembly, those will be respected and not overridden. (You can see the code here.)
At runtime you can read the assembly version through reflection (just like you always could).
When running in a DNX application there's also an ILibraryManager interface that you can use to inspect the running application. However, that's a fairly advanced scenario.
Lastly, in the project.json file you can hard-code the x.y.z part of the version, e.g. 1.2.3 but you can also specify a * for the pre-release specifier, e.g. 1.2.3-*. If you use * for the pre-release specifier, you can set an environment variable named DNX_BUILD_VERSION to specify the value of the *, e.g. beta1 or rc2-54289.
There are some feature requests logged to allow more flexibility in specifying the entire version number externally.

Adding properties to DLL after it's been built

I have a set of C# DLLs that have already been built--they've gone through the process of setting the version numbers in AssemblyInfo.cs, they've been formally built by our configuration management team, and they've been archived off where they belong so we don't lose the built DLLs.
Now I have to take a collection of these DLLs and package them up into a couple umbrellas, and these umbrellas can have different versions. For example:
Collection1 v1.0 Collection1 v1.1 Collection2 v1.0
---------------- ---------------- ----------------
MyDll1.dll v1.0 MyDll1.dll v1.0 MyDll1.dll v1.0
MyDll2.dll v1.1 MyDll2.dll v1.2 MyDll4.dll v1.0
MyDll3.dll v1.2 MyDll3.dll v1.2 MyDll5.dll v1.1
Looking through each DLL's properties, I already see its usual fields, including File version and Product version set to its respective version number.
What I would like to do is to capture the collection name and version number somewhere in order to show which collection it belonged to when it was packaged up. Again, the DLLs are already built, so I can't add anything to AssemblyInfo.cs now.
Ideally, this would be another property that shows up on the DLL's Details tab, and it would be something that I can inject into a DLL using some tool, but I'm not familiar with any Windows API calls that can add/modify these properties.
Keep in mind this is for internal releases of these DLLs so we can keep track of what we have installed ourselves during development; the ones that will be packaged and released "for real" would be the pristine ones formally built and won't have any properties added into them.
EDIT: Third-party tools will be difficult to use; if it doesn't come with Windows or Visual Studio, then it would be strongly preferred if it's something that can be written very quickly.
Thanks.
You can try ILMerge tool provided by Microsoft: http://research.microsoft.com/en-us/people/mbarnett/ilmerge.aspx
Just create a DLL containing all custom assembly-level attributes you want to merge. Then run ILMerge specifying MyDll.dll as a primary assembly and your DLL with custom attributes as a secondary one. Don't forget to specify /copyattrs flag.
Full ILMerge documentation can be found here: http://research.microsoft.com/en-us/people/mbarnett/ilmerge.doc
If your input assembly is signed, you also have an option to provide .snk file, so that your output assembly will be signed as well.
Another option is to use a combination of ILdasm/ILasm tools, which seem to be part of the SDK. But it requires a little bit more efforts because you need to modify IL code in between.

Categories