12

I want to get the value of the element <Location>SourceFiles/ConnectionStrings.json</Location> that is child of <PropertyGroup /> using C#. This is located at the .csproj file for a .NET Core 2 classlib project. The structure is as follow:

<PropertyGroup>
  <TargetFramework>netcoreapp2.0</TargetFramework>
  <Location>SharedSettingsProvider.SourceFiles/ConnectionStrings.json</Location>
</PropertyGroup>

Which class can I use from .NET Core libraries to achieve this? (not .NET framework)

Update 1: I want to read the value when the application (that this .csproj file builds) runs. Both before and after deployment.

Thanks

walter_dl
  • 309
  • 1
  • 3
  • 11
  • 1
    Can you clarify what you want to do? Do you want to read the value when your application (that this csproj file builds) is run (possibly after deploying to server)? Or do you have a separate application that needs to read the value from this csproj file? What exactly do you want to do? – omajid Mar 27 '18 at 22:40
  • @omajid The update 1 clarify what I want. Thanks – walter_dl Mar 27 '18 at 22:59
  • 1
    Oh. I am afraid this is not possible. A csproj file is used for building and isn't present at runtime. So you can't read values from it. You could write out a config file during build (that config file would contain the variable/value) and put that config file next to the application where your application can find it at runtime. – omajid Mar 27 '18 at 23:03

1 Answers1

23

As has been discussed in comments, csproj content only controls predefined build tasks and aren't available at run-time.

But msbuild is flexible and other methods could be used to persist some values to be available at run time.

One possible approach is to create a custom assembly attribute:

[System.AttributeUsage(System.AttributeTargets.Assembly, Inherited = false, AllowMultiple = false)]
sealed class ConfigurationLocationAttribute : System.Attribute
{
    public string ConfigurationLocation { get; }
    public ConfigurationLocationAttribute(string configurationLocation)
    {
        this.ConfigurationLocation = configurationLocation;
    }
}

which can then be used in the auto-generated assembly attributes from inside the csproj file:

<PropertyGroup>
  <ConfigurationLocation>https://my-config.service/customer2.json</ConfigurationLocation>
</PropertyGroup>
<ItemGroup>
  <AssemblyAttribute Include="An.Example.ConfigurationLocationAttribute">
    <_Parameter1>"$(ConfigurationLocation)"</_Parameter1>
  </AssemblyAttribute>
</ItemGroup>

And then used at run time in code:

static void Main(string[] args)
{
    var configurationLocation = Assembly.GetEntryAssembly()
        .GetCustomAttribute<ConfigurationLocationAttribute>()
        .ConfigurationLocation;
    Console.WriteLine($"Should get config from {configurationLocation}");
}
Martin Ullrich
  • 94,744
  • 25
  • 252
  • 217
  • 1
    Just a heads up for the next person: GetEntryAssembly() might be different from the executing assembly... – JohnTortugo Aug 10 '18 at 17:02
  • 1
    I can't access the type `ConfigurationLocationAttribute` using this example. If I use a `Compile` tag in the .csproj file then it compiles but doesn't work at runtime. If I use the `AssemblyAttribute` tag as shown here I don't have access to the type and the project doesn't compile (your Main method won't compile for me). – Dan Rayson Apr 29 '19 at 12:35
  • 1
    @DanRayson can you provide a complete example? maybe create a new question? the only thing not completely explained here is to replace `An.Example.` with the namespace used by the app. Also it doesn't work when assembly info generation is deactivated for the project (but then it should compile but fail at runtime) – Martin Ullrich Apr 29 '19 at 20:16
  • @MartinUllrich It turns out this was my mistake - I was passing the parameters via Visual Studio (which doesn't actually let you do it, hence my error), as soon as I started using `msbuild` directly in the Command Prompt, it worked perfectly. Apologies for wasting time. Bit annoying that I can't change my vote :/ – Dan Rayson May 01 '19 at 12:38
  • For folks looking into doing this sort of thing in .Net Framework, [you have to add a couple more bits to the csproj file to make it work](https://stackoverflow.com/a/4306142/1946412), otherwise the attributes are not written at all. – julealgon Jul 02 '19 at 12:56
  • btw i suggest github.com/dasMulli/AssemblyInfoGenerationSdk for framework projects (you may need to set a few properties to disable some attribute generation if you want to keep your assemblyinfo.cs – Martin Ullrich Jul 02 '19 at 13:00
  • We managed to make it work, setting as @MartinUllrich purposes: `` – TrustworthySystems Jan 06 '21 at 05:29
  • To clarify on the comments by julealgon and martin-ullrich : The way proposed by the answer works regardless of the TFM (i. e. also for .NET Framework) as long as you are using an SDK-style project. You may have to do it differently for Non-SDK-style projects, as historically had to be used for .NET Framework projects before SDK-style projects started supporting .NET Framework TFMs (around 2019 I guess). – svenhuebner Sep 21 '22 at 04:10