MVC 3:如何在通过ajax加载时呈现不带布局页的视图?

156

我正在学习渐进增强,对于使用AJAX化视图有些疑问。在我的MVC 3项目中,我有一个布局页面、一个viewstart页面和两个普通的视图。

viewstart页面位于Views文件夹的根目录,因此适用于所有视图。它指定所有视图都应该使用_Layout.cshtml作为它们的布局页面。布局页面包含两个导航链接,一个用于每个视图。这些链接使用@Html.ActionLink()来呈现到页面上。

现在我添加了jQuery,并想劫持这些链接,并使用Ajax动态地加载它们的内容到页面上。

<script type="text/javascript">
    $(function () {
        $('#theLink').click(function () {
            $.ajax({
                url: $(this).attr('href'),
                type: "GET",
                success: function (response) {
                    $('#mainContent').html(response);
                }
            });
            return false;
        });
    });
</script>

我能想到两种方法来实现这个功能,但是我都不是很喜欢:

1)我可以将整个视图的内容放在一个部分视图中,然后在主视图呈现时调用该部分视图。通过在控制器中使用Request.IsAjaxRequest(),我可以根据请求是否为Ajax请求返回View()PartialView()。我不能将常规视图返回给Ajax请求,因为那样会使用布局页面,并且会注入第二个复制的布局页面。但是,我不喜欢这个方法,因为它强制我创建空视图,只有一个@{Html.RenderPartial();}

    public ActionResult Index()
    {
        if (Request.IsAjaxRequest())
            return PartialView("partialView");
        else
            return View();
    }

然后在Index.cshtml中做如下操作:

@{Html.RenderPartial("partialView");}

2)我可以从_viewstart中删除布局指定,并在请求不是 Ajax 时手动指定它:

    public ActionResult Index()
    {
        if (Request.IsAjaxRequest())
            return View(); // Return view with no master.
        else
            return View("Index", "_Layout"); // Return view with master.
    }

有没有更好的建议?有没有一种方法可以返回一个视图而不包括它的布局页面?如果是ajax请求,明确地说“不包括布局”会更容易,而如果不是ajax请求,则明确地包括布局会更容易。

7个回答

260

~/Views/ViewStart.cshtml中:

@{
    Layout = Request.IsAjaxRequest() ? null : "~/Views/Shared/_Layout.cshtml";
}

在控制器中:

public ActionResult Index()
{
    return View();
}

3
这个能在viewstart中指定吗? - Chev
11
@Matt Greer,你觉得它难看,我认为它DRY(Don't Repeat Yourself),不过这种感受因人而异 :-) - Darin Dimitrov
2
我必须承认,一开始我并不喜欢它,但是它节省的代码量似乎远远超过了它的缺点。它只是一个简单的布尔值if语句,在我的看法中并没有太多的限制。我比每次都要将我的动作方法分成两半更喜欢它。此外,它还可以防止我像Matt所说的那样潜在地走下两个巨大的逻辑路径。我要么编写相同的操作以在两种情况下工作,要么编写一个新的操作。 - Chev
2
我想我可以这样做,但是为什么要为一个小小的代码行创建一个baseController呢? - Chev
1
@Shimmy,是的,有一种方法,您可以使用View方法的适当重载,在返回ViewResult时指定布局。 - Darin Dimitrov
显示剩余8条评论

93

只需将以下代码放在页面顶部即可

@{
    Layout = "";
}

4
这不起作用,因为我希望能够基于是否通过AJAX请求来请求布局来切换布局的开启或关闭。这只允许你关闭布局,而不能切换它。 - Chev
4
为什么这个帖子有点赞?请解释一下,这样我也可以给它点赞。 - Usman Younas
1
@UsmanY。你不需要给它投票,但我需要。我的论点在 https://www.google.com.pk/#q=mvc3%20view%20without%20layout 。这是对该查询的完美答案。 - Sami
3
主题是切换两种不同情况下的布局。这个答案无论情况如何都将布局设置为空。 - Rajshekar Reddy
这可能并不回答OP的问题,但我仍然点赞了它,因为它回答了我需要回答的问题。 - Sam I am says Reinstate Monica
显示剩余3条评论

13

你只需要创建两个布局:

  1. 一个空的布局

  2. 主要的布局

然后在_viewStart文件中编写以下代码:

@{
   if (Request.IsAjaxRequest())
   {
      Layout = "~/Areas/Dashboard/Views/Shared/_emptyLayout.cshtml";
   }
   else
   {
      Layout = "~/Areas/Dashboard/Views/Shared/_Layout.cshtml";
   }
 }

当然,也许这不是最佳方案


13

我更喜欢并使用你的第一种选择。我不喜欢第二种选择,因为对我来说 View() 意味着你要返回一个完整的页面。在视图引擎完成后,它应该是一个完全成形且有效的 HTML 页面。 PartialView() 是用来返回任意一部分 HTML 的。

我认为仅仅只有一个视图调用了一个部分视图不是什么大问题。这仍然符合 DRY 原则,并允许您在两种场景下使用部分视图的逻辑。

很多人不喜欢在他们的操作调用路径中加入 Request.IsAjaxRequest(),我能理解这点。但是,在我看来,如果你只需要决定是否调用 View()PartialView(),那么这个分支就不是什么大问题,而且易于维护(和测试)。如果你发现自己使用 IsAjaxRequest() 来决定操作的大部分内容,则创建一个单独的 AJAX 操作可能会更好。


9
你不需要为此创建一个空视图。
在控制器中:
if (Request.IsAjaxRequest())
  return PartialView();
else
  return View();

返回PartialViewResult将在呈现响应时覆盖布局定义。

2

在ASP.NET 5中,不再使用Request变量。现在可以通过Context.Request进行访问。

此外,不再存在IsAjaxRequest()方法,您需要自己编写它,例如在Extensions\HttpRequestExtensions.cs中。

原始答案:Original Answer

using System;
using Microsoft.AspNetCore.Http;

namespace Microsoft.AspNetCore.Mvc
{
    public static class HttpRequestExtensions
    {
        public static bool IsAjaxRequest(this HttpRequest request)
        {
            if (request == null)
            {
                throw new ArgumentNullException(nameof(request));
            }

            return (request.Headers != null) && (request.Headers["X-Requested-With"] == "XMLHttpRequest");
        }
    }
}

我在这个问题上搜索了一段时间,希望能对其他人有所帮助 ;)

资源: https://github.com/aspnet/AspNetCore/issues/2729

最初的回答:


-5
在 Ruby on Rails 应用程序中,我可以通过在控制器操作中指定 render layout: false 来防止布局加载,以便响应 ajax html。

6
标签:C# ASP.NET,不是Ruby。 - MrKekson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接