简体   繁体   中英

C#: How to bind another implementation of my interface at runtime using ninject?

I have a NuGet package in which I'm using ninject. This NuGet package will be used by multiple applications and each of these applications have their own way of logging. I want to be able to use a default logger implemented in my package, unless the developer who is using my NuGet binds his own implementation of my logging interface.

So, let's say we have the following interface:

public interface ILogger
{
    void Log(string message);
}

Our NuGet package also provides its own implementation of the ILogger interface which is used by default:

internal class ConsoleLogger : ILogger
{
    public void Log(string message)
    {
        Console.WriteLine($"Console logger: {message}");
    }
}

In our NuGet package we have defined the following binding:

public void LoadAssemblyBindings(IKernel kernel)
{
    kernel.Bind<ILogger>().To<ConsoleLogger>().InSingletonScope();
}

Now I want to leave the possibility for the developer who is using my NuGet package to implement our ILogger interface and call a publicly available API in my NuGet package to replace our ILogger implementation with his own:

public void AddCustomBinding<T1, T2>()
    where T2 : T1
{
    this.kernel.Rebind<T1>().To<T2>();
}

If there is another implementation of the ILogger interface, I want to stop using the default ConsoleLogger and use the provided implementation instead. However, when I try something like this, I get the following exception:

Exception occurred: Ninject.ActivationException Error activating ISomeService
No matching bindings are available, and the type is not self-bindable.

* ISomeService is a service whose implementation is depending on ILogger . This service cannot be activated anymore because I have messed something up when I called AddCustomBinding

I have also tried the following:

public void AddCustomBinding<T1, T2>(T2 newBinding)
    where T2 : T1
{
    return this.kernel.Rebind<T1>().ToConstant(newBinding);
}

But the issue is still the same. Does anyone know the possible solution for this? Thanks!

I found a proper solution to this problem. The easiest way is to let the developers who are using my NuGet package implement an interface from my package which contains a method which loads custom bindings.

Let's say I provide them with the following interface:

public interface IModuleLoader
{
    void LoadAssemblyBindings(IKernel kernel);
}

The developers who want to use their custom logger can then do something like this:

public class ModuleLoader : IModuleLoader
{
    public void LoadAssemblyBindings(IKernel kernel)
    {
        kernel.Bind<ILogger>().To<FileLogger>().InSingletonScope();
    }
}

My ServiceLocator class is a static class which has a static constructor in which I can load all assemblies using reflection and check for IModuleLoader implementations. When I gather all IModuleLoader implementations, I can call the LoadAssemblyBindings method to load all of the custom assemblies.

Check the main idea behind this over here: https://www.codeproject.com/Articles/744862/Dependency-injection-in-class-libraries

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