.netload-testingsystem.componentmodelassemblyversions

Could not load file or assembly System.ComponentModel.Annotations, Version=4.2.0.0


I realise this question has been asked, but I have tried all of the suggested solutions I can find.

I have a Load Testing project (with a .loadtest file and class that inherits from Microsoft.VisualStudio.TestTools.WebTesting.WebTest). It has to target the .Net Framework (version 4.6.1) as opposed to .Net Core.

It references a project that targets .Net Standard 2.0, and both the load project and the .Net Standard project have the System.ComponentModel.Annotations (version 4.5.0) Nuget packages added.

When I try to run the Load Test itself, I receive the following exception:

System.IO.FileNotFoundException
  Message=Could not load file or assembly 'System.ComponentModel.Annotations, Version=4.2.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or one of its dependencies. The system cannot find the file specified.

I have tried adding an app.config file to the Load Test project with a binding redirect in, but it made no difference to the exception.

I can't move down to version 4.4.1 of the NuGet package, because other projects elsewhere depend on it being version 4.5.

I have read that there is a problem with the versioning in this package. And indeed when I inspect the dependencies of the built .Net Standard project dll, it seems to target not the 4.5.0 as specified, but version 4.2.0.0.

enter image description here

Now I am able to force the project to the proper version (which appears to be 4.2.1.0) by removing the NuGet package reference and adding a manual reference to the dll in the Packages folder, but then another project down the chain refuses to accept the hintPath I give it, and defaults to a different location and version:

enter image description here

So I can't force all projects I need to to use the actual version and location of the dll that I want.

Just wondering if anyone can suggest any course of action that might help here, as I'm at a bit of a loss as to how to force the whole thing to use the proper version. Either via binding redirects, or getting all projects to accept the paths to dlls that I'm giving them.


Solution

  • For anyone coming across this in the future, I did end up solving this via binding redirect in the end. A re-read of the github thread I linked to made me realise that there isn't actually technically a problem with the version numbers in the package, and that binding redirect was the "correct" solution.

    So the actual problem I was having was that the Microsoft Load Testing framework doesn't load any app.config you add to the project, and instead uses a QTAgent_40.exe.Config file somewhere in the Program Files folder. So I had to resolve assemblies manually upon Load Test initialisation. This blog has the code to do it: http://macmillan.scot/post/visual-studio-web--load-tests-can%E2%80%99t-access-appconfig

    But I modified the code a bit to include version checking:

    public static void Resolve()
    {
        LoadConfig();
        AppDomain.CurrentDomain.AssemblyResolve +=  delegate (object sender, ResolveEventArgs e)
        {
            var requestedName = new AssemblyName(e.Name);
    
            foreach (XmlNode assembly in assemblyBindingFromAppContext)
            {
                var assemblyIdentityNameNode = assembly.SelectSingleNode("./bindings:assemblyIdentity/@name", docNamepace);
                var bindingRedirectNewVersionNode = assembly.SelectSingleNode("./bindings:bindingRedirect/@newVersion", docNamepace);
    
                if (assemblyIdentityNameNode != null && bindingRedirectNewVersionNode != null)
                {
                    var assemblyName = assemblyIdentityNameNode.Value;
                    var specifiedVersion = bindingRedirectNewVersionNode.Value;
    
                    if (string.Equals(requestedName.Name, assemblyName, StringComparison.OrdinalIgnoreCase))
                    {
                        var resolvedAssembly = Assembly.LoadFrom(Invariant($"{assemblyName}.dll"));
                        var resolvedAssemblyVersion = resolvedAssembly.GetName().Version;
    
                        if (string.Equals(resolvedAssemblyVersion.ToString(), specifiedVersion, StringComparison.OrdinalIgnoreCase))
                        {
                            return resolvedAssembly;
                        }
                    }
                }
            }
    
            return null;
        };
    }
    
    private static void LoadConfig()
    {
        var configFileName = Path.Combine(Environment.CurrentDirectory, Invariant($"{Assembly.GetExecutingAssembly().ManifestModule.Name}.config"));
        var xmlDoc = new XmlDocument();
        xmlDoc.Load(configFileName);
    
        docNamepace = new XmlNamespaceManager(xmlDoc.NameTable);
        docNamepace.AddNamespace("bindings", "urn:schemas-microsoft-com:asm.v1");
    
        if (xmlDoc.DocumentElement != null)
        {
            assemblyBindingFromAppContext = xmlDoc.DocumentElement.SelectNodes("//bindings:dependentAssembly", docNamepace);
        }
    }