【问题标题】:How do you build a Single Page Interface in ASP.NET MVC?如何在 ASP.NET MVC 中构建单页界面?
【发布时间】:2009-10-15 17:18:16
【问题描述】:

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

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

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

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

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

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

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

PS:我正在 Visual Web Developer 2008 Express Edition 中进行开发,并安装了 MVC 1.0,使用 C#

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

$("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 调用创建一个新的路由模式是一个好习惯,它只会返回部分页面? (我还没有研究这么多。)

[编辑2] 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);
}

【问题讨论】:

  • 您是否要求由同一路线定义的CRUD?即localhost/Admin,该页面将允许您创建、读取、更新和删除管理员,而无需执行 /Admin/Create?
  • 不,我想知道在 ASP.NET 中使用 SPI 的“最佳实践”是什么。并不是什么具体的东西,而是如何开始使用该技术 (SPI) 构建 web 应用程序。但是,当我要求 CRUD 的情况下,您似乎已经准备好了答案? :)

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


【解决方案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】:

    嗯,你可以通过 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();
        }
    

    【讨论】:

    • 嗨,谢谢,但是这实际上获取了整个页面,其中显示了部分视图。请参阅上面的编辑我如何解决它以及我的新问题:你知道我必须如何修改控制器或其他任何东西来打印仅部分视图吗?
    【解决方案3】:

    我们有一个网站可以做到这一点,你真的想在这里使用 jQuery 路由——从长远来看更容易实现。对于没有启用 javascript 的用户(例如 google),您可以轻松地使其优雅降级。

    【讨论】:

    • 能否详细说明优雅的降级?我猜在这种情况下,用户会访问像 /Home/About 这样的 URL,但使用 AJAX 他们只会获取页面的一部分。您使用 AJAx 获取的 URL 是否与优雅降级的 URL 相同,或者您是否为 AJAX 使用其他 URL(例如 /Ajax/Home/About)?否则,您将获取的不是一部分,而是整个页面。 (另见我上面的编辑。)
    • 这个应用程序的结果是它是同一个 URL。 Javascript 请求将其剥离到窗口“窗格”,而完整请求获取页面。并且直接链接到 /#section/page 也有效。并且后退按钮起作用了。我认为完成大部分巫术的图书馆称为 jquery.jframe。
    【解决方案4】:

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

    【讨论】:

      【解决方案5】:

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

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

      更新: ...他们从 MVC 4 RC 中删除了它

      更新: ...随着 2012 年秋季更新,它又回来了

      【讨论】:

        猜你喜欢
        • 2015-09-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多