Asp.Net核心中的属性注入

问题描述 投票:28回答:2

我正在尝试将asp.net应用程序移植到asp.net核心。我在这样的UnitOfWork实现上进行属性注入(使用ninject)。

[Inject]
public IOrderRepository OrderRepository { get; set; }
[Inject]
public ICustomerRepository CustomerRepository { get; set; }

是否可以使用.net核心上的内置DI实现相同的功能?也可以使用基于约定的绑定吗?

dependency-injection asp.net-core
2个回答
39
投票

不,故意在使用和功能方面使内置DI / IoC容器保持简单,以为其他DI容器插入提供基础。

因此,没有内置支持:自动发现,自动注册,修饰器或注入器或基于约定的注册。据我所知,还没有计划将其添加到内置容器中。

您必须使用带有属性注入支持的第三方容器。

[请注意,在所有情况下,属性注入在98%的情况下都被认为是不好的,因为它隐藏了依赖关系,并且不能保证在创建类时将注入对象。

通过构造函数注入,您可以通过构造函数强制执行此操作,并检查null和not创建类的实例。通过属性注入,这是不可能的,并且在单元测试期间,当在构造函数中未定义类时,类所需的服务/依赖关系就不明显,因此很容易错过并获得NullReferenceExceptions

我发现属性注入的唯一有效理由是将服务注入到第三方库生成的代理类中,即,从您无法控制对象创建的接口创建的WCF代理。甚至在那里,它仅适用于第三方库。如果您自己生成WCF代理,则可以通过partial class轻松扩展代理类,并添加新的DI友好构造函数,方法或属性。

避免它无处不在其他。


4
投票

是否有办法在.net核心上使用内置的DI实现相同的功能?

否,但是您可以在[inject]的帮助下创建自己的autofac's property injection mecanism属性。

首先创建自己的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));
  }
}

然后在ConfigureServiceswhere you wire upAutofacServiceProvider中使用选择器:

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配置服务时检查此属性。但这超出了此答案的范围。

© www.soinside.com 2019 - 2024. All rights reserved.