Автоматическое связывание интерфейсов с помощью AutoFac
У меня есть некоторые классы, такие как UserQuery, CustomerQuery, реализующие интерфейсы, такие как IUserQuery, ICustomerQuery соответственно. В моей конфигурации привязки мне нужно связать каждый интерфейс с запросом соответственно:
builder.RegisterType<UserQuery>().As<IUserQuery>().InstancePerRequest();
builder.RegisterType<CustomerQuery>().As<ICustomerQuery>().InstancePerRequest();
Это работает очень хорошо, но мне было интересно, есть ли способ сделать привязку на основе соглашения вместо привязки каждой отдельной строки XXX [Query] → [I] XXX [Query].
Я использую AutoFac в качестве контейнера DI.
Ответы
Ответ 1
Я не опытный пользователь AutoFac. Однако после некоторого исследования успешно протестировали код ниже:
var assembly = Assembly.GetExecutingAssembly();
builder
.RegisterAssemblyTypes(assembly)
.AssignableTo<IQuery>()
.AsImplementedInterfaces()
.InstancePerRequest();
Интерфейс IQuery выше - это просто интерфейс тега, который должен быть унаследован от каждого интерфейса запроса, который у вас есть. Используя ваш пример:
Интерфейсы
IUserQuery: IQuery
ICustomerQuery: IQuery
Классы
UserQuery: IUserQuery
CustomerQuery: CustomerQuery
Ответ 2
Вам необходимо использовать функцию сканирования сборок в Autofac.
Если ваши интерфейсы или ваши реализации разделяют базовый класс (например, QueryBase
) или базовый интерфейс (например, IQuery
), вы можете использовать методы convince для регистрации, такие как: AssignableTo<>
и т.д. см. < Ответ href= "/questions/327523/automatically-bind-interfaces-using-autofac/1569760#1569760" > gustavodidomenico.
Однако иногда у вас не может быть общего базового интерфейса/класса, в этом случае вы можете использовать метод Where
, где у вас может быть любая пользовательская логика для определения того, какие классы должны быть зарегистрированы и как.
В этом случае ваша регистрация должна выглядеть примерно так:
builder.RegisterAssemblyTypes(yourAssembly)
.Where(t => t.IsClass && t.Name.EndsWith("Query"))
.As(t => t.GetInterfaces().Single(i => i.Name.EndsWith(t.Name)));
Он зарегистрирует все типы из данной сборки, имя которой заканчивается на "Query"
с помощью соответствующего интерфейса, поэтому он зарегистрирует SomeNiceQuery
с помощью интерфейса ISomeNiceQuery
Ответ 3
В качестве альтернативы вы можете просто зарегистрировать каждый тип либо как первый реализованный интерфейс, либо самостоятельно.
builder.RegisterAssemblyTypes(new[] { Assembly.GetAssembly(typeof(IUserQuery))})
.Where(x=> x.IsClass && x.Name.EndsWith("Query"))
.As(t => t.GetInterfaces().Any() ? t.GetInterfaces()[0] : t);