Asp.net核心MVC依赖注入-构造函数中的必需属性?

ʞᴉɯ*_*ʞᴉɯ 5 c# asp.net-mvc dependency-injection asp.net-core

在一个asp.net核心mvc项目中,我有一个ViewModel用于布局的抽象类,它需要一些属性才能正常运行,而每个具体页面的ViewModel派生结果都来自于此:

public abstract class Layout
{
    // required to function properly
    public string Prop1 { get; set; }

    // required to function properly
    public IEnumerable<Foo> FooList { get; set; }

    protected Layout()
    {
        // Populate FooList from an util caching class?
    }
}

public class ViewModelHome : Layout {}
public class ViewModelProducts : Layout {}
Run Code Online (Sandbox Code Playgroud)

布局需要FooList从数据库或缓存填充的,因为它是不经常更改的数据。

我想避免将每个必填字段放在构造函数中,以使其不太冗长,并且我想避免对每个派生类进行以下操作:

var model = new ViewModelHome();
model.FooList = .....
Run Code Online (Sandbox Code Playgroud)

在asp.net中IMemoryCache,可以通过DI的来进行核心缓存,所以我不能这样写:

    public abstract class Layout
    {           
       protected Layout()
       {
           var cacheClass = new MyCacheClass(...IMemoryCache??...);
           this.FooList = cacheClass.GetFooList();        
       }        
    }
Run Code Online (Sandbox Code Playgroud)

这是因为我是Layout在服务中自己创建的,而服务又是从控制器调用的。

public class MainController : Controller
{
    private readonly IMainService _service;

    public MainController(IMainService service)
    {
       _service = service;
    }


    public IActionResult Home()
    {              
       return View(_service.GetHomeViewModel());
    }
    public IActionResult Products()
    {
        return View(_service.GetProductsViewModel());
    }
 }
Run Code Online (Sandbox Code Playgroud)

我的问题是:我应该在抽象类构造函数中放入从数据库或缓存中获取数据的逻辑吗?

谢谢

Cri*_* E. 2

我想你这里有几个选择:

  1. 属性注入-IMemoryCache通过 DI 将您的属性注入到属性中(大多数容器都支持它),我不推荐这种方法。
public class Foo {
   [Inject] // or other marker attribute specific to your IoC
   public readonly IMemoryCache;
....
}
Run Code Online (Sandbox Code Playgroud)
  1. 服务定位器- 使用线程安全的单例引用容器并解决依赖关系。我也会避免这个选择。
public Foo(): base()
{
  base.MemoryCache = IoC.Resolve<IMemoryCache>();
}
Run Code Online (Sandbox Code Playgroud)
  1. 从派生到父级的 Ctor 注入- 尽管这可能很冗长,但它实际上是正确的做法,因为您将明确了解您的契约和依赖项。
public Foo(IMemoryCache cache): base(cache)
Run Code Online (Sandbox Code Playgroud)
  1. 在方法签名中传递依赖项- 非常明确但遵循函数式编程原则。例如:问问自己,是整个类需要该依赖项还是只是其中一个方法?
public void Foo(IMemoryCache cache, int bar)
Run Code Online (Sandbox Code Playgroud)
  1. Ctor 注入,但如果有太多依赖项,则将容器传递给父级
public Foo(IBar bar, IBaz baz, IContainer container): base(container)
{
  ...
}
Run Code Online (Sandbox Code Playgroud)

我曾遇到过在大量重构过程中选项 5 效果最好的情况。