Simple Injection Plugins

I am building a system in .NET 4.5, which will have different implementations (i.e. it is implemented indoors for different clients). Each client will have its own infrastructure and database structure, so I am building a system that relies heavily on bow architecture, by itself relying on interfaces and DI. Thus, I can use client-specific solutions "Repository" and "Service".

My goal is to be able to install the system on the client server without recompilation (the entry point to the system is basically a Windows service that periodically runs business logic and also supports WCF services). To do this, I mean some “Dependencies” or “Plugins” folder as a subfolder of the folder containing the Windows service executable, which will contain a client-specific DLL that has specific classes that implement all the necessary interfaces on which the application relies.

I am trying to achieve this with Simple Injector. I looked at the assembly of SimpleInjector.Packaging, as well as the paragraph "Registering plugins dynamically" here , but I'm still kind of stuck and do not know where to start, like what I have to determine in which assembly.

I need some concrete example of how to achieve this.

Is the SimpleInjector Packaging assembly used for this purpose, or am I seeing this incorrectly? If so, how?

Someone please enlighten me.

thank

ps: to be 100% understandable: interfaces and specific implementations are obviously divided into different assemblies. This question is related to how to dynamically connect all things using Simple Injector.

+4
3

IoC, Simple Injector, , . , .

public interface IImageConverter : IDisposable
{
    string Name { get; }
    string DefaultSourceFileExtension { get; }
    string DefaultTargetFileExtension { get; }
    string[] SourceFileExtensions { get; }
    string[] TargetFileExtensions { get; }
    void Convert(ImageDetail image);
}

( , .NET)

private void RegisterImageConverters(Container container)
{
    var pluginAssemblies = this.LoadAssemblies(this.settings.PluginDirectory);

    var pluginTypes =
        from dll in pluginAssemblies
        from type in dll.GetExportedTypes()
        where typeof(IImageConverter).IsAssignableFrom(type)
        where !type.IsAbstract
        where !type.IsGenericTypeDefinition
        select type;

    container.RegisterAll<IImageConverter>(pluginTypes);
}

private IEnumerable<Assembly> LoadAssemblies(string folder)
{
    IEnumerable<string> dlls =
        from file in new DirectoryInfo(folder).GetFiles()
        where file.Extension == ".dll"
        select file.FullName;

    IList<Assembly> assemblies = new List<Assembly>();

    foreach (string dll in dlls) {
        try {
            assemblies.Add(Assembly.LoadFile(dll));
        }
        catch { }
    }

    return assemblies;
}

, ,

container.RegisterDecorator(
    typeof(IImageConverter), 
    typeof(ImageConverterChecksumDecorator));
container.RegisterDecorator(
    typeof(IImageConverter), 
    typeof(ImageConverterDeleteAndRecycleDecorator));
container.RegisterDecorator(
    typeof(IImageConverter), 
    typeof(ImageConverterUpdateDatabaseDecorator));
container.RegisterDecorator(
    typeof(IImageConverter), 
    typeof(ImageConverterLoggingDecorator));

, , ,

public sealed class PluginManager : IPluginManager
{
    private readonly IEnumerable<IImageConverter> converters;

    public PluginManager(IEnumerable<IImageConverter> converters) {
        this.converters = converters;
    }

    public IList<IImageConverter> List() {
        return this.converters.ToList();
    }

    public IList<IImageConverter> FindBySource(string extension) {
        IEnumerable<IImageConverter> converters = this.converters
            .Where(x =>
                x.SourceFileExtensions.Contains(extension));

        return converters.ToList();
    }

    public IList<IImageConverter> FindByTarget(string extension) {
        IEnumerable<IImageConverter> converters = this.converters
            .Where(x =>
                x.TargetFileExtensions.Contains(extension));

        return converters.ToList();
    }

    public IList<IImageConverter> Find(
        string sourceFileExtension, 
        string targetFileExtension)
    {
        IEnumerable<IImageConverter> converter = this.converters
            .Where(x =>
                x.SourceFileExtensions.Contains(sourceFileExtension) &&
                x.TargetFileExtensions.Contains(targetFileExtension));

        return converter.ToList();
    }

    public IImageConverter Find(string name) {
        IEnumerable<IImageConverter> converter = this.converters
            .Where(x => x.Name == name);

        return converter.SingleOrDefault();
    }
}

IPluginManager , Simple Injector :

container.Register<IPluginManager, PluginManager>();

, .

+5

, , , :

public class TypeLoader<T> : List<T>
{
    public const BindingFlags ConstructorSearch =
        BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.CreateInstance |
        BindingFlags.Instance;

    private void Load(params Assembly[] assemblies)
    {
        foreach (
            Type t in
                assemblies.SelectMany(
                    asm =>
                        asm.GetTypes()
                            .Where(t => t.IsSubclassOf(typeof (T)) || t.GetInterfaces().Any(i => i == typeof (T)))))
        {
            Add((T) Activator.CreateInstance(t, true));
        }
    }
}

, , Assembly.ReflectionOnlyLoad .

, , IPlugin , new TypeLoader<IPlugin>().Load(assemblies);, , IPlugin.

+2

API .NET . , , . API Simple Injector, , , LINQ .

, :

// Find all repository abstractions
var repositoryAbstractions = (
    from type in typeof(ICustomerRepository).Assembly.GetExportedTypes()
    where type.IsInterface
    where type.Name.EndsWith("Repository")
    select type)
    .ToArray();

string pluginDirectory =
    Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Plugins");

// Load all plugin assemblies
var pluginAssemblies =
    from file in new DirectoryInfo(pluginDirectory).GetFiles()
    where file.Extension.ToLower() == ".dll"
    select Assembly.LoadFile(file.FullName);

// Find all repository abstractions
var repositoryImplementationTypes =
    from assembly in pluginAssemblies
    from type in assembly.GetExportedTypes()
    where repositoryAbstractions.Any(r => r.IsAssignableFrom(type))
    where !type.IsAbstract
    where !type.IsGenericTypeDefinition
    select type;

// Register all found repositories.
foreach (var type in repositoryImplementationTypes)
{
    var abstraction = repositoryAbstractions.Single(r => r.IsAssignableFrom(type));
    container.Register(abstraction, type);
}

The above code is a variation of the sample code in the Registering plugins dynamically wiki page from the Simple Injector documentation.

+1
source

Source: https://habr.com/ru/post/1533184/


All Articles