0

I have the following project structure:

  1. Web API
  2. Class Library A
  3. Class Library B
  4. Class Library C

These are the references between the projects

  • Web API directly references A and B
  • B directly references C

C has a method which needs to ensure that A is loaded to use, by reflection, a type defined in it.

My code actually is like the following

public class C {
    public void MethodCallingBType( string fullClassName ) {
        //e.g. "MyNamespace.MyType, MyNamespace"
        string[] parts = fullClassName.Split( ',' );
        var className = parts[0].Trim();
        var assemblyName = parts[1].Trim();
        if ( !string.IsNullOrEmpty( assemblyName ) && !string.IsNullOrEmpty( className ) ) {
            string assemblyFolder = Path.GetDirectoryName( Assembly.GetExecutingAssembly().Location );
            string assemblyPath = Path.Combine( assemblyFolder, assemblyName + ".dll" );
            if ( File.Exists( assemblyPath ) ) {
                Assembly assembly = Assembly.LoadFrom( assemblyPath );
                Type type = assembly.GetType( className );
                result = Activator.CreateInstance( type ) as IInterfaceRunner;
            }
        }
    }
}

This code actually does not work as the Path.GetDirectoryName function does not return a valid path. Apart from this I would like to create a better way t ensure that B module is loaded in memory before looking for its type.

Any suggestion?

Lorenzo
  • 29,081
  • 49
  • 125
  • 222

2 Answers2

4

The simple Assembly.Load does not work? You don't have to know the location, only the name.

I use Assembly.CodeBase in the same situation and it works fine:

string codebase = System.Reflection.Assembly.GetExecutingAssembly().CodeBase;
Uri p = new Uri(codebase);
string localPath = p.LocalPath;
var myassembly = System.Reflection.Assembly.LoadFrom(System.IO.Path.Combine(localPath, "MyAssebmly.dll"));

Best regards, Peter

Peter Krassoi
  • 571
  • 3
  • 11
1

Modifying Peter's answer, but the logic is more correct as his will fail on the combine and no reason to create a URL to get the local file path.

using System.Reflection;
using System.IO;

var appDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
var myAssembly = Assembly.LoadFrom(Path.Combine(appDir, "MyAssebmly.dll"));
Chizl
  • 2,004
  • 17
  • 32
  • Yes and no. There's a difference between CodeBase and Location. See: https://blogs.msdn.microsoft.com/suzcook/2003/06/26/assembly-codebase-vs-assembly-location/ – Peter Krassoi Jan 16 '19 at 09:45
  • I know the difference, but your getting the http path, then converting to the Location. No reason to do that. Codebase is used for specific needs, but this isn't one of them. – Chizl Jan 16 '19 at 13:16
  • AFAIK Location can be totally wrong (i.e. somewhere in the GAC) where you cannot find the other dlls. If I understood correctly when we have two application (in C:\dir1 and C:\dir2 folders) using the same MyCommon assembly, then both will use exactly the same instance. From dir1 or dir2 or from the GAC (let's call it gacdir4mycommon), does not matter. But if we use MyCommon2 assembly with different versions in dir1 and dir2 (and of course no instance in gacdir4mycommon) then at least one Assembly.LoadFrom will fail from MyCommon using Assembly.Location. – Peter Krassoi Jan 18 '19 at 08:55
  • (continue:) If you are sure that Assembly.GetExecutingAssembly().Location is always "real" (never in the GAC), then your comment is correct. But I think this is not true, at least for IIS hosted applications. – Peter Krassoi Jan 18 '19 at 08:56
  • I guess the difference is, I never use the GAC. My libraries are always under the parent folder so I dont have to worry about versioning. I learned my lesson from the DLL hell days. – Chizl Jan 19 '19 at 20:37