Estoy creando una vista parcial para una barra lateral que mostrará las publicaciones más populares en mi sitio. ¿Cómo puedo crear un controlador separado para cargar el modelo requerido por la vista parcial? (El IEnumerable<Post> con las publicaciones populares)
Actualmente, he creado una clase de controlador que carga las publicaciones populares, pero sigo recibiendo errores al representar el parcial, ya que no puedo llamar al controlador y cargar el modelo parcial. Por ejemplo, si lo llamo desde una vista donde renderizo una sola publicación, los tipos de modelos no coincidirán ( Publicación vs Post IEnumerable<Post> )
Este es mi SidebarController :
using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using GoBaron.Front.Models; namespace GoBaron.Front.Controllers { public class SidebarController : Controller { private readonly ApplicationDbContext _context; public SidebarController(ApplicationDbContext context) { _context = context; } public async Task<IActionResult> PopularPosts() { return PartialView(await _context.Posts .Where(p => p.IsActive == true) .OrderByDescending(p => p.Id) .Take(5) .ToListAsync()); } } } Y esta es mi vista parcial PopularPosts.cshtml :
@model IEnumerable<GoBaron.Front.Models.Post> @using GoBaron.Front.Data.Extensions @if (Model.Any()) { <div class="sidebar-item" id="topTrending"> <header class="sidebar-item__header"> <h1>Najpopularniejsze</h1> </header> <div class="sidebar-item__content"> @foreach (var item in Model) { <a asp-controller="Post" asp-action="Details" asp-route-id="@item.Id" asp-route-slug="@item.Title.ConvertToSlug()" title="@item.Title"> <div class="sidebar-post-item" style="background-image:url('@item.PosterUrl')"> <span class="sidebar-post-item__counter">+5</span> <span class="sidebar-post-item__title">@item.Title</span> </div> </a> } </div> </div> }Cuando quiero incluir la barra lateral de publicaciones populares, por ejemplo, en el diseño, solo agrego:
@await Html.PartialAsync("~/Views/Sidebar/PopularPosts.cshtml")Este es un buen caso de uso para un componente de vista en lugar de una vista parcial. No solo necesita representar una vista, también necesita ejecutar ese poco de lógica que carga las Publicaciones populares desde la base de datos.
En lugar de un controlador, cree una nueva clase ViewComponent . Contiene la lógica que prepara el modelo para el componente de vista en su método InvokeAsync y podría tomar cualquier número de parámetros. En su caso, InvokeAsync no toma parámetros, cargará las publicaciones populares de la base de datos y mostrará la vista del componente de vista:
public class PopularPostsViewComponent: ViewComponent { private readonly ApplicationDbContext _context; public PopularPostsViewComponent(ApplicationDbContext context) { _context = context; } public async Task<IViewComponentResult> InvokeAsync() { var posts = await _context.Posts .Where(p => p.IsActive == true) .OrderByDescending(p => p.Id) .Take(5) .ToListAsync(); return View(posts); } } Ahora necesita crear la vista para ese componente de vista. El nombre de vista predeterminado Default.cshtml (como cuando return View() sin especificar un nombre de vista) y debe estar ubicado en Views/Shared/Components/PopularPosts/Default.cshtml . Esto será básicamente lo mismo que su vista parcial actual:
@model IEnumerable<GoBaron.Front.Models.Post> @using GoBaron.Front.Data.Extensions @if (Model.Any()) { <div class="sidebar-item" id="topTrending"> <header class="sidebar-item__header"> <h1>Najpopularniejsze</h1> </header> <div class="sidebar-item__content"> @foreach (var item in Model) { <a asp-controller="Post" asp-action="Details" asp-route-id="@item.Id" asp-route-slug="@item.Title.ConvertToSlug()" title="@item.Title"> <div class="sidebar-post-item" style="background-image:url('@item.PosterUrl')"> <span class="sidebar-post-item__counter">+5</span> <span class="sidebar-post-item__title">@item.Title</span> </div> </a> } </div> </div> } Luego, desde cualquier otra vista, renderizaría su componente de vista en lugar de uno parcial, pasando los parámetros requeridos por InvokeAsync . En tu caso no tomas parámetros por lo que será:
@await Component.InvokeAsync("PopularPosts")Finalmente, si está en .Net Core 1.1 o superior, también puede invocarlo como asistente de etiquetas:
<vc:popular-posts></vc:popular-posts>PD. Escribí un artículo que describe los usos de parciales, ayudantes de etiquetas y componentes de vista que pueden resultarle interesantes.