在渲染局部视图时如何调用控制器操作?

Del*_*vor 5 c# asp.net-core-mvc asp.net-core

我正在为侧边栏创建部分视图,以显示我网站中最受欢迎的帖子.如何创建用于加载局部视图所需模型的独立控制器?(IEnumerable<Post>随着热门帖子)

目前我已经创建了一个加载流行帖子的控制器类,但是在渲染部分时我一直遇到错误,因为我无法调用控制器并加载部分模型.例如,如果我从我呈现单个帖子的视图中调用它,则模型类型将不匹配(Postvs IEnumerable<Post>)

这是我的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());
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这是我的部分观点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>
}
Run Code Online (Sandbox Code Playgroud)

当我想要包含热门帖子侧边栏时,例如在布局中,我只需添加:

@await Html.PartialAsync("~/Views/Sidebar/PopularPosts.cshtml")
Run Code Online (Sandbox Code Playgroud)

Dan*_*.G. 17

这是View Component的一个很好的用例,而不是局部视图.您不仅需要渲染视图,还需要执行从db加载Popular Posts的逻辑.

而不是Controller,创建一个新ViewComponent类.这包含在其InvokeAsync方法中为视图组件准备模型的逻辑,它可以使用任意数量的参数.在你的情况下InvokeAsync没有参数,将从数据库加载流行的帖子,并将呈现视图组件视图:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,您需要为该视图组件创建视图.默认视图名称Default.cshtml(如果return View()没有指定视图名称时),它应该位于Views/Shared/Components/PopularPosts/Default.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>
}
Run Code Online (Sandbox Code Playgroud)

然后从任何其他视图,您将渲染视图组件而不是部分,传递所需的任何参数InvokeAsync.在你的情况下,你没有参数,所以它将是:

@await Component.InvokeAsync("PopularPosts")
Run Code Online (Sandbox Code Playgroud)

最后,如果您使用的是.Net Core 1.1或更高版本,您还可以将其作为标记帮助程序调用:

<vc:popular-posts></vc:popular-posts>
Run Code Online (Sandbox Code Playgroud)

PS.我写了一篇文章,描述了您可能感兴趣的部分,标记助手和视图组件的用法.

  • 我想进行网络api调用以取回数据并将其显示在网页的一部分中,但是我不希望这延迟加载页面的其余部分。将视图组件与invokeasync结合使用的解决方案能否实现这一目标?还是我唯一使用某种Javascript(例如React.js)的解决方案? (2认同)