At first I'd like to say I'm new to Asp.net Core and also with concepts of dependency injection (DI). I'm reading a lot trying understand it, so I ask for patience.
I'm trying Razor Pages (not MVC) and my goal is to render to "_layout.cshtml" a partial view, in which information obtained using the Entity Framework is available on all pages.
I added the DBContext in the Startup.cs file as follows:
services.AddDbContext <AppDBContext> (options =>
options.UseSqlServer (Configuration.GetConnectionString ("AppDBContext")
And in "PageModel" for MenuPartial.cshtml.cs
public class MenuPartialModel: PageModel
{
private readonly AppDBContext _db;
public MenuPartialModel (AppDBContext db)
{
_db = db;
}
}
In the _layout.cshtm file I tried several ways to call PartialAsync with the instance of a new model:
If set new instance model like bellow I'll be using constructor without parameters, therefore the DbContext is not injected
@await Html.PartialAsync ("MenuPartial", new MenuPartialModel ())
And I also thought about using:
@await Html.PartialAsync ("MenuPartial", new MenuPartialModel (new AppDBContext ())
I believe that wouldn't be a correct approach. Because if the DbContext was injected automatically, why should I perform a new instance by passing connection parameters again?
What would be the best approach to achieve my goal? I thought about using ViewComponents, however, at first I would like to understand if there is any way to instantiate a model and use the constructor that injects the DBContext.
I would like to understand if there is any way to instantiate a model and use the constructor that injects the DBContext.
In ASP.NET Core MVC, plain old CLR classes (POCOs) do not participate in ASP.NET Core Dependency Injection. The MenuPartialModel
is a POCO (as are most MVC models). As a result, the framework will not automatically inject dependencies into it.
Some built-in ASP.NET Core MVC classes are wired into the dependency injection. These include (but are not limited to):
The canonical approach in MVC is to inject dependencies (aka services) into one of those, and then to pass any data manually to the POCO model.
What would be [a good] approach to achieve my goal?
Instead of Partial View, I would use a View Component. A view component is like a partial view that has a model, a view, and a controller.
The controller is InvokeAsync
, which isn't exposed to HTTP, but it is still a controller in the traditional sense, because it is responsible for binding the model to the view.
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using MyApplication.Data;
public class MenuModel
{
public string MyProperty { get; set; }
public string MyOtherProperty { get; set; }
}
public class MenuViewComponent : ViewComponent
{
private readonly ApplicationDbContext dbContext;
public MenuViewComponent(ApplicationDbContext dbContext)
{
this.dbContext = dbContext;
}
public async Task<IViewComponentResult> InvokeAsync()
{
var data = await dbContext...
var model = new MenuModel
{
MyProperty = data.FirstValue,
MyOtherProperty = data.OtherValue,
};
return View(model);
}
}
You will also need a Razor file at one of these locations to act as the view.
/Pages/Shared/Components/Menu/Default.cshtml
/Views/Shared/Components/Menu/Default.cshtml
That Default.cshtml
file will contain something like this:
@model MenuModel
<p>@Model.MyProperty</p>
<p>@Model.MyOtherProperty</p>
@await Component.InvokeAsync("Menu")
Out of the box, View Components are not exposed to HTTP. To access them via AJAX, we need to add an ASP.NET Core MVC Controller to reach them.
[Route("component/[action]")]
public class ViewComponentController : Controller
{
// ~/component/menu
public IActionResult Menu() => ViewComponent("Menu");
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With