C #: Как связать другую реализацию моего интерфейса во время выполнения с помощью ninject? - PullRequest
0 голосов
/ 30 сентября 2019

У меня есть пакет NuGet, в котором я использую ninject. Этот пакет NuGet будет использоваться несколькими приложениями, и каждое из этих приложений имеет свой собственный способ регистрации. Я хочу использовать регистратор по умолчанию, реализованный в моем пакете, если разработчик, использующий мой NuGet, не связывает свою реализацию моего интерфейса журналирования.

Итак, допустим, у нас есть следующий интерфейс:

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

Наш пакет NuGet также предоставляет собственную реализацию интерфейса ILogger, который используется по умолчанию:

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

В нашем пакете NuGet мы определили следующую привязку:

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

Теперь я хочу оставить разработчику, который использует мой пакет NuGet, возможность реализовать наш интерфейс ILogger и вызвать общедоступный API в моем пакете NuGet, чтобы заменить нашу реализацию ILogger его собственной:

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

Если есть другая реализация интерфейса ILogger, я хочу прекратить использование значения по умолчанию ConsoleLogger и использовать вместо этого предоставленную реализацию. Однако, когда я пытаюсь что-то вроде этого, я получаю следующее исключение:

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

*ISomeService - это сервис, реализация которого зависит от ILogger. Эта услуга больше не может быть активирована, потому что я что-то напутал, когда позвонил AddCustomBinding

. Я также попробовал следующее:

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

Но проблема остается той же. Кто-нибудь знает возможное решение для этого? Спасибо!

1 Ответ

0 голосов
/ 01 октября 2019

Я нашел правильное решение этой проблемы. Самый простой способ - позволить разработчикам, использующим мой пакет NuGet, реализовать интерфейс из моего пакета, который содержит метод, который загружает пользовательские привязки.

Допустим, я предоставляю им следующий интерфейс:

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

Разработчики, которые хотят использовать свой собственный регистратор, могут затем сделать что-то вроде этого:

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

Мой ServiceLocator класс - это статический класс, в котором есть статический конструктор, в который я могу загрузить все сборкииспользуя отражение и проверьте для IModuleLoader реализаций. Когда я соберу все реализации IModuleLoader, я могу вызвать метод LoadAssemblyBindings для загрузки всех пользовательских сборок.

Проверьте основную идею, стоящую за этим, здесь: https://www.codeproject.com/Articles/744862/Dependency-injection-in-class-libraries

...