简体   繁体   中英

C# - Loading dlls and creating instances

I have a situation and I need to know how to deal with it in the best way.

I have an application (MVC3) and I have couple of integrations for it. I have an interface "IntegrationInterface" and every integration implements it. I want to load the dlls of the integrations, create a list of them, and run a loop that runs a method for every integration in the list.

For example - let's say I have integrations for facebook, myspace and twitter (for my appliction), and every time the user post a message in my application I want to post a message on his\\her facebook, myspace and twitter.

I don't want that the code will know which integrations I have, so if tomorrow I'll create a new integration for google+, I'll just need to add a new DLL without changing the code of my application.

How can I do that?

First, you'll have to find all relevant dlls and classes:

loadedIntegrations.Clear();
if (!Directory.Exists(path))
    return;
DirectoryInfo di = new DirectoryInfo(path);
FileInfo[] files = di.GetFiles("*.dll");
foreach (var file in files)
{
    Assembly newAssembly = Assembly.LoadFile(file.FullName);
    Type[] types = newAssembly.GetExportedTypes();
    foreach (var type in types)
    {
        //If Type is a class and implements the IntegrationInterface interface
        if (type.IsClass && (type.GetInterface(typeof(IntegrationInterface).FullName) != null))
            loadedIntegrations.Add(type);
    }
}

loadedIntegrations is of type List<Type> . Then you can instantiate each integration and call its methods:

foreach(var integrationType in loadedIntegrations)
{
    var ctor = integrationType.GetConstructor(new Type[] { });
    var integration = ctor.Invoke(new object[] { }) as IntegrationInterface;
    //call methods on integration
}

I am doing something similar to what you described in an import utility that wrote. My issue was that I didn't want to load ALL the assemblies. I only wanted to load assemblies that contained types that were requested.

To accomplish this I've used the AppDomain.CurrentDomain.AssemblyResolve event handler.

This event handler is raised just before the AppDomain throw an exception notifying that an assembly is not found. I execute similar code to what Nico suggested in that handler and return the requested assembly.

NOTE: I have a sub-directory called 'Tasks' (think Import Tasks) where I store all of my assemblies I want to load at runtime.

Here is the code:

        var tasks = GetTasks();
        var basedir = AppDomain.CurrentDomain.BaseDirectory; // Get AppDomain Path
        var tasksPath = Path.Combine(basedir, "Tasks"); // append 'Tasks' subdir

        // NOTE: Cannot be factored, relies on 'tasksPath' variable (above).
        AppDomain.CurrentDomain.AssemblyResolve += (s, e) => // defined 'AssemblyResolve' handler
        {
            var assemblyname = e.Name + ".dll"; // append DLL to assembly prefix
            // *expected* assembly path
            var assemblyPath = Path.Combine(tasksPath, assemblyname); // create full path to assembly
            if (File.Exists(assemblyPath)) return Assembly.LoadFile(assemblyPath); // Load Assembly as file.
            return null; // return Null if assembly was not found. (throws Exception)
        };

        foreach (var task in tasks.OrderBy(q => q.ExecutionOrder)) // enumerate Tasks by ExecutionOrder
        {
            Type importTaskType = Type.GetType(task.TaskType); // load task Type (may cause AssemblyResolve event to fire)
            if (importTaskType == null)
            {
                log.Warning("Task Assembly not found");
                continue;
            }
            ConstructorInfo ctorInfo = importTaskType.GetConstructor(Type.EmptyTypes); // get constructor info
            IImportTask taskInstance = (IImportTask)ctorInfo.Invoke(new object[0]); // invoke constructor and cast as IImportTask
            taskInstances.Add(taskInstance);
        }
        // rest of import logic omitted...

If u know MEF (Managed extensibility framework) this might help you I personally use it but have to say that using MEF with MVC is not trivial i think for more information please visit

http://msdn.microsoft.com/en-us/library/dd460648.aspx

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM