I'm working on web application based on .NET CORE 2.0.
I have class ReportModel, which I use for binding parameters in controller method. And I also have some functionality in the same class (method Get() starts doing somethings, based on provided binded parameters), e.g:
[HttpGet]
public JsonResult GetReport(ReportModel model)
{
return new JsonResult( new { model.Get().ToString() });
}
Now I'm moving on .NET 5 and want to add IConfiguration via DI to ReportModel.
I've expected it to work the follwing way: add constructor for ReportModel with IConfiguration for DI to provide configuration:
public class ReportModel
{
private readonly IConfiguration _configuration;
public ReportModel(IConfiguration configuration)
{
_configuration = configuration;
}
...
But when I try to run GetReport(ReportModel model) method it returns exception:
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.
A little explanation: there are few more classes, which I use this way (binding params to properties and storing functionality inside same class), so I don't really want to add each method Get() additional parameter for IConfiguration.
How am I supposed to do this properly? Am I missing something? Or It's just don't work this way?
I'm sorry if I use any of terminology wrong, would be glad if you point me the wrong stuff. Thanks.
CodePudding user response:
It's a great question. You're on the right track.
In my opinion, the ReportModel simply shouldn't use dependency injection. The model should just be a property bag that models the incoming parameters.
Have logic be performed in a controller action (or otherwise handled some other way).
CodePudding user response:
How am I supposed to do this properly? Am I missing something? Or It's just don't work this way?
It doesn't work that way.
First of all, models are not supposed to have dependencies injected, they are just a class for getting the input from the request.
This is also wrong, though: ... GetReport(ReportModel model). This relies on the fact that ASP.NET Core injects a new ReportModel by default - if this behavior changes, your code magically stops working.
Your code should look like this instead:
public class ReportsController
{
private readonly IReportModelService _reportModelService;
public ReportsController(IReportModelService reportModelService)
{
_reportModelService = reportModelService;
}
[HttpGet]
public IActionResult GetReport()
{
return new JsonResult(_reportModelService.GetReport());
}
}
Along with an appropriate class that builds the report, something like:
public class ReportModelService: IReportModelService
{
private readonly IConfiguration _configuration;
public ReportModelService(IConfiguration configuration)
{
_configuration = configuration;
}
public string GetReport()
{
// your logic here
}
}
CodePudding user response:
default DI container that is used in net core can only inject dependency inside of the constructor, in this case a controller constructor, not inside of an action, since action doesn't have a constructor. So change your code like this
public class ReportController
{
private readonly ReportModel _model
public ReportController(ReportModel model )
{
_model=model;
}
[HttpGet]
public JsonResult GetReport()
{
return new JsonResult( new { _model.Get().ToString() });
}
}
and don't forget to add DI to the startup
services.AddScoped<ReportModel>();
