Can you share version information between .NET Standard libraries?
Asked Answered
A

2

8

In a typical .NET app, product and version information are stored in the AssemblyInfo.cs file under the 'Properties' folder, like so...

DLL Project
 - Properties Folder
    - AssemblyInfo.cs

In our case, we have a solution where we need to keep version information synced across eleven DLLs.

To accomplish this, we first removed any shared values from each project's AssemblyInfo.cs file, leaving only those values specific to that particular project.

We then placed all of the shared values in a second file called AssemblyInfo_Shared.cs which we store in a sibling folder to those of the projects. We then add that file to each project's 'Properties' folder via a link (that's the little 'down' arrow on the button when you're adding it.)

By doing this, all related DLLs share the same version information while still retaining assembly-specific properties as well. It makes keeping a set of versioned DLLs in sync a piece of cake as we edit a single file and all eleven DLLs' versions update at once.

Here's what it looks like...

Common Folder
  - AssemblyInfo_Shared.cs (Actual)

DLL Project A
 - Properties Folder
    - AssemblyInfo.cs // Only values specific to A
    - AssemblyInfo_Shared.cs (Link)

DLL Project B
 - Properties Folder
    - AssemblyInfo.cs // Only values specific to B
    - AssemblyInfo_Shared.cs (Link)

The contents of AssemblyInfo.cs in Project A looks like this...

using System.Reflection;

[assembly: AssemblyTitle("SomeApp.LibA")]
[assembly: AssemblyDescription("This is the code for  A")]

This is project B's

using System.Reflection;

[assembly: AssemblyTitle("SomeApp.LibB")]
[assembly: AssemblyDescription("This is the code for Project B")]

And here's the shared...

using System;
using System.Reflection;
using System.Resources;
using System.Runtime.InteropServices;

[assembly: AssemblyProduct("SomeApp")]
[assembly: AssemblyVersion("1.4.3.0")]
[assembly: AssemblyFileVersion("1.4.3.0")]
[assembly: AssemblyCompany("MyCo")]
[assembly: AssemblyCopyright("Copyright (c) 2010-2018, MyCo")]
[assembly: ComVisible(false)]
[assembly: NeutralResourcesLanguage("en-US")]

[assembly: CLSCompliant(true)]

With the above, both DLLs share the same version information since the common file is 'merged' with the project-specific one when building. Hope this makes sense.

However, in .NET Standard projects, it looks like the version information is baked right into the Project file under the <PropertyGroup> section, so I'm not sure how we can achieve the same capability.

Does .NET Standard have anything that supports this?

Ambrosine answered 31/8, 2018 at 5:13 Comment(4)
Can you clarify exactly what you get from AssemblyInfo_Shared.cs? What does it look like? Does it for instance give you a list of the specific versions of components that project A and B should both use, is that it?Cia
It's just splitting up the normal AssemblyInfo.cs file. I'll add it above so you can see.Ambrosine
It is a notably bad practice to do this. These assemblies should have the same Product Version. Conveniently absent from the auto-generated code, use [assembly:AssemblyInformationalVersion("1.2.3.4")]Osber
These aren't auto-generated. I created them manually in my code. Also, don't focus on what's in the files themselves as listed here. I hand-edited them to get them in the question. They aren't complete by any means. The point of the question was about segregating the common information shared across all assemblies vs. the assembly-specific information, not what's actually in them.Ambrosine
A
12

Yes, you can ;o)

Add a folder named Properties to each project root and add the link to AssemblyInfo_Shared.cs.

After that you have to set in each .Net Standard/Core project configuration

<PropertyGroup>
  ...
  <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
</PropertyGroup>

You will find a complete Solution at https://github.com/SirRufo/SharedVersionTest

Arc answered 31/8, 2018 at 6:50 Comment(6)
@MarqueIV You want that all dll/exe files have the same version info, right? Well they have and it depends on a single file AssemblyInfo_Shared.csArc
Aaaah! I originally posted a comment saying this was referring to the old format and I wanted the newer, but I deleted it so I could go test. Now I see this can be used with the newer! I've already updated my existing new .NET Standard DLLs (which were older .NET Framework DLLs) using this very technique which is essentially the same as before. Perfect! Thanks!Ambrosine
@Rufo, I forgot to ask, can you please put a link to where you found this information? I looked and didn't see it, but obviously it's out there. Some of our attributes don't appear to be available/used in the .NET Standard versions, but I'd like to check the docs to be sure. Also, I'm temporarily unchecking this as the accepted answer based on what Lucas posted about the Directory.Props stuff. I want to see which is the official way forward, or if they're both still considered current. (Another reason for wanting the docs.) Once I get more info, I'll choose the one that fits best.Ambrosine
Digging around more, it looks like they are still both supported, as the GenerateAssemblyInfo just determines if AssemblyInfo.cs is automatically generated for you, ergo, of course it's still a supported way of doing things. That's the missing info from your answer. Mind adding it? (I only found it on a third-party blog.)Ambrosine
One other thing... it looks like the other way, since it's merged into the project file itself, helps when building packages for NuGet, which I don't believe the AssemblyInfo.cs way does, hence why they added the values to the new project format. Mind throwing that piece of info in here as well?... or at least referencing the other answer too?Ambrosine
@MarqueIV no need to duplicate info - the two answers are fine in isolation, they just solve the same problem in a different way.Millen
M
6

Sir Rufo's solution is perfectly fine, but here's another way, made possible by the new project format. This lets you customize automatic assembly generation.

You can put a Directory.Build.props file in a parent directory of your projects, and it will be automatically included. See the documentation:

However, now you can add a new property to every project in one step by defining it in a single file called Directory.Build.props in the root folder that contains your source. When MSBuild runs, Microsoft.Common.props searches your directory structure for the Directory.Build.props file (and Microsoft.Common.targets looks for Directory.Build.targets). If it finds one, it imports the property. Directory.Build.props is a user-defined file that provides customizations to projects under a directory.

So you can leverage that to add your assembly info:

<?xml version="1.0" encoding="utf-8"?>
<Project>
  <PropertyGroup>
    <Version>1.4.3.0</Version>
    <Product>SomeApp</Product>
    <Company>MyCo</Company>
    <Copyright>Copyright (c) 2010-2018, MyCo</Copyright>
  </PropertyGroup>
</Project>

There's probably no tag for the CLSCompliant attribute, but you'll have everything you need for the assembly info, and some other stuff. Here are the docs for NuGet-related properties, but unfortunately, right now the only "documentation" for assembly info properties is the source code here (until this issue is resolved, at least).

You can then override any property you want in each of your projects.

Millen answered 31/8, 2018 at 12:26 Comment(3)
Because of this, I've temporarily de-selected an answer here. Is this considered the proper way going forward, or is this just an additional way one can use? The thing I like about the other way is each project determines what extra files/props are included explicitly, but the thing I like about this is any project in the same folder implicitly gets the values. Pros and cons of each. But I want to make sure the other way isn't just 'legacy supported' and is still considered current.Ambrosine
Doing a little more digging, it seems the 'GenerateAssemblyInfo' attribute just automatically generates the 'AssemblyInfo.cs' file for you, meaning specifying it manually is still a perfectly acceptable way to do things. Still, I like this extra bit of auto-magic-sauce you've put here which also helps with NuGet package generation (which I don't think the other does.) Yet another case where I wish I could split the answer! :)Ambrosine
@MarqueIV both ways are supported, I think it's more or less a matter of preference. The NuGet thing is also separate to the assembly info, even though it can reuse some of the properties. I mentioned it for this reason. Also FYI you can override the properties defined in Directory.Build.props, I've added that to the anwser.Millen

© 2022 - 2024 — McMap. All rights reserved.