2017-03-16 79 views
4

我正在爲側邊欄創建部分視圖,該視圖將顯示我網站中最受歡迎的帖子。我如何創建一個單獨的控制器來加載部分視圖所需的模型? (IEnumerable<Post>與熱門帖子)具有局部視圖的ASP.NET核心控制器

目前我已經創建了一個控制器類加載流行的帖子,但我不斷收到錯誤時呈現部分,因爲我不能調用控制器和加載部分模型。例如,如果我把它從我呈現一個立柱的觀點,模型類型不匹配(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") 

回答

7

對於View Component而不是局部視圖,這是一個很好的用例。你不僅需要渲染一個視圖,還需要執行那些從數據庫加載熱門帖子的邏輯。

而不是控制器,創建一個新的ViewComponent類。這包含爲InvokeAsync方法中的視圖組件準備模型的邏輯,它可以採用任意數量的參數。在你的情況InvokeAsync不帶任何參數,將加載從DB的熱門帖子,將渲染視圖組件視圖:

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所需的任何參數。在你的情況,你不帶任何參數,因此將是:

@await Component.InvokeAsync("PopularPosts") 

最後,如果你是在對.NET核心1.1或更高版本,你也可以調用它作爲一個標籤幫手:

<vc:popular-posts></vc:popular-posts> 

PS 。我寫了一個article,描述了你可能會感興趣的partials,標籤助手和視圖組件的用法。

+0

我想做一個web api調用來獲取數據並將其顯示在網頁的一部分中,但我不希望這會延遲加載頁面的其餘部分。這種使用invokeasync的視圖組件的解決方案是否實現了這一點?或者,我唯一的解決方案就是使用某種Javascript,比如React.js? – Primico

相關問題