尝试为绑定对象添加依赖注入

Trying to add dependency injection for binding object

我正在开发基于 .NET Core 2.0 的 Web 应用程序。 我有 class ReportModel,用于在控制器方法中绑定参数。而且我在同一个 class 中也有一些功能(方法 Get() 开始做一些事情,基于提供的绑定参数),例如:

    [HttpGet]
    public JsonResult GetReport(ReportModel model)
    {
        return new JsonResult( new { model.Get().ToString() });
    }

现在我要 .NET 5 并想通过 DI 添加 IConfigurationReportModel.

我希望它按以下方式工作:为 ReportModel 添加构造函数,为 DI 添加构造函数 IConfiguration 以提供配置:

    public class ReportModel
    {
        private readonly IConfiguration _configuration;

        public ReportModel(IConfiguration configuration)
        {
            _configuration = configuration;
        }
    ...

但是当我尝试 运行 GetReport(ReportModel model) 方法时 returns 异常: InvalidOperationException: Could not create an instance of type 'ViewData.Models.Data.ReportModel'. Model bound complex types must not be abstract or value types and must have a parameterless constructor. Record types must have a single primary constructor. Alternatively, give the 'data' parameter a non-null default value.

一点解释:还有几个 classes,我用这种方式(将参数绑定到属性并将功能存储在同一个 class 中),所以我真的不想为 IConfiguration.

添加每个方法 Get() 附加参数

我应该如何正确执行此操作?我错过了什么吗?或者它只是行不通?

如果我使用的术语有误,我深表歉意,如果您指出错误的内容,我们将很高兴。谢谢。

这是一个很好的问题。你走在正确的轨道上。

在我看来,ReportModel 根本不应该使用依赖注入。该模型应该只是一个 属性 对传入参数建模的包。

在控制器操作中执行逻辑(或以其他方式处理)。

How am I supposed to do this properly? Am I missing something? Or It's just don't work this way?

这样不行。

首先,模型不应该注入依赖项,它们只是 class 用于从请求中获取输入。

不过,这也是错误的: ... GetReport(ReportModel model)。这依赖于 ASP.NET Core 默认注入一个新的 ReportModel 这一事实——如果这种行为发生变化,您的代码会神奇地停止工作。

您的代码应该如下所示:

public class ReportsController
{
    private readonly IReportModelService _reportModelService;

    public ReportsController(IReportModelService reportModelService)
    {
        _reportModelService = reportModelService;
    }

    [HttpGet]
    public IActionResult GetReport()
    {        
        return new JsonResult(_reportModelService.GetReport());
    }
}

连同构建报告的适当 class,例如:

public class ReportModelService: IReportModelService
{
    private readonly IConfiguration _configuration;

    public ReportModelService(IConfiguration configuration)
    {
        _configuration = configuration;
    }

    public string GetReport()
    {
        // your logic here
    }
}

net core 中使用的默认 DI 容器只能在构造函数内部注入依赖项,在这种情况下是控制器构造函数,而不是在 action 内部,因为 action 没有构造函数。所以像这样更改你的代码

public class ReportController
{
   private readonly ReportModel _model

  public ReportController(ReportModel model )
  {
   _model=model;
  }  

    [HttpGet]
    public JsonResult GetReport()
    {
        return new JsonResult( new { _model.Get().ToString() });
    }
}

并且不要忘记将 DI 添加到启动中

services.AddScoped<ReportModel>();

所以我听从了@Camilo 的建议。我的计划是将 ReportModel 拆分为 ReportParams(DTO class)和 ReportProvider(业务逻辑 class)。然后,为 ReportProvider 添加构造函数,以便通过调用 ActivatorUtilities.CreateInstance<ReportProvider>()

通过 依赖注入 提供 IConfiguration

模型拆分:

    public class ReportParams
    {
        public double Size { get; set; }
        
        // other properties.
    }

    public class ReportProvider
    {
        private readonly IConfiguration _configuration;

        public ReportProvider(IConfiguration configuration)
        {
            _configuration = configuration;
        }

        public List<string> Get(ReportParams args)
        {
            // ...
        }
    }

报表控制器:

    public class ReportController: Controller
    {
        private readonly IServiceProvider _services;

        public ReportController(IServiceProvider services)
        {
            _services = services;
        }

        public IActionResult Get(ReportParams args)
        {
            ReportProvider model = ActivatorUtilities.CreateInstance<ReportProvider>(_services);
            return JsonResult(model.Get(args));
        }
    }