首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >ASP.NET核心中的属性注入

ASP.NET核心中的属性注入
EN

Stack Overflow用户
提问于 2016-07-19 21:10:22
回答 4查看 37.9K关注 0票数 52

我正在尝试将一个ASP.NET应用程序移植到ASP.NET核心。我在我的UnitOfWork实现上有如下的属性注入(使用Ninject):

代码语言:javascript
复制
[Inject]
public IOrderRepository OrderRepository { get; set; }
[Inject]
public ICustomerRepository CustomerRepository { get; set; }

有没有一种方法可以使用.NET核心上的内置DI实现相同的功能?另外,是否可以使用基于约定的绑定?

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2016-07-19 21:26:53

不,内置的DI/IoC容器在使用和功能上都有意保持简单,以便为其他DI容器提供一个插件的基础。

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

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

请注意,在98%的场景中,属性注入被认为是不好的,因为它隐藏了依赖关系,并且不能保证在创建类时对象将被注入。

使用构造函数注入,您可以通过构造函数强制执行此操作,并检查null和不创建类的实例。有了属性注入,这是不可能的,而且在单元测试期间,当类没有在构造函数中定义时,类需要哪些服务/依赖项并不明显,因此很容易遗漏并获得NullReferenceExceptions

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

everywhere else避免这样做。

票数 55
EN

Stack Overflow用户

发布于 2018-11-27 03:51:50

有没有一种方法可以使用.NET核心上的内置DI来实现相同的功能?

不能,但下面是如何在Autofac's property injection mechanism的帮助下创建自己的[inject]属性。

首先创建您自己的InjectAttribute

代码语言:javascript
复制
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public class InjectAttribute : Attribute
{
  public InjectAttribute() : base() { }
}

然后创建您自己的InjectPropertySelector,它使用反射来检查用[inject]标记的属性

代码语言:javascript
复制
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 where you wire up AutofacServiceProvider中使用选择器

代码语言:javascript
复制
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]

代码语言:javascript
复制
public class MyServiceX 
{
    [Inject]
    public IOrderRepository OrderRepository { get; set; }
    [Inject]
    public ICustomerRepository CustomerRepository { get; set; }
}

当然,您还可以进一步使用此解决方案,例如,使用属性在服务的类定义之上指定服务的生命周期……

代码语言:javascript
复制
[Injectable(LifetimeScope.SingleInstance)]
public class IOrderRepository

然后,...and会在通过Autofac配置服务时检查此属性。但这超出了这个答案的范围。

票数 14
EN

Stack Overflow用户

发布于 2021-04-09 21:24:16

我不想争论,因为我是.NET核心的新手。但想象一下这样的情况:class A使用服务Service1, ..., Service5,它们的接口IService1, ..., IService5作为依赖项传递到其构造函数中;class B继承自class Aclass C继承自class B等,因此所有这些派生类都应该至少在其构造函数中传递IService1, ..., IService5接口。但是,class B及其派生的所有类都放在使用者库或应用程序中,因此超出了class A开发人员的能力范围。

现在,class A的开发人员会发现,合并到class A中的一些功能值得重构和外包到外部服务中,因为它需要在class A之外的其他地方使用。因此,它使用IService6接口将其外包给Service6。但是,通过向class A构造函数添加另一个参数,开发人员违反了与该类用户的约定:构造函数用于派生类,并且只知道它的5个参数。

解决方案?或者:

  1. 通过属性注入IService6

  1. 将单个服务的5个接口传递给构造函数,而不是传递单个接口,该接口将在其属性中为上述5个服务提供5个接口。此接口将成为class A附带的软件包的一部分。如果需要将任何class A功能外包给服务,则将向此接口添加另一个属性,并将另一个服务添加到捆绑包中。所有class A依赖项(可能选项除外)都将在此界面中清楚地汇总。

  1. 有没有更好的解决方案?
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/38459625

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档