ASP.NET MVC:AJAX调用的控制器是应该返回JSON还是渲染html?

时间:2009-05-27 18:04:58

标签: asp.net-mvc json

我无法确定AJAX调用的控制器操作是应返回部分视图还是“原始”JSON。

返回部分视图,使用呈现的HTML使javascript更容易使用返回的HTML更新当前DOM。但是,它确实限制了使用Web服务的javascript客户端可以对返回的HTML执行的操作。

另一方面,让控制器操作返回JSON将需要javascript调用“手动”根据返回的JSON创建标记。

与往常一样,每种方法都有它的好处和缺点。每种方法都有其他优点/缺点吗?

7 个答案:

答案 0 :(得分:18)

在我看来,返回JSON然后让客户端查看排序可能会因为以下限制而变得混乱:

  1. 没有JavaScript的标准模板语言。在最糟糕的情况下,您会想要连接字符串以形成您需要的HTML。
  2. 没有简单的方法来对您的连接代码生成的HTML进行单元测试。
  3. 您的JavaScript缺乏智能感知意味着您也容易犯更多错误。
  4. 我处理这个的方法是返回渲染的HTML,但是使用局部视图返回这个渲染的HTML。这为您提供了两全其美的体验。您已获得服务器端模板以及IntelliSense支持。

    以下是一个例子:

    这是我的Ajax调用,因为你可以看到它所做的就是替换我的无序列表的html:

    FilterRequests: function() {
        $.post("/Request.aspx/GetFilteredRequests", { }, function(data) {
            $('ul.requests').html(data);
        });
    },
    

    这是我在我的控制器上的动作:

    public ActionResult GetFilteredRequests(string filterJson)
    {
        var requests = _requestDao.LoadAll();
    
        return PartialView("FilteredRequests", requests);
    }
    

    最后这是我的部分视图(没有必要理解这一点,我只是向您展示一些渲染在真实世界的应用程序中会有多复杂。我很害怕在JavaScript中这样做。你也会注意到我的局部视图反过来调用其他部分视图。):

    <%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<IEnumerable<Request>>" %>
    <%@ Import Namespace="Diangy.HelpDesk.Models.Lookups"%>
    <%@ Import Namespace="Diangy.HelpDesk.Models.Requests"%>
    <%@ Import Namespace="System.Web.Mvc.Html"%>
    
    <% foreach (var request in ViewData.Model) %>
    <%{%>
        <li class="request">
            <h2>#<%= request.Id %>: <%= request.InitialInteraction().Description %></h2>
            <p>from <%= request.Customer.FullName %> (<%= request.Customer.EmailAddress %>), <%= request.InitialInteraction().UsableTimeStamp %></p>
    
            <h3>Custom Fields & Lookups</h3>
            <div class="tabs">
                <ul>
                <li><a href="#customfields<%= request.Id %>">Custom Fields</a></li>
                <% foreach (var lookupDefinition in (List<LookupDefinition>)ViewData["LookupDefinitions"]) %>
                <%{%>
                <li><a href="#<%= lookupDefinition.Name.ToLowerInvariant().Replace(" ", "") + request.Id %>"><%= lookupDefinition.Name %></a></li>
                <%}%>
            </ul>
            <% Html.RenderPartial("CustomFields", request); %>
        </div>
    
        <% Html.RenderPartial("Discussion", request); %>
        <% Html.RenderPartial("Attachment", request); %>
        </li>
    <%}%>
    

答案 1 :(得分:16)

如果您正在使用MVC范例,则控制器应返回数据(JSON)并让视图自行对其进行排序,就像它的工作是查找/调整模型中的数据并将其传递给视图一样在服务器端。

你得分为褐色
  • 保持逻辑和UI之间关注点的分离

  • 使你的ajax动作可测试(祝你好运测试从该动作返回的HTML ......)

它可能有点复杂,但它适合。

您可以使用客户端模板系统(例如MS Ajax Toolkit中现有的系统)来帮助消除部分负载并在客户端保留逻辑/呈现分离。

所以我肯定会说JSON。但是,嘿,YMMV像往常一样......

答案 2 :(得分:4)

我想允许调用应用程序来决定。我把MultiViewController(我在网上发现的大部分代码,我会在找到它的时候尝试用信用卡更新)加在一起,基于动作扩展,它将返回相应的格式。例如:

myapp.com/api/Users/1 - defaults to html based on route
myapp.com/api/Users.html/1 - html
myapp.com/api/Users.json/1 - json
myapp.com/api/Users.xml/1 - xml
myapp.com/api/Users.partial/1 - returns a partial view of action name (see code)
myapp.com/api/Users.clean/1 - partial html without styling, etc...

我的控制器继承自MultiViewController而不是“return view(Model);”我只是调用“返回FormatView(Model);或者FormatView(”ViewName“,Model);”。第二个是如果我需要将特定视图应用于结果 - 而不是隐含视图。

MultiViewController看起来像这样。特别注意FormatView,whitch返回一个动作结果:

    public abstract class MultiViewController : Controller
{
    private const string FORMAT_KEY = "format";
    public enum FileFormat {Html, Json, Xml, Partial, Clean}

    protected MultiViewController()
    {
        RequestedFormat = FileFormat.Html;
    }
    protected FileFormat RequestedFormat { get; private set; }

    protected override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        base.OnActionExecuting(filterContext);
        var routeValues = filterContext.RouteData.Values;
        if (routeValues.ContainsKey(FORMAT_KEY))
        {
            var requestedFormat = routeValues[FORMAT_KEY].ToString();
            if (isValidFormat(requestedFormat))
            {
                RequestedFormat = (FileFormat)Enum.Parse(typeof(FileFormat), requestedFormat, true);
            }
        }
    }

    private bool isValidFormat(string requestedFormat)
    {
        return Enum.GetNames(typeof (FileFormat)).Any(format => format.ToLower() == requestedFormat.ToLower());
    }

    protected ActionResult FormatView(string viewName, object viewModel)
    {
        switch (RequestedFormat)
        {
            case FileFormat.Html:
                if (viewName != string.Empty)
                {
                    return View(viewName,viewModel);
                }
                return View(viewModel);
            case FileFormat.Json:
                return Json(viewModel);
            case FileFormat.Xml:
                return new XmlResult(viewModel);
            case FileFormat.Partial:
            //return View(this.ControllerContext.RouteData.Values["action"] + "Partial");
            return PartialView(this.ControllerContext.RouteData.Values["action"] + "Partial");
            case FileFormat.Clean:
                if (viewName != string.Empty)
                {
                    return View(viewName, "~/Views/Shared/Clean.master", viewModel);
                }
                var v = View(viewModel);
                v.MasterName = "~/Views/Shared/Clean.Master";
                return v;
            default:
                throw new FormatException(string.Concat("Cannot server the content in the request format: ", RequestedFormat));
        }
    }
    protected ActionResult FormatView(object viewModel)
    {
        return FormatView("", viewModel);
    }




}

Clean.master只是一个不包含任何其他html的母版页 - 它接受视图(这样我可以合并任何部分类)并使用可以直接放置的干净html呈现它。

如果我想要json - 控制器构建我的viewmodel然后将该视图模型作为json返回,而不是发送到默认视图 - 与.xml相同。

部分视图有点有趣,按照惯例,我的所有主视图都被分解为部分视图,因此可以自己请求特定的部分 - 这对于使用jquery模拟updatepanel的功能非常方便所有与updatepanel相关的垃圾。

答案 3 :(得分:2)

为了保持关注点的分离,你应该返回JSON。

当您返回html时,您可以限制使用返回的数据执行的操作。如果您需要一个数据列表并希望以不同的方式呈现它,请使用JSON,否则您必须在服务器上使用不同的方法来获取相同数据的不同呈现。

答案 4 :(得分:2)

为什么不同时使用json和html? 在当前项目中我们正在制作路线,因此您可以从前端进行选择,在某些情况下哪种格式最适合...所以为什么不制作两个控制器,首先将返回json中的预期数据,另一个控制器将返回相同的数据,但与HTML ...这样你可以选择让我们说jQuery什么时候你想要什么,你想要它的格式......最好的是,对于不同的格式你只需要调用不同的地址...

换句话说,让它安静下来,宝贝! :)

欢呼声

答案 5 :(得分:2)

至于我,我选择数据驱动的方法。以下是两个小功能:

数据驱动:

  1. 来自服务器的JSON(Controller直接将模型发送给响应)
  2. JS模板绑定(可能需要更多时间在客户端)
  3. 低带宽 负载
  4. 这太性感了!
  5. HTML驱动:

    1. 来自服务器的HTML(Controller将模型发送到某个部分View,它会呈现结果并返回它 - 可能需要更多时间在服务器端)
    2. JS绑定中没有重载
    3. 高带宽负载
    4. 不性感,不,不:)
    5. 所以你可以使用HTML驱动的方法维护MVC,虽然它会有点难度。

答案 6 :(得分:0)

如果您使用JQuery,您应该使用JSON或XML,因为它更容易修改,但如果您的ajax调用仅返回列表框的项目,例如您也可以使用html。

我的个人偏好是JSON或XML,因为经常使用JQuery