如何在ASP.NET MVC中构建单页面界面?

时间:2009-10-15 17:18:17

标签: ajax asp.net-mvc partial-views single-page-application

我想使用ASP.NET MVC构建一个带有“单页面界面”的Web应用程序。

我已经搜索过这是否至少是可能的,我认为答案是:不是通过简单的方法(阅读http://msdn.microsoft.com/en-us/magazine/cc507641.aspx#S2倒数第二段;那篇文章是从2008年5月开始的。)

我找到了其他通过jQuery编码/黑客实现这一点的例子。但是,如果可能的话,我正在寻找一种干净的解决方案,使用标准的.NET方法。

当您创建新的“MVC Web应用程序”时,我想要的是完全相同的功能。但是,我没有链接到重新加载整个页面的“/ Home / About”,而是希望链接到“ Home / About”,它只通过AJAX加载新部分。

使用Html.RenderPartial调用模板(部分视图)的标准方法正是我想要的,然后才通过AJAX请求加载它们。

当然,可能由于某种原因,我不能使用由主页面呈现的这些模板(也许它总是在特定的上下文中被调用地点左右)。但也许还有另一个干净的解决方案,用于如何构建模板页面并从主页面中获取它们。

谁有一个很好的解决方案来实现这样的东西,单页面界面?

PS:我正在使用C#

开发安装了MVC 1.0的Visual Web Developer 2008 Express Edition

[编辑] 下面我读到使用模板是可能的,并且jQuery看起来确实不可避免,所以我测试了它。 下面的代码将Html.ActionLink创建的常规链接转换为锚链接(带#)以包含历史记录,然后通过AJAX获取页面并仅注入我感兴趣的html部分(即div中的部分页面# partialView):

$("a").each(function() {
    $(this).click(function() {
        $("div#partialView").load($(this).attr("href") + " div#partialView");
        location.hash = $(this).attr("href");
        return false;
    });
});

这些链接也允许优雅的降级。

但是我现在剩下的,仍然是取出整个页面,而不仅仅是部分页面。改变控制器没有帮助;它仍然提供了整个页面的html,以及所有这些陈述:

public ActionResult About()
{
    return View();
    return View("About");
    return PartialView();
    return PartialView("About");
}

我怎样才能返回我感兴趣的部分的内容(即Home / About.aspx的内容)? 我想要的是用AJAX发布一个值(例如“requesttype = ajax”),以便我的控制器知道页面是通过AJAX获取的,只返回部分页面;否则它将返回整个页面(即当你访问/ Home / About而不是#Home / About)时。

改变Global.asax.cs是一个很好的做法,为AJAX调用创建一个新的路由模式,只会返回部分页面? (我还没有考虑过这么多。)

[EDIT2] 的 Robert Koritnik是对的:我还需要一个About.ascx页面(UserControl),只有该页面的小HTML内容。 About.aspx的第一行通过MasterPageFile="~/..../Site.master"与主页链接,导致所有HTML都被打印出来。

但是为了能够在我的控制器中执行以下操作:

public ActionResult About()
{
    return Request.IsAjaxRequest() ? (ActionResult)PartialView() : View();
}

我需要改变找到PartialView(。ascx文件)和View(。aspx)文件的方式,否则两种方法都会返回相同的页面(About.aspx,最终导致无限循环)。 将以下内容放入Global.asax.cs后,将使用PartialView()View()返回正确的网页:

protected void Application_Start()
{
    foreach (WebFormViewEngine engine in ViewEngines.Engines.Where(c => c is WebFormViewEngine))
    {
        /* Normal search order:
        new string[] { "~/Views/{1}/{0}.aspx",
            "~/Views/{1}/{0}.ascx",
            "~/Views/Shared/{0}.aspx"
            "~/Views/Shared/{0}.ascx"
        };
        */

        // PartialViews match with .ascx files
        engine.PartialViewLocationFormats = new string[] { "~/Views/{1}/{0}.ascx", "~/Views/Shared/{0}.ascx" };

        // Views match with .aspx files
        engine.ViewLocationFormats = new string[] { "~/Views/{1}/{0}.aspx", "~/Views/Shared/{0}.aspx" };
    }

    RegisterRoutes(RouteTable.Routes);
}

5 个答案:

答案 0 :(得分:1)

好吧,您可以通过AJAX请求加载部分视图。在示例中,我将使用jquery进行ajax调用。

这些可能是控制器中的动作(名为HomeController):

public ActionResult About()
    {
        //Do some logic...
        //AboutView is the name of your partial view
        return View("AboutView");
    }

JQuery ajax调用将已撤销的html放置到您想要的位置:

var resultDiv = $('#contentDIV');

    $.ajax({
        type: "POST",
        url: "/Home/About",
        success: function(responseHTML) {
            resultDiv.replaceWith(responseHTML);
        }
    });

[编辑问题已更新]

可以完全按照自己的意愿行事。第一个控制器动作可以返回局部视图,因此我的“AboutView”可能是这样的:

<table>
<tr>
    <th>
        Column1Header
    </th>
    <th>
        Column2Header
    </th>
</tr>
<tr>
    <td>
    ...
    </td>
    <td>
    ...
    </td>
</tr>

这个HTML正是你在jquery ajax方法中成功处理程序的responseHTML中所拥有的。

其次,如果请求是ajax请求,您可以区分控制器操作:

public ActionResult About()
    {
        //partial AboutView is returned if request is ajax
        if (Request.IsAjaxRequest())
            return View("AboutView");
        else //else it will be the default view (page) for this action: "About"
            return View();
    }

答案 1 :(得分:1)

完整视图与部分视图

好像你搞砸了什么。如果您创建一个About.aspx页面,其中包含显示整个页面所需的所有HTML,那么如果您说

则无关紧要
return PartialView('About');

视图仍然会返回写在其中的所有HTML。

您应该创建一个单独的 About.ascx ,该页面内容只包含页面内容,而不包含整个页面中的标题和其他内容。

您的原始网页About.aspx在其内容中会有类似内容(以避免重复编写相同的内容两次):

<%= Html.RenderPartial("About") %>

你可以有两个控制器动作。一个返回常规视图,另一个返回局部视图:

return View("About"); // returns About.aspx that holds the content of the About.ascx as well
return PartialView("About"); // only returns the partial About.ascx

关于Global.asax

中的路线

不是为Ajax调用编写单独的路由,而是编写一个与AcceptVerbsAttribute动作过滤器类似的动作过滤器。这样来自客户端的请求将保持不变(从而阻止用户手动请求错误的东西),但根据请求类型,将执行正确的控制器操作。

答案 2 :(得分:0)

我们有一个网站正是这样做的,你真的想在这里使用jQuery路由 - 从长远来看很容易实现。对于没有启用javascript的用户(例如google),您可以轻松地让它降级。

答案 3 :(得分:0)

您要求的内容并不是那么清楚,是完整的示例还是某些特定的功能?对于简单的场景,您应该能够在没有JQuery的情况下执行此操作,您可以使用Ajax视图助手,如ActionLink方法。另外,我真的不明白你在使用RenderPartial时遇到了什么问题,但也许你正在寻找类似于ASP.NET MVC Futures的RenderAction。

答案 4 :(得分:0)

ASP.NET MVC 4(现在处于测试阶段)增加了对MVC中单页应用程序的支持。

http://www.asp.net/single-page-application

更新: ......他们将它从MVC 4 RC中移除

更新: ......它又回到了2012秋季更新