Özg*_*lan 30 dependency-injection asp.net-core
我正在尝试将asp.net应用程序移植到asp.net核心.我在我的UnitOfWork实现上有属性注入(使用ninject).
[Inject]
public IOrderRepository OrderRepository { get; set; }
[Inject]
public ICustomerRepository CustomerRepository { get; set; }
Run Code Online (Sandbox Code Playgroud)
有没有办法在.net核心上使用DI构建来实现相同的功能?是否可以使用基于约定的绑定?
Tse*_*eng 41
不,内置的DI/IoC容器在使用和功能方面都有意保持简单,为其他DI容器插件提供了基础.
因此,没有内置支持:自动发现,自动注册,装饰器或注入器,或基于约定的注册.据我所知,目前还没有计划将其添加到内置容器中.
您必须使用具有属性注入支持的第三方容器.
请注意,在98%的场景中,属性注入被认为是错误的,因为它隐藏了依赖关系,并且无法保证在创建类时将注入对象.
使用构造函数注入,您可以通过构造函数强制执行此操作并检查null,而不是创建类的实例.使用属性注入这是不可能的,并且在单元测试期间,当它们未在构造函数中定义时,不太明显该类需要哪些服务/依赖项,因此容易遗漏和获取NullReferenceExceptions.
我迄今发现的唯一正当理由物业注射到中注入服务由第三方库生成的代理类,从那里你不知道的对象创建控制的接口创建即WCF代理.
在其他地方避免它.
得票最高的答案并不完全正确。虽然内置 DI 容器 ( IServiceProvider) 有意保持简单且功能轻,但它也具有相当的可扩展性,并且可以通过一些管道提供您所需的功能。
这就是Quickwire NuGet 包提供的开箱即用的功能。这正如您所期望的那样工作。
首先用 和 来装饰类[RegisterService],并使用 attribute 来注入属性[InjectService]:
[RegisterService(ServiceLifetime.Scoped)]
public class BusinessLogic
{
[InjectService]
public IOrderRepository OrderRepository { get; set; }
[InjectService]
public ICustomerRepository CustomerRepository { get; set; }
// ...
}
Run Code Online (Sandbox Code Playgroud)
然后使用ScanCurrentAssembly来自ConfigureServices:
public void ConfigureServices(IServiceCollection services)
{
services.ScanCurrentAssembly();
// Register other services...
}
Run Code Online (Sandbox Code Playgroud)
这将扫描当前程序集以查找用 修饰的类RegisterService并将它们注册到 中IServiceCollection,同时确保将依赖项注入到用 修饰的 setter 中[InjectService]。
再次强调,此方法不需要您使用 Autofac 等第三方依赖项注入容器。您的所有现有代码将继续工作,无需任何修改。
是否有办法在.net核心上使用内置DI实现相同的功能?
不,但是这里是您可以[inject]在autofac的属性注入机制的帮助下创建自己的属性的方法。
首先创建自己的InjectAttribute:
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public class InjectAttribute : Attribute
{
public InjectAttribute() : base() { }
}
Run Code Online (Sandbox Code Playgroud)
然后创建自己的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));
}
}
Run Code Online (Sandbox Code Playgroud)
然后在你使用你的选择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);
}
}
Run Code Online (Sandbox Code Playgroud)
最后,您现在可以使用[inject]:
public class MyServiceX
{
[Inject]
public IOrderRepository OrderRepository { get; set; }
[Inject]
public ICustomerRepository CustomerRepository { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
您肯定可以进一步采用此解决方案,例如,通过在服务的类定义上方使用属性来指定服务的生命周期...
[Injectable(LifetimeScope.SingleInstance)]
public class IOrderRepository
Run Code Online (Sandbox Code Playgroud)
...然后在通过autofac配置服务时检查此属性。但这将超出此答案的范围。
| 归档时间: |
|
| 查看次数: |
18070 次 |
| 最近记录: |