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

时间:2017-03-16 22:23:23

标签: c# asp.net-core asp.net-core-mvc

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

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

这是我的部分观点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>
}

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

@await Html.PartialAsync("~/Views/Sidebar/PopularPosts.cshtml")

1 个答案:

答案 0 :(得分:15)

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

创建一个新的$('#line').remove(); $('#chart_container').append('<canvas id="line" height="600px" style="margin-top:20px;" ></canvas>'); 类,而不是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); } } (与您在未指定视图名称的情况下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> } 所需的任何参数。在你的情况下,你没有参数,所以它将是:

InvokeAsync

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

@await Component.InvokeAsync("PopularPosts")

PS。我写了一篇article来描述你可能感兴趣的部分,标记助手和视图组件的用法。