Benjol
Benjol

Reputation: 66551

TypeLoadException says 'no implementation', but it is implemented

I've got a very weird bug on our test machine. The error is:

System.TypeLoadException: Method 'SetShort' in type 'DummyItem' from assembly 'ActiveViewers (...)' does not have an implementation.

I just can't understand why. SetShort is there in the DummyItem class, and I've even recompiled a version with writes to the event log just to make sure that it's not a deployment/versioning issue. The weird thing is that the calling code doesn't even call the SetShort method.

Upvotes: 311

Views: 158506

Answers (30)

Amir Hajiha
Amir Hajiha

Reputation: 935

In my case, using different versions of Microsoft.Extensions.AI package across different projects was the issue so all I had to do was to make sure that all nuget packages across different packages are on the same version.

Upvotes: 0

Benjol
Benjol

Reputation: 66551

NOTE - If this answer doesn't help you, please take the time to scroll down through the other answers that people have added since.

Really short answer

Delete all your bin and obj directories and rebuild everything. The versions of the dlls don't match.

Short answer

This can happen if you add a method to an interface in one assembly, and then to an implementing class in another assembly, but you rebuild the implementing assembly without referencing the new version of the interface assembly.

In this case, DummyItem implements an interface from another assembly. The SetShort method was recently added to both the interface and the DummyItem - but the assembly containing DummyItem was rebuilt referencing the previous version of the interface assembly. So the SetShort method is effectively there, but without the magic sauce linking it to the equivalent method in the interface.

Long answer

If you want to try reproducing this, try the following:

  1. Create a class library project: InterfaceDef, add just one class, and build:

     public interface IInterface
     {
         string GetString(string key);
         //short GetShort(string key);
     }
    
  2. Create a second class library project: Implementation (with separate solution), copy InterfaceDef.dll into project directory and add as file reference, add just one class, and build:

     public class ImplementingClass : IInterface
     {
         #region IInterface Members
         public string GetString(string key)
         {
             return "hello world";
         }
    
         //public short GetShort(string key)
         //{
         //    return 1;
         //}
         #endregion
     }
    
  3. Create a third, console project: ClientCode, copy the two dlls into the project directory, add file references, and add the following code into the Main method:

      IInterface test = new ImplementingClass();
      string s = test.GetString("dummykey");
      Console.WriteLine(s);
      Console.ReadKey();
    
  4. Run the code once, the console says "hello world"

  5. Uncomment the code in the two dll projects and rebuild - copy the two dlls back into the ClientCode project, rebuild and try running again. TypeLoadException occurs when trying to instantiate the ImplementingClass.

Upvotes: 284

zeocrash
zeocrash

Reputation: 665

We had the same issue. It turned out to be a version mismatch between a library referenced by our console app and the library referenced by our data access library.

I realise answers similar to this have been posted before but feel the addition of pictures should really help.

When you reference a class library, you think of the references as a hierarchical tree. App A references Library B, which in turn references library C (see picture below).

How you imagine references

In reality however it's more tangled than that (at least in .net Framework). Your app must not only reference the class library it uses but also all the dependencies of that class library. App A references Library B and Library C. Library B references Library C

How it actually is

The problem arises when Library B references a different version of Library C to the version of Library C that App A references

This doesn't work

If you look at your method signature you'll find a type that's from library C. That should tell you which library to check the version of.

Upvotes: 2

SalientBrain
SalientBrain

Reputation: 2541

I got this issue when I tried to implement plugin assembly loading in dot net 5 using custom AssemblyLoadContext (without AppDomain creation) and shared type (interface which you need to use to call plugin methods without reflection). Nothing from this thread helped me. Here is what I did to solve this issue:

  1. To allow debugging of plugin loading without a problems - setup project output path to host app bin folder. You will debug the same assembly you got after plugin project build. This is, probably, temporary change (just for debug).
  2. To fix TypeLoadException you need to load all 'contract assembly' referenced assemblies as shared assemblies (except runtime assemblies). Check loader context implementation (loading sharedAssemblies in constructor):

    public class PluginAssemblyLoadContext : AssemblyLoadContext
    {
        private AssemblyDependencyResolver _resolver;
        
        private IDictionary<string, Assembly> _loadedAssemblies;
        
        private IDictionary<string, Assembly> _sharedAssemblies;

        private AssemblyLoadContext DefaultAlc;

        private string _path;

        public PluginAssemblyLoadContext(string path, bool isCollectible, params Type[] sharedTypes)
             : this(path, isCollectible, sharedTypes.Select(t => t.Assembly).ToArray())
        {
        }

        public PluginAssemblyLoadContext(string path, bool isCollectible, params Assembly[] sharedAssemblies)
             : base(isCollectible: isCollectible)
        {

            _path = path;

            DefaultAlc = GetLoadContext(Assembly.GetExecutingAssembly()) ?? Default;

            var fileInfo = new FileInfo(_path);
            if (fileInfo.Exists)
            {
                _resolver = new AssemblyDependencyResolver(_path);

                _sharedAssemblies = new Dictionary<string, Assembly>(StringComparer.OrdinalIgnoreCase);
                foreach (var a in sharedAssemblies.Distinct())
                {
                    LoadReferencedAssemblies(a);
                }

                _loadedAssemblies = new Dictionary<string, Assembly>();

                var assembly = LoadFromAssemblyPath(fileInfo.FullName);

                _loadedAssemblies.Add(fileInfo.FullName, assembly);
            }
            else
            {
                throw new FileNotFoundException($"File does not exist: {_path}");
            }
        }

        public bool LoadReferencedAssemblies(Assembly assembly)
        {
            if (assembly == null)
            {
                throw new ArgumentNullException(nameof(assembly));
            }
            if (string.IsNullOrEmpty(assembly.Location))
            {
                throw new NotSupportedException($"Assembly location is empty string or null: {assembly.FullName}");
            }
            var alc = GetLoadContext(assembly);
            if (alc == this)
            {
                throw new InvalidOperationException($"Circular assembly loader dependency detected");
            }
            if (!_sharedAssemblies.ContainsKey(assembly.Location))
            {
                _sharedAssemblies.Add(assembly.Location, assembly);

                foreach (var an in assembly.GetReferencedAssemblies())
                {
                    var ra = alc.LoadFromAssemblyName(an);
                    LoadReferencedAssemblies(ra);
                }
                return true;
            }
            else
            {
                return false;
            }
        }

        public IEnumerable<Type> GetCommandTypes<T>()
        {
            var cmdType = typeof(T);
            return _loadedAssemblies.Values.SelectMany(a => a.GetTypes()).Where(t => cmdType.IsAssignableFrom(t));
        }

        public IEnumerable<T> CreateCommands<T>(Assembly assembly)
        {
            foreach (var cmdType in GetCommandTypes<T>())
            {
                yield return (T)Activator.CreateInstance(cmdType);
            }
        }

        protected override Assembly Load(AssemblyName assemblyName)
        {
            var path = _resolver.ResolveAssemblyToPath(assemblyName);
            if (path != null)
            {
                if (_sharedAssemblies.ContainsKey(path))
                {
                    return _sharedAssemblies[path];
                }
                if (_loadedAssemblies.ContainsKey(path))
                {
                    return _loadedAssemblies[path];
                }
                return LoadFromAssemblyPath(path);
            }     
            return DefaultAlc.LoadFromAssemblyName(assemblyName);
        }
    }

Usage:


var loader = new PluginAssemblyLoadContext(fullPath, false, typeof(IPluginCommand));
loader.CreateCommands<IPluginCommand>()...

Upvotes: 2

gradole
gradole

Reputation: 99

It happened to me when an interface had a reference to 3rd party dll (MWArray) with 'Specific Version' set to 'True' while the implemented class had a reference to the same dll but with 'Specific Version' set to 'False', so class and interface had different versions reference to the same dll.

Setting both to 'Specific Version': 'False' or 'True' (depending on what you need) fixed it.

Upvotes: 2

Get Off My Lawn
Get Off My Lawn

Reputation: 36311

What solved the problem for me was to add the following to ProjectReference and/or PackageReference along with <CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies> in the Assembly which was being loaded:

<Private>false</Private>
<ExcludeAssets>runtime</ExcludeAssets>

This then made my project file look something like this:

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>netcoreapp3.1</TargetFramework>
    <CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
  </PropertyGroup>

  <!-- For a package -->
  <ItemGroup>
    <PackageReference Include="SomePackage" Version="x.x.x.x">
      <Private>false</Private>
      <ExcludeAssets>runtime</ExcludeAssets>
    </PackageReference>
  </ItemGroup>

  <!-- For a project -->
  <ItemGroup>
    <ProjectReference Include="..\SomeProject\SomeProject.csproj">
      <Private>false</Private>
      <ExcludeAssets>runtime</ExcludeAssets>
    </ProjectReference>
  </ItemGroup>
</Project>

Upvotes: 0

vbguyny
vbguyny

Reputation: 1172

The solution for me was related to the fact that the project that was implementing the interface had the property "Register for COM Interop" set. Unchecking this option resolved the issue for me.

Upvotes: 0

JWallace
JWallace

Reputation: 487

I had this error when my integration test project was trying to load a DLL which didn't contain dependency resolution for an interface:

  1. Integration Test Project (references Main Project but not StructureMap)
  2. Main Project (references StructureMap project - uses Interface in class constructor)
  3. StructureMap Project (IoC - For().Use();)

This caused the error to be thrown because it couldn't find the concrete implementation. I excluded the DLL in my test configuration and the error disappeared

Upvotes: 0

Mahmoud Moravej
Mahmoud Moravej

Reputation: 9034

Our problem solved with updating windows! Our web application is on .Net 4.7.1 and c# 7.0. As we tested in different windowses, we understood that the problem will be solved by updating windows. Indeed, the problem was seen in windows 10 (version 1703) and also in a windows server 2012(not updated in last year). After updating both of them, the problem was solved. In fact, the asp.net minor version(the third part of the clr.dll version in C:\Windows\Microsoft.NET\Framework64\v4.0.30319 ) was changed a bit after the update.

Upvotes: 0

Ruben Bartelink
Ruben Bartelink

Reputation: 61795

I got this in a WCF service due to having an x86 build type selected, causing the bins to live under bin\x86 instead of bin. Selecting Any CPU caused the recompiled DLLs to go to the correct locations (I wont go into detail as to how this happened in the first place).

Upvotes: 2

Matthew Kane
Matthew Kane

Reputation: 331

Yet another way to get this:

class GenericFoo<T> {}

class ConcreteFoo : GenericFoo<ClassFromAnotherAssembly> {}

Code in an assembly that doesn't reference the assembly of ClassFromAnotherAssembly.

var foo = new ConcreteFoo(); //kaboom

This happened to me when ClassFromAnotherAssembly was ValueTuple.

Upvotes: 1

zzfima
zzfima

Reputation: 1565

I get this error today. My problem was - do not doing in TFS get latest version. In server was dll with interface whic one of methods was modified. I worked with an old one - in my PC its works. How to fix: get latest, rebuild

Upvotes: 1

Paul Matovich
Paul Matovich

Reputation: 1516

I ran into this and only my local machine was having the problem. No other developers in our group nor my VM had the problem.

In the end it seemed to be related to a "targeting pack" Visual Studio 2017

  • Open the Visual Studio Installer
  • Select Modify
  • Go to the second top tab "Individual Components"
  • See what Frameworks and Targeting packs you have selected.
  • I did not have the two newest targeting packs selected
  • I also noticed I did not have "Advanced ASP.NET features" selected and the other machines did.
  • Selected and installed the new items and it is all good now.

Upvotes: 0

tom redfern
tom redfern

Reputation: 31760

Just to add my experience as it has not been covered in other answers:

I got this problem when running unit tests in MsTest.

The classes under test were in a signed assembly.

A different version of this assembly happened to be in the GAC (but with the same assembly version number).

Dependency resolution algorithm for strong named assemblies is slightly different to non-signed as the GAC is checked first.

So MsTest was picking up the GAC'd assembly rather than using the one from the bin folder, and trying to run the tests against it, which was obviously not working.

Solution was to remove the GAC'd assembly.

Note, the clue for me was this was not happening on the build server when the tests were run, because the build would compile the assemblies with a new assembly version number. This meant that older versions of the assembly in the GAC would not be picked up.

Also, I found a potential workaround here, if you cannot for some reason access the GAC: https://johanleino.wordpress.com/2014/02/20/workaround-for-unit-testing-code-that-reside-in-the-gac/

Upvotes: 1

Mike_G
Mike_G

Reputation: 16502

I received this error after a recent windows update. I had a service class set to inherit from an interface. The interface contained a signature that returned a ValueTuple, a fairly new feature in C#.

All I can guess is that the windows update installed a new one, but even explicitly referencing it, updating binding redirects, etc...The end result was just changing the signature of the method to something "standard" I guess you could say.

Upvotes: 1

Hydrargyrum
Hydrargyrum

Reputation: 3816

I encountered this error in a context where I was using Autofac and a lot of dynamic assembly loading.

While performing an Autofac resolution operation, the runtime would fail to load one of the assemblies. The error message complained that Method 'MyMethod' in type 'MyType' from assembly 'ImplementationAssembly' does not have an implementation. The symptoms occurred when running on a Windows Server 2012 R2 VM, but did not occur on Windows 10 or Windows Server 2016 VMs.

ImplementationAssembly referenced System.Collections.Immutable 1.1.37, and contained implementations of a IMyInterface<T1,T2> interface, which was defined in a separate DefinitionAssembly. DefinitionAssembly referenced System.Collections.Immutable 1.1.36.

The methods from IMyInterface<T1,T2> which were "not implemented" had parameters of type IImmutableDictionary<TKey, TRow>, which is defined in System.Collections.Immutable.

The actual copy of System.Collections.Immutable found in the program directory was version 1.1.37. On my Windows Server 2012 R2 VM, the GAC contained a copy of System.Collections.Immutable 1.1.36. On Windows 10 and Windows Server 2016, the GAC contained a copy of System.Collections.Immutable 1.1.37. The loading error only occurred when the GAC contained the older version of the DLL.

So, the root cause of the assembly load failure was the mismatching references to System.Collections.Immutable. The interface definition and implementation had identical-looking method signatures, but actually depended on different versions of System.Collections.Immutable, which meant that the runtime did not consider the implementation class to match the interface definition.

Adding the following binding redirect to my application config file fixed the issue:

<dependentAssembly>
        <assemblyIdentity name="System.Collections.Immutable" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-1.1.37.0" newVersion="1.1.37.0" />
</dependentAssembly>

Upvotes: 7

Kgn-web
Kgn-web

Reputation: 7555

I faced almost same issue. I was scratching my head what is causing this error. I cross checked, all the methods were implemented.

On Googling I got this link among other. Based on @Paul McLink comment, This two steps resolved the issue.

  1. Restart Visual Studio
  2. Clean, Build (Rebuild)

and the error gone.

Restart VS Plugin

Thanks Paul :)

Hope this helps someone who come across this error :)

Upvotes: 3

Chris Peterson
Chris Peterson

Reputation: 713

As an addendum: this can also occur if you update a nuget package that was used to generate a fakes assembly. Say you install V1.0 of a nuget package and create a fakes assembly "fakeLibrary.1.0.0.0.Fakes". Next, you update to the newest version of the nuget package, say v1.1 which added a new method to an interface. The Fakes library is still looking for v1.0 of the library. Simply remove the fake assembly and regenerate it. If that was the issue, this will probably fix it.

Upvotes: 1

James
James

Reputation: 3928

In my case, I was attempting to use TypeBuilder to create a type. TypeBuilder.CreateType threw this exception. I eventually realized that I needed to add MethodAttributes.Virtual to the attributes when calling TypeBuilder.DefineMethod for a method that helps implements an interface. This is because without this flag, the method does not implement the interface, but rather a new method with the same signature instead (even without specifying MethodAttributes.NewSlot).

Upvotes: 1

fiat
fiat

Reputation: 15981

In my case I had previously referenced a mylib project in a sibling folder outside of the repo - let's call that v1.0.

|-- myrepo
|    |-- consoleApp
|    |-- submodules
|         |-- mylib (submoduled v2.0)
|-- mylib (stale v1.0)

Later I did it properly and used it via a git submodule - lets call that v2.0. One project consoleApp however wasn't updated properly. It was still referencing the old v1.0 project outside of my git project.

Confusingly, even though the *.csproj was plainly wrong and pointing to v1.0, the Visual Studio IDE showed the path as the v2.0 project! F12 to inspect the interface and class went to the v2.0 version too.

The assembly placed into the bin folder by the compiler was the v1.0 version, hence the headache.

That fact that the IDE was lying to me made it extra hard to realise the error.

Solution: Deleted project references from ConsoleApp and readded them.

General Tip: Recompile all assemblies from scratch (where possible, can't for nuget packages of course) and check datetime stamps in bin\debug folder. Any old dated assemblies are your problem.

Upvotes: 3

Almis
Almis

Reputation: 171

I had the same problem. I figured out that my assembly, which is loaded by the main program, had some references with "Copy Local" set to true. These local copies of references were looking for other references in the same folder, which did not exist because the "Copy Local" of other references was set to false. After the deletion of the "accidentally" copied references the error was gone because the main program was set to look for correct locations of references. Apparently the local copies of the references screwed up the sequence of calling because these local copies were used instead of the original ones present in the main program.

The take home message is that this error appears due to the missing link to load the required assembly.

Upvotes: 1

Tony Pulokas
Tony Pulokas

Reputation: 475

I have yet another esoteric solution to this error message. I upgraded my target framework from .Net 4.0 to 4.6, and my unit test project was giving me the "System.TypeLoadException...does not have an implementation" error when I tried to build. It also gave a second error message about the same supposedly non-implemented method that said "The 'BuildShadowTask' task failed unexpectedly." None of the advice here seemed to help, so I searched for "BuildShadowTask", and found a post on MSDN which led me to use a text editor to delete these lines from the unit test project's csproj file.

<ItemGroup>
  <Shadow Include="Test References\MyProject.accessor" />
</ItemGroup>

After that, both errors went away and the project built.

Upvotes: 6

Tolu
Tolu

Reputation: 1147

I got this error because I had a class in an assembly 'C' which was on version 4.5 of the framework, implementing an interface in assembly 'A' which was on version 4.5.1 of the framework and serving as the base class to assembly 'B' which was also on version 4.5.1 of the framework. The system threw the exception while trying to load assembly 'B'. Additionally, I had installed some nuget packages targeting .net 4.5.1 on all three assemblies. For some reason, even though the nuget references were not showing in assembly 'B', it was building successfully.

It turned out that the real issue was that the assemblies were referencing different versions of a nuget package that contained the interface and the interface signature had changed between versions.

Upvotes: 4

Robert Luo
Robert Luo

Reputation: 1

Another possibility is a mixture of release and debug builds in the dependencies. For example, Assembly A depends on Assembly B, A was built in Debug mode while the copy of B in GAC was built in Release mode, or vice versa.

Upvotes: -1

DJ.
DJ.

Reputation: 1025

I keep coming back to this... Many of the answers here do a great job of explaining what the problem is but not how to fix it.

The solution to this is to manually delete the bin files in your projects published directory. It will clean up all the references and force the project to use the latest DLLs.

I don't suggest using the publish tools Delete function because this tends to throw off IIS.

Upvotes: 10

user1228
user1228

Reputation:

Here's my take on this error.

Added an extern method, but my paste was faulty. The DllImportAttribute got put on a commented out line.

/// <returns>(removed for brevity lol)</returns>[DllImport("user32.dll")] 
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool IsWindowVisible(IntPtr hWnd);

Ensuring the attribute was actually included in source fixed the issue.

Upvotes: 2

Tilman
Tilman

Reputation: 237

FWIW, I got this when there was a config file that redirected to a non-existent version of a referenced assembly. Fusion logs for the win!

Upvotes: 4

Olivier Jacot-Descombes
Olivier Jacot-Descombes

Reputation: 112402

In my case it helped to reset the WinForms Toolbox.

I got the exception when opening a Form in the designer; however, compiling and running the code was possible and the code behaved as expected. The exception occurred in a local UserControl implementing an interface from one of my referenced libraries. The error emerged after this library was updated.

This UserControl was listed in the WinForms Toolbox. Probably Visual Studio kept a reference on an outdated version of the library or was caching an outdated version somewhere.

Here is how I recovered from this situation:

  1. Right click on the WinForms Toolbox and click on Reset Toolbox in the context menu. (This removes custom items from the Toolbox).
    In my case the Toolbox items were restored to their default state; however, the Pointer-arrow was missing in the Toolbox.
  2. Close Visual Studio.
    In my case Visual Studio terminated with a violation exception and aborted.
  3. Restart Visual Studio.
    Now everything is running smoothly.

Upvotes: 3

shenku
shenku

Reputation: 12448

I just upgraded a solution from MVC3 to MVC5, and started receiving the same exception from my Unit test project.

Checked all the references looking for old files, eventualy discovered I needed to do some bindingRedirects for Mvc, in my unit test project.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="System.Web.Helpers" publicKeyToken="31bf3856ad364e35" />
        <bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="System.Web.WebPages" publicKeyToken="31bf3856ad364e35" />
        <bindingRedirect oldVersion="0.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" />
        <bindingRedirect oldVersion="0.0.0.0-5.1.0.0" newVersion="5.1.0.0" />
      </dependentAssembly>
    </assemblyBinding>
  </runtime>
</configuration>

Upvotes: 3

TrustyCoder
TrustyCoder

Reputation: 4789

This simply means that the implementation project is out of date in my cases. The DLL containing the interface was rebuilt but the implementation dll was stale.

Upvotes: 2

Related Questions