Retrieve Target Framework Version and Target Framework Profile from a .Net Assembly

12,940

Solution 1

If you would be satisfied with the version of the CLR that compiled the assembly, you can use the Assembly.ImageRuntimeVersion property. According to MSDN, that property:

representing the version of the common language runtime (CLR) saved in the file containing the manifest.

and

By default, ImageRuntimeVersion is set to the version of the CLR used to build the assembly. However, it might have been set to another value at compile time.

Of course, that doesn't give you the specific version of the .NET Framework (for example: .NET Frameworks 2, 3.0 and 3.5 are all on the 2.0 CLR).

If the CLR version isn't sufficient, you could to try to 'estimate' (guess intelligently) what version it must be based on the assemblies it references. For .NET 1 and 4, the CLR version should be enough. However, if the CLR version was 2.0, you wouldn't know if that meant 2.0, 3.0, or 3.5 so you could try some more logic. For example, if you saw that the Assembly referenced System.Core (using Assembly.GetReferencedAssemblies()) then you would know that the version is 3.5 since System.Core was new in 3.5. That's not exactly rock-solid since the assembly in question might not use any types from the Assembly so you wouldn't be able to catch that. To try to catch more cases, you could loop through all the referenced assemblies and check their version numbers - maybe filtering to just assemblies that start with System to avoid false positives with other libraries. If you see any System.* assemblies referenced that have a version of 3.5.x.x, then you can also be pretty sure it was built for 3.5.


As you've noticed, I don't believe the TargetFrameworkProfile escapes past Visual Studio. However, if there happens to be an app.config file for the application, Visual Studio may have put the target framework in there. For example, if you set project to use the 4.0 Client Profile, Visual Studio creates an app.config like this:

<?xml version="1.0"?>
<configuration>
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0,Profile=Client"/>
  </startup>
</configuration>

Solution 2

If the assembly was compiled with the TargetFrameworkAttribute (assembly scoped) you can easily and uniformly determine the framework profile target.

Try this example and reference your own custom assemblies with different targets.

class Program
{
    static void Main(string[] args)
    {


        // Lets examine all assemblies loaded into the current application domain.
        var assems = AppDomain.CurrentDomain.GetAssemblies();

        // The target framework attribute used when the assemby was compiled.
        var filteredType = typeof(TargetFrameworkAttribute);

        // Get all assemblies that have the TargetFrameworkAttribute applied.
        var assemblyMatches = assems.Select(x => new { Assembly = x, TargetAttribute = (TargetFrameworkAttribute)x.GetCustomAttribute(filteredType) })
                                    .Where(x => x.TargetAttribute != null);

        // Report assemblies framework target
        foreach (var assem in assemblyMatches)
        {
            var framework = new System.Runtime.Versioning.FrameworkName(assem.TargetAttribute.FrameworkName);
            Console.WriteLine("Assembly: '{0}' targets .NET version: '{1}'.",
                                assem.Assembly.FullName,
                                framework.Version);
        }

        Console.ReadLine();
    }
}

Solution 3

This should work!

-> Compile bin\net45\myapp.exe = ".NET Framework 4.5"

var asm = Assembly.GetExecutingAssembly();
var b = asm.CustomAttributes.FirstOrDefault(a => a.AttributeType == typeof(TargetFrameworkAttribute));
var strFramework = b.NamedArguments[0].TypedValue.Value;

Console.WriteLine(strFramework);
Share:
12,940
Scott
Author by

Scott

By Day: Head Developer nah, sounds too naff Lead Developer hmmm still a bit naff Senior Developer makes me sound old.... Ninja... I can't even finish that one with a straight face its so 2008. I'm some guy that's been at Redgum since pretty much the get-go, we write software that others have deemed to be too difficult and generally fix projects that have gone off the rails. By Night: I spend time with my family and there's a pretty good chance my kid really is cuter than yours.

Updated on June 12, 2022

Comments

  • Scott
    Scott about 2 years

    Is there any way that I can access the values that were used for TargetFrameworkVersion and/or TargetFrameworkProfile when a .Net assembly was compiled?

    The values I'm talking about are the ones contained the project file

    <?xml version="1.0" encoding="utf-8"?>
    <Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
      <PropertyGroup>
        <OtherStuff />
        <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
        <TargetFrameworkProfile>Client</TargetFrameworkProfile>
        <OtherStuff />
      </PropertyGroup>
      <OtherStuff>
      </OtherStuff>
    </Project>
    

    Basically I'd like to find out what the Target Version of the Framework was when the assembly was compiled and if possible the Target Framework Profile as well.

    And I'm not talking about the currently loaded version of the CLR, Environment.Version isn't what I'm after.

    Ideally the solution would use System.Reflection but if I have to resort to other methods I will.

    • Damien_The_Unbeliever
      Damien_The_Unbeliever almost 13 years
      I believe the TargetFrameworkProfile only affects which references Visual Studio will allow you to make from the project. I don't think anything gets compiled into the output assembly.
    • Scott
      Scott almost 13 years
      Damien I think you are correct. I don't see it listed as an available project level property that can be passed to MSBuild. If it's not going to MSBuild then it's certainly not going to be embedded in the Assembly. I can still live in hope that TargetFrameworkVersion is embedded in there somewhere though.
    • Mark Schultheiss
      Mark Schultheiss about 6 years
      public string TargetFrameworkProfile { get; set; } Microsoft.Build.Tasks
  • Kiquenet
    Kiquenet over 10 years
    I have R1.dll with Target Framework 4.5, and R2.dll with Target Framework 4.0. CLR 4.0 for both dll. then, I have P1.dll compiled with Target Framework 4.0. Can P1.dll references R1.dll in execution time ?
  • Stephen McDaniel
    Stephen McDaniel over 10 years
    @Kiquenet This seems like a somewhat unrelated question. You might want to check out other questions that are more closely related to your question. For example: Is it possible to reference an assembly that targets .net 4.5 in a project that targets 4.0? or Upgrade to .Net 4.5 causes assembly to fail?
  • Scott
    Scott about 10 years
    Thanks Stephen McDaniel - I was hoping someone would come along with a better answer but I don't think that's going to happen. It seems that the correct answer is "No", but I'll accept your answer as it contains some useful info anyway.
  • Ivaylo Slavov
    Ivaylo Slavov about 9 years
    Very interesting answer. I am surprised to find it that the supported .NET runtime is so obscure to find from an assembly, still good work with the "guess intelligently" approach. Do you have any idea, or reference to point me to, on how Mono handles this? I know the version of mono is irrelevant to the supported .NET runtime a mono-compiled assembly may support. Still I wonder, would your trick work in the same way for assemblies compiled with mono?
  • Stephen McDaniel
    Stephen McDaniel about 9 years
    @IvayloSlavov I would expect my guessing logic to work even in the context of mono. I took a look at a random class that I know only exists in .net 3.5 (System.Linq.Enumerable) and the mono version of that is also declared in the System.Core.dll file. I would expect most types to be that way as well. But probably the best way to know for sure would be to test it out and see. :-)
  • Alexei - check Codidact
    Alexei - check Codidact almost 3 years
    For a .NET 5 assemblies I could get a meaningful target version by using b?.ConstructorArguments[0].Value instead of b.NamedArguments[0].TypedValue.Value.