如何在模型(或虚拟机)中使用 DI?

Posted

技术标签:

【中文标题】如何在模型(或虚拟机)中使用 DI?【英文标题】:How to use DI in Model (or VM)? 【发布时间】:2022-01-10 00:24:09 【问题描述】:

我曾尝试分离 DAL 并将其注入 Program.cs 中的 DI,如下所示

services.AddScoped<IDataLoadServices, DataLoadServices>(); 

然后要从 DB 中获取数据并将其放入 Model(也许可以称之为 ViewModel)我需要从 Model 类的构造函数中获取这些服务,如下所示

class MyModel
    public IList Countriesget;set;
    
    public int SelectedCountryCodeget;set;
    
    //default Ctor
    //call When creating by Model Binding
    public MyModel()
      
    
    //call when creating by Factory
    [ActivatorUtilitiesConstructor]
    public MyModel(IDataLoadServices ser)
         Countries = ser.LoadMyListFromDB();           
    

在 Controller Action 中,我可以使用 FactoryServices 创建 MyModel 实例。(此处未显示) 之后成功传递给 View。

@model MyModel
<form method="post" asp-controller="MyController">
  ...
  <select asp-for="SelectedCountryCode" asp-items="@(new SelectList(Model.Countries, "CountryCode", "CountryName"))">            
  </select>
  <input type="hidden" asp-for="SelectedCountryCode" />
 ...

在提交后的控制器操作中

[HttpsPost]
public IActionResult Submited(MyModel model)
   //model.Countries == null
   //model.SelectedCountryCode == 0 ????

我认为 MyModel 的问题是在具有默认构造函数的模型绑定阶段创建的,因此它无法获取国家列表并且无法解析 SelectedCountryCode。

    是这样吗? 有什么办法绕过这个问题吗?

【问题讨论】:

【参考方案1】:

您的视图显示的大部分数据应该从控制器传入。我会尽可能保持模型裸露。相反,将IDataLoadServices 注入控制器。

public class WorldController : Controller

    private readonly IDataLoadServices _service;

    public WorldController(IDataLoadServices service)
    
         _service = service          
    

查看有关此的文档。 Dependency injection into controllers in ASP.NET Core

【讨论】:

【参考方案2】:

    对吗? --> 可能是,但您可以从模型中删除该默认 ctor。因为它会默认创建。

    有绕过这个问题的想法吗? --> 有很多方法可以做到这一点。

您可以使用 Options 模式(假设您有一个包含国家代码和国家名称的类)在 startup.cs 类中加载国家列表,然后在模型构造函数中使用该类。 Option Pattern 在控制器类构造函数中注入 IDataLoadServices。

【讨论】:

没有默认 ctor,因为模型绑定无法解析 IDataLoadServices,所以您会合规。并且将 IDataServices 放入 Controller 将与 Get Action(将模式放入 View)一起使用,但不适用于 Post Action(从模型绑定中获取模型) 您是否尝试过我上面提到的选项模式。 ?您是如何注册服务的? 我正在阅读选项模式但还没有理解。我在 Progarm.cs 的 ConfigureServices 方法中注册了 IDataLoadServices,例如“services.AddTransient()” 看看这个。 docs.microsoft.com/en-us/aspnet/core/mvc/views/…【参考方案3】:

    没错 --> ModelBininding 创建新的 MyModel 使用 Default Tor

    这不应该成为问题。我在 Control Action 中收到的 MyModel 实例应该有 SelectedCountryCode != 0。=> 我在 Mapping 类中失败了。

    [HttpsPost]
    
    public IActionResult Submited(MyModel model)
    
      //model.Countries == null => ok. because cant resolve IDataLoadServices
    
      //model.SelectedCountryCode != 0 
    
    

万一 someOne 需要 ModelBining 调用参数 Tor:

    创建工厂以将 DI 注入 Model Tor。

    public class FactoryServices : IFactoryServices
    
       private readonly IServiceProvider _sp;
    
       public FactoryServices(IServiceProvider serviceProvider)
       
         _sp = serviceProvider;
      
    
       public T Create<T>(params object[] p) 
       
    
         return ActivatorUtilities.CreateInstance<T>(_sp, p);
       
    
    

    创建自定义活页夹

    创建自定义 BinderProvider

    注册 DI

For 1., 3., 4. refer to this answer

【讨论】:

以上是关于如何在模型(或虚拟机)中使用 DI?的主要内容,如果未能解决你的问题,请参考以下文章

如何在为虚拟机增加磁盘后初始化磁盘

修炼内功[JVM] 浅谈虚拟机内存模型

深入理解JAVA虚拟机读书笔记——虚拟机类加载过程和双亲委派模型

Java虚拟机:内存模型详解

如何禁止VMware虚拟机与Host的时间同步功能

怎样扩展VMware虚拟机的硬盘容量