How can I programatically get the version of a NuGet package being used in the solution?
Asked Answered
M

6

19

I'm working on a project, and we need to know the version of a NuGet package we are using, and use it in the code.

One way I tried was to read from the packages.config file, parse it for the package I want, and parse the line for the version. Something like:

var lines = System.IO.File.ReadAllLines(@"..\..\packages.config");
foreach(var line in lines)
{
    if (line.Contains("My.Package"))
    {
         foreach(var part in line.split(' '))
         {
             if (part.Contains("version"))
             {
                 return part.Split('"')[1];
             }
         }
    }
}

Is there a better way to do this programmatically?

Note: The above code will not work, as packages.config is not deployed with the application.

Mickiemickle answered 13/1, 2016 at 19:47 Comment(6)
Reading it as XML would probably make more sense. At which point in time do you need to know the package version? You could probably determine it from the compiled assembly version as well.Outward
Not sure exactly what you mean by "at which point in time", but I'd like to grab the version during runtime, to use elsewhere in the code.Mickiemickle
Do you include packages.config when you deploy your app?Benco
@AleksandrIvanov No we don't, so unfortunately this will not work.Mickiemickle
Related: How can I get the NuGet package version programmatically from a NuGet feed?Ivetteivetts
You still did not select your answer, heh?Raptor
C
13

If the package has any classes you can just get the assembly from that class and then the version. However, if the package has no classes, e.g. does something like copying files using nuget.targets then it's impossible this way.

Console.WriteLine("Using Selenium.WebDriver: " + Assembly.GetAssembly(typeof(OpenQA.Selenium.By)).GetName().Version.ToString());
Cambogia answered 23/7, 2019 at 5:37 Comment(2)
Note: this only gets the major version. E.g Serilog 2.4.0 -> 2.0.0.0Mclean
Even more general approach, just drop this anywhere in a method (also works with static methods): string applicationVersion = Assembly.GetAssembly(MethodBase.GetCurrentMethod().DeclaringType).GetName().Version.ToString(); be sure to add at the top using System.Reflection namespace.Grimbly
I
2

You can read the version from the assembly:

string assemblyVersion = Assembly.LoadFile('your assembly file').GetName().Version.ToString();
Icebreaker answered 13/1, 2016 at 19:49 Comment(0)
G
2

You can configure your project to record the data at compile time. Here is an MSBuild snippet that generates an assembly attribute called MyNamespace.MSBuildVersionAttribute with a single constructor argument.

<Target Name="ExtractMSBuildVersion" BeforeTargets="BeforeBuild">
    <ItemGroup>
        <MSBuildPackageVersion Include="@(PackageReference->'%(Version)')" Condition="'%(Identity)' == 'Microsoft.Build'" />
        <AssemblyAttributes Include="MyNamespace.MSBuildVersionAttribute">
            <_Parameter1>@(MSBuildPackageVersion)</_Parameter1>
        </AssemblyAttributes>
    </ItemGroup>
        
    <WriteCodeFragment AssemblyAttributes="@(AssemblyAttributes)" Language="C#" OutputDirectory="$(IntermediateOutputPath)" OutputFile="MSBuildVersion.cs">
        <Output TaskParameter="OutputFile" ItemName="Compile" />
        <Output TaskParameter="OutputFile" ItemName="FileWrites" />
    </WriteCodeFragment>
</Target>

You can now access that attribute at runtime.

Gillette answered 24/1, 2023 at 10:22 Comment(1)
interesting concept but, the package comes with multiple versions of the DLL. Moreover, if you have a component (your own DLL) that used a package DLL v1 and then you have an endpoint like a Console app or Web API, which uses v2 of that DLL. Now, you have 2 different attributes. Or if you have v1 in the endpoint and v2 in the component and then you use Binding redirect. So, you write v1 into the attribute but at runtime use v2. This are the reasons why using package versions is a unholy proposition And to know assembly used one can make query for file and assembly version and also PIRaptor
E
2

Use AssemblyInformationalVersionAttribute.InformationalVersion. e.g.:

const string NewtonsoftNuGetId = "Newtonsoft.Json";
// JsonConvert is a class in Newtonsoft.Json
// https://www.newtonsoft.com/json/help/html/t_newtonsoft_json_jsonconvert.htm
var newtonSoftInformationalVersion = typeof(Newtonsoft.Json.JsonConvert).Assembly
    .GetCustomAttribute<AssemblyInformationalVersionAttribute>().InformationalVersion;
var newtonsoftVersion = newtonSoftInformationalVersion.Substring(0, newtonSoftInformationalVersion.IndexOf("+")); // 13.0.2
Enthymeme answered 2/3, 2023 at 21:54 Comment(0)
S
0

I created a project and it is also available on NuGet: NuGetVersionChecker.

GitHub: https://github.com/meokullu/NuGetVersionChecker

NuGet: https://www.nuget.org/packages/NuGetVersionChecker/

GetPackages([Your .csproj file path]);

returns List of Package which you see Package Name, Semantic Version and UpdateAvailable data.

GetPackages(string path) method basically parse .csproj file with XmlDocument.Load() and list all packages you used.

Sakhuja answered 28/6, 2024 at 10:48 Comment(0)
R
-1

This is still active and controversial after 8 years so the

BIG UPDATE

To know your package you need to read the packages from your project file. It could be a packages.config setup or package references. You shouldn't read from packages.config because this file is often out of sync. You should read Hint and PackageReference tags in the project file. And if your solution has multiple projects? One way - use Pre Build Event and a tool that you can write using PowerShell. Your input will be the project file, in which you can find tags, and then parse the digits out of them. Then you create an output - a file where you write a class and in that class a dictionary with package name and version. In fact, you can make a list and not parse the version out of the name. You can also have a template saved and only replace and re-save the part. so, save the template in the project like

using System;
using System.Collections.Generic;
namespace Packages.Versions
{
    public class PackageCollection
    {

        public PackageCollection ()
        {
            Packages = new List<string>();
            //PLACEHOLDER
        }
        public List<string> Packages { get; }
    }
} 

And in the PowerShell you compose a string like

"Packages.Add(\"MyPackage.Name.123.0.0\"); 
Packages.Add(\"MyPackage2.Name.987.0.0\");
Packages.Add(\"MyPackage3.Name.567.0.0\");"

And then you plug this into the //PLACEHOLDER and overwrite the file.

This will give you more precise result of what your project(s) use but not the dependencies of the packages themselves.

However!! The packages that are referenced at the design/compile time do not guarantee that these are the same ones used at runtime (and I am talking about DLLs in the packages). Different projects in your solution can reference different versions of the same package and only 1 version will be used (usually, because it is possible to have multiple versions.)

This is why I said below that answer to "how to collect package version" can actually mislead the whole operation. Because you might want to get Assembly Version and File Version rather than package version. These you can get reliably. And I have the links below.

END big update

Original answer below

Good question. But you have not said why you want to know the version.

I have to start my answer from pointing that you're on the wrong path. I suspect that you need to know at runtime the version of assembly in use.

But the whole NuGet concept and packages.config is a compile-time concept and not a runtime concept. You shouldn't even have packages.config in your output folder or published folder. At runtime you need to get loaded assemblies from AppDomain.CurrentDomain. I will not go in depth on it here, but here is the reference you can look at. I only say that you can get assembly version there.

Then, in code, if you want to do things differently based on certain assembly version. If you want to compile based on version of framework or assembly - check this post

Bottom Line:

The fact that packages.config exist or not, or what it has in it, has no correlation to which DLL file has been used at compile time. VS has an incredible ability to crawl through directories and finding matching DLL files. packages.config can be outdated or desynchronized with the actual dll. This is not a bullet-proof way to do things.

Raptor answered 14/1, 2016 at 1:1 Comment(4)
The reason isn't important. This is a specific question that other people are searching for on the internet and a direct answer is the most helpful.Cirone
@WarrenParks Reason (or, what in programming we call motivation) is super important; because most of the time there is an easy solution for a problem that is posted here. Only people go into wrong direction from the beginning. Let me tell you something about this question - the fact that packages.config exist or not, has no correlation to which dll has been used at compile time. packages.config can be outdated or desynchronized with actual dll. This is not bullet-proof way to do things and hence my answer. I am ok if you feel differently. Enjoy.Raptor
AGAIN, there is no guarantee that assembly used at runtime is the same version as was used at compile time. This is why reflection needed to get assembly version. How you get it - is a different question.Raptor
Looks like people still don't understand that when you go to your assembly at runtime AppDomain.CurrentDomain.GetAssemblies() this is what is executing at runtime. OP's question was however about NuGet packages version. The nuget package version is not a file version or assembly version. While building multi-project solutions, the DLLs can overwrite each other. And based on target framework a different DLL can be taken from different folders in the same nuget package. People use DependencyRedirect controls to deal with these differences.Raptor

© 2022 - 2025 — McMap. All rights reserved.