How can I call a controller action when rendering a partial view?

荒凉一梦 提交于 2019-12-01 18:22:22

This is a good use case for a View Component instead of a partial view. You not only need to render a view, you also need to execute that bit of logic that loads the Popular Posts from the db.

Instead of a Controller, create a new ViewComponent class. This contains the logic that prepares the model for the view component in its InvokeAsync method, and it could take any number of parameters. In your case InvokeAsync takes no parameters, will load the popular posts from the db and will render the view component view:

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);
    }
}

Now you need to create the view for that view component. The default view name Default.cshtml (as when you do return View() without specifying a view name) and it should be located in Views/Shared/Components/PopularPosts/Default.cshtml. This will basically be the same as your current partial view:

@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>
}

Then from any other view, you would render your view component instead of a partial, passing any parameters required by InvokeAsync. In your case you take no parameters so it will be:

@await Component.InvokeAsync("PopularPosts")

Finally, if you are in .Net Core 1.1 or higher, you can also invoke it as a tag helper:

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

PS. I wrote an article describing usages for partials, tag helpers and view components that you might find interesting.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!