Инъекция собственности в Core Asp.Net
Я пытаюсь перенести приложение asp.net в ядро asp.net. У меня есть инъекция свойств (используя ninject) в моей реализации UnitOfWork, как это.
[Inject]
public IOrderRepository OrderRepository { get; set; }
[Inject]
public ICustomerRepository CustomerRepository { get; set; }
Есть ли способ достичь той же функциональности, используя встроенный DI на .net-ядре? Также возможно использовать привязку на основе соглашения?
Ответы
Ответ 1
Нет, встроенный контейнер DI/IoC намеренно упрощается как в использовании, так и в функциях, чтобы предложить базу для других контейнеров DI для плагина.
Таким образом, нет встроенной поддержки для: автоматического обнаружения, авторегистрации, декораторов или инжекторов или регистрации на основе конвенций. Также нет планов добавить это во встроенный контейнер, насколько я знаю.
Вам понадобится использовать сторонний контейнер с поддержкой вставки свойств.
Обратите внимание, что в 98% всех сценариев вложение свойств считается плохим, поскольку оно скрывает зависимости, и нет гарантии, что объект будет введен при создании класса.
С вводом конструктора вы можете принудительно выполнить это через конструктор и проверить значение null и не создавать экземпляр класса. При инъекции свойств это невозможно, и во время модульных тестов неясно, какие службы/зависимости требуется классу, когда они не определены в конструкторе, поэтому легко пропустить и получить NullReferenceExceptions
.
Единственная действительная причина для Инъекции свойств, которую я когда-либо находил, заключалась в том, чтобы внедрять службы в прокси-классы, созданные сторонней библиотекой, то есть прокси WCF, созданные из интерфейса, где у вас нет контроля над созданием объекта.
Избегайте его везде else.
Ответ 2
Есть ли способ достичь такой же функциональности, используя сборку DI на ядре.net?
Нет, но вот как вы можете создать свои собственные атрибуты [inject]
с помощью метода автозаполнения свойств.
Сначала создайте свой собственный InjectAttribute
:
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public class InjectAttribute : Attribute
{
public InjectAttribute() : base() { }
}
Затем создайте свой собственный InjectPropertySelector
который использует отражение, чтобы проверить свойства, помеченные с помощью [inject]
:
public class InjectPropertySelector : DefaultPropertySelector
{
public InjectPropertySelector(bool preserveSetValues) : base(preserveSetValues)
{ }
public override bool InjectProperty(PropertyInfo propertyInfo, object instance)
{
var attr = propertyInfo.GetCustomAttribute<InjectAttribute>(inherit: true);
return attr != null && propertyInfo.CanWrite
&& (!PreserveSetValues
|| (propertyInfo.CanRead && propertyInfo.GetValue(instance, null) == null));
}
}
Затем используйте свой селектор в ConfigureServices
где вы AutofacServiceProvider
:
public class Startup
{
public IServiceProvider ConfigureServices(IServiceCollection services)
{
var builder = new ContainerBuilder();
builder.Populate(services);
// use your property selector to discover the properties marked with [inject]
builder.RegisterType<MyServiceX>().PropertiesAutowired((new InjectablePropertySelector(true)););
this.ApplicationContainer = builder.Build();
return new AutofacServiceProvider(this.ApplicationContainer);
}
}
Наконец, в вашем сервисе вы теперь можете использовать [inject]
:
public class MyServiceX
{
[Inject]
public IOrderRepository OrderRepository { get; set; }
[Inject]
public ICustomerRepository CustomerRepository { get; set; }
}
Вы, конечно же, можете принять это решение еще больше, например, используя атрибут для определения жизненного цикла службы выше вашего определения класса обслуживания...
[Injectable(LifetimeScope.SingleInstance)]
public class IOrderRepository
... и затем проверяя этот атрибут при настройке ваших сервисов через autofac. Но это выходит за рамки этого ответа.
Ответ 3
Когда доступен HttpContext
(например, в контроллере), существует одно быстрое и грязное решение с использованием шаблона HttpContext
сервисов:
ILoggingService Logger => HttpContext.RequestServices.GetService<ILoggingService>();
Однако это не рекомендуется, и обычно ссылки на службы должны быть получены с помощью инжектора конструктора или [FromServices]
параметра [FromServices]
.