Autofa c 5 отменяет регистр в зависимости от состояния - PullRequest
1 голос
/ 02 апреля 2020

Для приложения у меня есть несколько IAuthentificationProvider:

public interface IAuthentificationProvider
{
   bool IsUserValid(string login, string password)
}

Для каждого IAuthentificationProvider У меня есть IAuthentificationProviderConfig, связанный с:

public interface IAuthentificationProvider
{
   bool IsEnabled { get; set; }
}

Для использования всех этих включенных поставщиков у меня есть другой класс :

public class AuthentificationManager
{
   public AuthentificationManager(IEnumerable<IAuthentificationProvider> providers)
   {
      //do something with providers
   }

   //other class logic
}

Теперь я хочу регистрировать только включенных провайдеров. Я пробовал что-то подобное:

//finding all possible providers in assembly
var providerInterface = typeof(IAuthentificationProvider);
var types = AppDomain.CurrentDomain.GetAssemblies()
    .SelectMany(s => s.GetTypes())
    .Where(p => providerInterface.IsAssignableFrom(p) && !p.IsAbstract).ToList();

foreach (var type in types)
{
    //Register type as self for simple resolve in lambda expression
    containerBuilder.RegisterType(type).AsSelf().SingleInstance();
    containerBuilder.Register(c =>
    {
        var configs = c.Resolve<IAuthentificationProvidersConfig>();
        //get specific configuration for provider
        var config = configs.GetConfig(type.Name);
        if (config.IsEnabled)
        {
           //return provider
           return c.Resolve(type);
        }
        else
        {
           //"cancel the register"
           return new object();
        }

     }).As<IAuthentificationProvider>().SingleInstance();
}

В Autofa c 4.9 вышеуказанный код работает, но теперь в Autofa c 5.1.2 строка return new object(); больше не работает:

InvalidCastException: Object cannot be stored in an array of this type.

Есть ли другой способ отменить регистр внутри лямбды?

1 Ответ

2 голосов
/ 02 апреля 2020

Вы не можете отменить регистрацию внутри лямбды той же самой регистрации. На мой взгляд, у вас есть два варианта:

1: разделить чтение конфигурации и конфигурации контейнера

Вы должны предпочесть разделение фазы при запуске приложения, когда вы читаете конфигурацию из фазы, где Вы регистрируете контейнер. Это позволяет сделать регистрацию условно на основе значения конфигурации.

Например:

var configs = new AuthentificationProvidersConfig();

builder.RegisterInstance(configs).As<IAuthentificationProvidersConfig>();

foreach (var type in types)
{
    if (configs.GetConfig(type.Name).IsEnabled)
    {
        builder.Register(type).As<IAuthentificationProvider>().AsSingleInstance();
    }
}

2. Создайте композит, который позволяет фильтровать провайдеров во время выполнения

В случае, если первое решение нежизнеспособно, вы можете фильтровать эти типы во время выполнения. Есть несколько способов сделать это, например, скрыть IEnumerable<IAuthentificationProvider> за составным, или отфильтровать типы внутри AuthentificationManager, или, возможно, просто зарегистрировать IEnumerable<IAuthentificationProvider> напрямую с помощью лямбды, чтобы вы могли создать отфильтрованный список :

foreach (var type in types)
{
    //Register type as self for simple resolve in lambda expression
    containerBuilder.RegisterType(type)
        .AsSelf()
        .SingleInstance();
}

containerBuilder.Register(c => (
    from type in types
    let configs = c.Resolve<IAuthentificationProvidersConfig>()
    let config = configs.GetConfig(type.Name)
    where config.IsEnabled
    select (IAuthentificationProvider)c.Resolve(type))
    .ToList()
    .AsReadOnly())
    .As<IEnumerable<IAuthentificationProvider>>()
    .SingleInstance();

...