Search code examples
c#typessystem.reflection

Type.GetInterface returning null


My issue is that I am getting different results to our older DLLs from history, when very little has changed and I don't under how the changes are relevant to the error shown.

This is part of a method, in our SecurityPluginServices.dll module, which essentially added plugins to a list so they can be utilised by the main program.

It gets all the DLLs in a set folder, then for each it runs through the code below.

private void AddPlugin(string FileName, LoggingUtilities.Source source)
{
    //Create a new assembly from the plugin file we're adding..
    Assembly pluginAssembly = Assembly.LoadFrom(FileName);

    try
    {
        //Next we'll loop through all the Types found in the assembly
        foreach (Type pluginType in pluginAssembly.GetTypes())
        {
            if (pluginType.IsPublic) //Only look at public types
            {
                if (!pluginType.IsAbstract)  //Only look at non-abstract types
                {
                    //Gets a type object of the interface we need the plugins to match
                    Type typeInterface = pluginType.GetInterface("SecurityInterface.ISecurityPlugin", true);

                    //Make sure the interface we want to use actually exists
                    if (typeInterface != null)
                    {
                     // Do work here
                    }

                    typeInterface = null; //Mr. Clean           
                }
            }
        }

        pluginAssembly = null; //more cleanup
    }
    catch (ReflectionTypeLoadException ex1)
    {
        Console.WriteLine(ex1.Message);
    }
    catch (Exception ex2)
    {
        Console.WriteLine(ex2.Message);
    }
}

The issue I am having is that everytime it gets to Type typeInterface = pluginType.GetInterface("SecurityInterface.ISecurityPlugin", true); it always returns null. The plugins I need to load are for NTLM and LDAP and they have changed very little in many versions and only a couple of extra properties and methods have been added, nothing to do with interfaces that the implement. I've opened up a copy of the newer plugin DLL and one of the older ones in ILDASM and they both seem to contain the same information regarding the SecurityInterface.ISecurityPlugin that the .GetInterface method is seeking.

Newer LdapSecurity

Older LdapSecurity


Solution

  • Suggestion:

    Type typeInterface = pluginType.GetInterface("SecurityInterface.ISecurityPlugin", true);
                                              // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    

    Change this to a fully-qualified type name, i.e. one that includes the assembly containing your interface type.

    (If you're now saying that you've got two different types by the same name, in two different assemblies, and therefore cannot include one definite assembly name, this may well be the likely cause of your issue.)

    Explanation:

    My other answer led me to a suspicion of what could cause your issue. Generally speaking, typeof(T) would force you to add an assembly reference to your project for the assembly that contains T. Otherwise, compilation will fail. On the other hand, textual mentions of type names such as Type.GetType("T") do not enforce a compile-time assembly reference... but they still have to be resolved to a type instance at run-time. So if you omit the assembly name, you need to keep in mind how .NET will map T to a specific assembly.

    Back to your issue. First, let's note that you are not using a fully-qualified type name:

    Type typeInterface = pluginType.GetInterface("SecurityInterface.ISecurityPlugin", true);
                                              // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    

    You specify only the namespace and the type name, but not the assembly containing your interface type. Could it be that the interface type is defined more than once, i.e. in different assemblies, and your mention of that type name is resolved to type in the wrong assembly?

    Let's briefly look at the MSDN documentation for Type.GetType(string) method, which describes the string parameter as follows:

    "The assembly-qualified name of the type to get. […] If the type is in the currently executing assembly or in Mscorlib.dll, it is sufficient to supply the type name qualified by its namespace."

    What if the same applies to the Type.GetInterface(string, bool) method which you're using? And what if your currently executing assembly does contain a type of that name? Then that is the type that pluginType will be checked against... but it might be a different ISecurityPlugin interface type (albeit equal in name) than the one your plug-in class actually implements.