SamuGG
SamuGG

Reputation: 479

Load libraries from app.config

Say, for example, I have many methods for calculating the square root of a number.

One developer gives me his own .dll (maths1.dll), another one gives me his too (maths2.dll) and maybe a third one (maths3.dll).

All of them contains the same class, implementing the same interface.

Assembly 1 Maths1.dll

public class Maths : IMaths {
    public static string Author = "Author1";
    public static SquareRoot(int number) {
        // Implementation method 1
    }
}

Assembly 2 Maths2.dll

public class Maths : IMaths {
    public static string Author = "Author2";
    public static SquareRoot(int number) {
        // Implementation method 2
    }
}

etc. etc.

And I have a console application wich must be aware of all the dlls dynamically at runtime.

Looking for .dll files in code is undesirable.

// DON'T WANT THIS
DirectoryInfo di = new DirectoryInfo("bin");
FileInfo[] fi = di.GetFiles("*.dll");

My idea is to manage them from the app.config file with a custom configuration section.

<configuration>

    <configSections>
        <section name="MathsLibraries" type="MyMathsLibrariesSectionClass, ApplicationAssembly" />
    </configSections>

    <MathsLibraries>
        <Library author="Author1" type="MathsClass, Maths1Assembly" /><!-- Maths1.dll -->
        <Library author="Author2" type="MathsClass, Maths2Assembly" /><!-- Maths2.dll -->
        <Library author="Author3" type="MathsClass, Maths3Assembly" /><!-- Maths3.dll -->
    </MathsLibraries>

</configuration>

Considering I will manually copy the library file Maths1.dll to my application's bin folder.Then, the only thing I would have to do is, add a line to my app.config file in the MathsLibraries section.

I need an example code for the console application's Main, presenting the user all the dynamically linked .dll's and allowing him to calculate the square root of a number with the chosen library.

// NOT WORKING CODE, JUST IDEA OF WHAT IS NEEDED
public static void Main(string[] args) {

    // Show the user the linked libraries
    MathsLibraries libs = MathsLibraries.GetSection();
    Console.WriteLine("Available libraries:");
    foreach (MathLibrary lib in libs.Libraries) {
        Console.WriteLine(lib.Author);
    }

    // Ask for the library to use
    Console.Write("Which do you want to use?");
    selected_option = Console.Read();

    IMaths selected_library;
    // since we don't know wich class would be,
    // declare a variable using the interface we know they al implement.

    // Assign the right class to the variable
    if (selected_option == '1') {
        selected_library = Assembly1.Maths;    
    } else if (selected_option == '2') {
        selected_library = Assembly2.Maths;
    }
    // other options...

    // Invoke the SquareRoot method of the dynamically loaded class
    float sqr_result = selected_library.SquareRoot(100);
    Console.WriteLine("Result is {0}", sqr_result);

    Console.WriteLine("Press Enter key to exit");
    Console.Read();
}

Please, can any one help me in this task of loading assemblies from app.config.
Detailed code would be appreciated.
Thanks!

Upvotes: 1

Views: 2704

Answers (3)

David Bennington
David Bennington

Reputation: 356

Assuming they all implement the same interface (actually the same one, declared in the same assembly, not just the same definition in individual namespaces), you could use dependency injection like ms unity, which can be managed in config file, to register all implementations of this interface, create concrete implementations of all at run time, and execute them.

EDIT

Wrote a sample app, I'll post the meat here, and will provide a link to git hub or something when I get it uploaded.

I have an interface, IMasterInterface, and 3 implementations in separate assemblies 'UnityContainer.MasterImplementation', 'Satellite1.Implementation1' and 'Satellite2.Implementation2'. UnityConfiguration is a console app, and I have referenced unity using NuGet. For convenience, I have configured the build paths of all 3 assemblies to the same Build directory for Debug, so the 2 satellite assemblies are available to the console app.

IMasterInterface has a single method GetResult(): string.

  1. Edit web config with the following:

    
        <configuration>
            <configSections>
                <section name="unity"
                   type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection,
                         Microsoft.Practices.Unity.Configuration, Version=3.0.0.0,
                         Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
            </configSections>
            <unity>
                <typeAliases>
                    <typeAlias alias="IMasterInterface"           type="UnityInjection.IMasterInterface, UnityInjection" />
                    <typeAlias alias="MasterImp"                  type="UnityInjection.MasterImplementation, UnityInjection" />
                    <typeAlias alias="SatelliteOneImplementation" type="Satellite1.Implementation1, Satellite1" />
                    <typeAlias alias="SatelliteTwoImplementation" type="Satellite2.Implementation2, Satellite2" />
                </typeAliases>
                <containers>
                    <container name="containerOne">
                        <types>
                            <type type="IMasterInterface" mapTo="MasterImp" name="Master" />
                            <type type="IMasterInterface" mapTo="SatelliteOneImplementation" name="One" />
                            <type type="IMasterInterface" mapTo="SatelliteTwoImplementation" name="Two" />
                        </types>
                    </container>
                </containers>
            </unity>
        </configuration>
    
  2. Configure the container

    
        //Set up the dependency container
        IUnityContainer myContainer = new UnityContainer();
        var section = (UnityConfigurationSection)ConfigurationManager.GetSection("unity");
        section.Configure(myContainer, "containerOne");
    
  3. Resolve All implementations

    
        //create all implementations of out interface
        var implementations = myContainer.ResolveAll<IMasterInterface>();
    
    
    //call the method we are interested in for all implementations
    foreach (var implementation in implementations)
    {
        Console.WriteLine(implementation.GetResult());
    }
    
  4. Resolve a specific named implementation

    
        //Get a particular one
        var specific = myContainer.Resolve<IMasterInterface>("Master");
        Console.WriteLine(specific.GetResult());
    

Upvotes: 1

SergeyIL
SergeyIL

Reputation: 595

You can use reflection to load selected library and create instance of required type.

var assembly = Assembly.LoadFrom("selected_math_library.dll");
var types = assembly.GetTypes();

var mathType = (from type in types
                      where type.GetInterface("IMath") != null && !type.IsAbstract
                      select type).ToList();

if (mathType.Count > 0)
{
    IMath math = (IMath)Activator.CreateInstance(mathType);
    // call methods from math

}

Upvotes: 0

Ehsan
Ehsan

Reputation: 32711

Possible duplicate of C# - Correct Way to Load Assembly, Find Class and Call Run() Method

    var asm = Assembly.LoadFile(@"YourMathAssembly.dll");
   var type = asm.GetType("Maths");
     var sqrRoot = Activator.CreateInstance(Maths) as IMaths;
 if (sqrRoot == null) 
    throw new Exception("broke");
        sqrRoot .SquareRoot(100);

Upvotes: 0

Related Questions