Saving Values ​​in a .Net Application at the Build Stage

There was a need for me when building the application to pass in a set of constants for use on runtime. For example, we want to "sew" into the application some string value that will be known at the time of assembly.

In the C ++ world, I solved such things very simply using define and compiler options. But in .Net define do not have values ​​other than true / false, i.e. they are either identified or not. As far as I understand, their goal is the simplest conditional compilation.

Who cares about the solution, welcome to cat.

The first thought that visited me was to generate a file with constants by template in front of the build, but I would like to do without involving heavy artillery of template engines.

After some searching, I discovered an interesting fact. .Net has an attribute mechanism. These attributes can cling to classes, methods, fields, and all sorts of different entities. It turned out that it can be hooked to the entire assembly.

In project files (.csproj), it is possible to set values ​​for these attributes during assembly. And in MSBuild, you can pass parameters from the outside through the mechanism of properties. It seems that everything fits, you have to try.

Create a new console application:

% mkdir Example && cd Example
% dotnet new console

We create the file ExampleAttribute.cs with the definition of our attribute.

using System;

namespace Example
{

[AttributeUsage(AttributeTargets.Assembly)] //     
public class ExampleAttribute : Attribute
{
    public string Value { get; set; }

    public ExampleAttribute(string value)
    {
        Value = value;
    }
}
 
}

Next, the Example.csproj file is reduced to the following form. I added comments so that the essence of the changes was clear.

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>netcoreapp3.1</TargetFramework>
    <RootNamespace>Example</RootNamespace>

    <ExampleValue>default</ExampleValue> <!--        -->
  </PropertyGroup>

  <!--          -->
  <ItemGroup>
    <AssemblyAttribute Include="Example.ExampleAttribute"> <!--    -->
      <_Parameter1>$(ExampleValue)</_Parameter1> <!--      -->
    </AssemblyAttribute>
  </ItemGroup>

</Project>

Well, actually, getting the value on runtime in Project.cs

using System;
using System.Reflection;

namespace Example
{
    class Program
    {
        static void Main(string[] args)
        {
            var assembly = Assembly.GetExecutingAssembly();
            var attr = (ExampleAttribute) assembly.GetCustomAttribute(typeof(ExampleAttribute));
            Console.WriteLine($"Assembly attribute value = '{attr.Value}'");
        }
    }
}

So, we will assemble and run in order to see what we have got.

% dotnet build .
% dotnet run --no-build .
Assembly attribute value = 'default'

And now with the parameter:

% dotnet build . /p:ExampleValue="NOT DEFAULT"
% dotnet run --no-build .
Assembly attribute value = 'NOT DEFAULT'

Voila, the goal has been achieved. Use on health.

All Articles