通过 AJAX 请求返回局部视图的 ASP.NET Core 策略 [英] ASP.NET Core strategy for returning partial views via AJAX requests

查看:22
本文介绍了通过 AJAX 请求返回局部视图的 ASP.NET Core 策略的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个 ASP.NET Core 5 Web 应用程序,想知道对部分视图和普通视图使用什么策略.

因此,例如,当用户在 Web 浏览器中导航到 /bars 时,我想加载带有 Bar 列表(连同菜单)的页面、页眉、页脚和其他共享布局元素).

然而,如果用户点击Bars菜单,我只想重新加载主容器(没有菜单、页眉、页脚等).

Controller 中,我应该为每个带有 PartialAction 的页面创建一个 Action,像这样:

public async Task指数(){返回视图(await _repository.ListAsync());}公共异步任务索引部分(){返回 PartialView(await _repository.ListAsync());}

然后用/Bar/IndexPartial调用菜单上的AJAX,把main action留给普通视图?相关,我应该为每个动作创建单独的视图吗?

解决方案

这是一个有趣的问题!您为每个页面公开一个操作并为该页面的内部内容返回 PartialViewResult 的一般方法对我来说很有意义.

如果完整视图和部分视图之间的唯一区别是公共元素,那么我会寻找集中入口点视图的方法 - 如果不是入口点操作本身 - 否则他们会去变得非常重复.

下面,我将介绍处理主要入口点的基本策略.

<块引用>

注意:鉴于问题的性质,我假设您很乐意实现 AJAX 部分,而只专注于服务器端建筑,我相信这是您问题的核心.显然,现有的答案解决了客户端实现问题(如果这很重要的话).

查看模型

首先,您可以建立一个处理整个页面内容的通用视图模型.这可能包括属性,例如您的导航项目.但它也会包含(部分)视图的名称以及该视图的视图模型,因为您可能需要这些来预渲染内部内容:

公共类 PageViewModel{…公共字符串视图{获取;放;}公共对象 ViewModel { 获取;放;}}

然后每个页面都有单独的视图模型,例如:

公共类 BarListViewModel{公共收藏<酒吧>酒吧{得到;} = 新();}

控制器

现在,在您的控制器中,您将引入一个建立 BarListViewModel 的方法,这样您就无需在入口点和返回的操作之间重复您的逻辑部分视图:

[NonAction]公共 BarListViewModel GetBarListViewModel(){var viewModel = new BarListViewModel(){酒吧 = …};返回视图模型;}

有了这个,您现在可以有一个操作来提供您的 Bars 页面,类似于您提出的:

public IActionResult Bars() =>PartialView(GetBarListViewModel());

但是,与其为每个部分使用不同的 Index 操作,您还可以使用以下内容

public IActionResult Index(Page page = "Home"){var viewModel = 新的 PageViewModel{View = page.ToString(),ViewModel = 页面切换{酒吧"=>GetBarListViewModel(),_ =>获取默认视图模型()}};返回视图(索引",视图模型);}

这提供了一个单一的调度"来连接任何入口点,而无需为每个入口点创建一个新的动作或视图.

查看

最后,在您的 Index.cshtml 中,您将使用以下内容根据视图模型动态注入正确的局部视图:

@model PageViewModel…<主要>@await Html.PartialAsync(Model.View, Model.ViewModel)</main>…

那会加载一个例如Bars.cshtml 包含循环遍历 BarListViewModel.Bars 属性的逻辑.

<块引用>

注意:这假设您希望在服务器端预渲染您的部分视图.显然,如果您希望通过 AJAX 进行初始加载,则不需要传递嵌套的 BarListViewModel,或调用 PartialAsync().

路由

据推测,以上将与允许将 page 作为路由参数传入的路由配置配对——甚至可能在默认的 Controller 和入口点的 Action:

app.UseEndpoints(endpoints =>{endpoints.MapControllerRoute(名称:默认",模式:{页面?}",new { 控制器 = 首页",动作 = 索引"});});

<块引用>

注意:显然,您需要小心不要以过于贪婪的路由锁定您的 AJAX 调用或其他入口点.以上只是作为如何捕获page路由参数的基本演示.

结论

这类似于@User1997 提出的方法,但允许他们提出的Index.cshtml 和隐含的 Index() 操作可重用于 所有 入口点.而且,当然,如果您有多个遵循这种模式的控制器,这甚至可以概括为一个基本控制器.

I have an ASP.NET Core 5 web application and would like to know what strategy to use for partial vs. normal views.

So, for example, when a user navigates in the web browser to /bars, I would like to load the page with the Bar list (along with the menu, headers, footer, and other shared layout elements).

However, if the user clicks on the Bars menu, I would like to reload only the main container (without the menu, headers, footer, etc.).

In the Controller, should I create an Action for each page with a PartialAction, like this:

public async Task<IActionResult> Index()
{
    return View(await _repository.ListAsync<T>());
}
    
public async Task<IActionResult> IndexPartial()
{
    return PartialView(await _repository.ListAsync<T>());
}

And then call the AJAX on the menu with /Bar/IndexPartial, leaving the main action for the normal view? Related, should I create separate views for each action?

解决方案

This is an interesting question! Your general approach of exposing an action for each page and returning a PartialViewResult for the inner contents of that page makes good sense to me.

If the only difference between the full view and the partial view is the common elements, however, I'd be looking into ways of centralizing the entry point views—if not the entry point actions themselves—as otherwise they're going to get really repetitive.

Below, I’ll scaffold the basic strategy I’d consider for handling the main entry point.

Note: Given the nature of the question, I’m going to assume you’re comfortable implementing the AJAX portion, and instead focus exclusively on the server-side architecture, which I believe to be at the heart of your question. Obviously, the existing answers address the client-side implementation, if that’s important.

View Models

To begin, you might establish a general view model that handles the overall page content. This might include properties for e.g. your navigation items. But it would also contain the name of the (partial) view as well as the view model for that view, as you’ll likely want these in order to pre-render the inner content:

public class PageViewModel 
{
    …
    public string View { get; set; }
    public object ViewModel { get; set; }
}

You'd then have individual view models for each page, such as:

public class BarListViewModel 
{
    public Collection<Bar> Bars { get; } = new();
}

Controller

Now, in your controller, you’ll introduce a method that establishes a BarListViewModel, so that you don’t need to repeat your logic between both your entry point as well as the actions which return a partial view:

[NonAction]
public BarListViewModel GetBarListViewModel() 
{
    var viewModel             = new BarListViewModel() 
    {
        Bars                  = …
    };
    return viewModel;
}

With that, you can now have an action that delivers your Bars page, similar to what you proposed:

public IActionResult Bars() => PartialView(GetBarListViewModel());

But, instead of having a different Index action for each partial, you could instead have something like the following

public IActionResult Index(Page page = "Home") 
{
    var viewModel = new PageViewModel 
    {
        View = page.ToString(),
        ViewModel = page switch 
        {
            "Bars" => GetBarListViewModel(),
            _ => GetDefaultViewModel()
        }
    };
    return View("Index", viewModel);
}

This provides a single "dispatch" for wiring up any entry point, without needing to create a new action or view for each one.

View

Finally, in your Index.cshtml, you'd have something like the following to dynamically inject the correct partial view based on the view model:

@model PageViewModel

…
<main>
  @await Html.PartialAsync(Model.View, Model.ViewModel)
</main>
…

That would load an e.g. Bars.cshtml which would contain the logic for looping through the BarListViewModel.Bars property.

Note: This assumes you want to prerender your partial view on the server side. Obviously, if you want the initial load to occur via AJAX, you wouldn’t need to pass the nested BarListViewModel, or call PartialAsync().

Routing

Presumably, the above would be paired with a route configuration that would allow the page to be passed in as a route parameter—possibly even baking in a default Controller and Action for your entry point:

app.UseEndpoints(endpoints => 
{
    endpoints.MapControllerRoute(
        name: "default",
        pattern: "{page?}", 
        new { controller = "Home", action = "Index" }
    );
});

Note: Obviously, you’ll need to be careful not to lock out your AJAX calls or other entry points with an overly greedy route. The above is just intended as a basic demonstration of how to capture the page route parameter.

Conclusion

This is similar to the approach proposed by @User1997, but it allows their proposed Index.cshtml and implied Index() action to be reused for all of your entry points. And, of course, if you had multiple controllers that followed this pattern, this could even be generalized as a base controller.

这篇关于通过 AJAX 请求返回局部视图的 ASP.NET Core 策略的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆