部分视图与 Json(或两者)

Posted

技术标签:

【中文标题】部分视图与 Json(或两者)【英文标题】:Partial Views vs. Json (or both) 【发布时间】:2010-12-01 01:27:24 【问题描述】:

我将 ASP.NET MVC 与 jQuery 结合使用,并向我的控制器发送大量 Ajax 请求。

在加载页面时使用部分视图(用户控件)构建初始视图。然后,如果我需要根据我的 Ajax 请求附加/替换数据,我会从 Json 响应构建 html

这种方法让我可以完全控制,即。如果出现问题,我可以从控制器返回额外信息,然后根据该信息显示错误消息。

但是,最近我对在部分视图和从 Json 生成 HTML 的部分中维护 HTML 结构的所有额外工作感到非常恼火。

我喜欢发出一个 jQuery ajax 请求,然后让控制器返回 PartialView("mypartialview"),然后只使用 jQuery 替换视图中的 HTML。

但是,通过这种方式,我无法从控制器附加额外的数据——它要么是局部视图给我的任何东西——要么什么都没有。至少这是我目前的看法。

如果某些验证在我的控制器操作中出现错误,我不想返回部分视图的 HTML。

那么你如何处理这个问题呢?

感谢阅读。

【问题讨论】:

【参考方案1】:

基于this*** anwser,我刚刚开始做同样的事情。

首先为控制器类创建一个扩展方法。

public static string RenderViewToString(this Controller controller, string viewName, object model)

    using (var writer = new StringWriter())
    
         var viewResult = ViewEngines.Engines.FindPartialView(controller.ControllerContext, viewName);
         controller.ViewData.Model = model;
         var viewCxt = new ViewContext(controller.ControllerContext, viewResult.View, controller.ViewData, controller.TempData, writer);
         viewCxt.View.Render(viewCxt, writer);
         return writer.ToString();
     

然后在控制器动作方法中返回json。

return Json(new 
  Html = this.RenderViewToString("MyView", model),
    SomeExtraData = data
);

您的 ajax 请求现在将收到包含 html 的 json。仍在试验这种方法而不是返回普通的 Html 片段。

希望对您有所帮助。

编辑已更新为与剃须刀一起使用

【讨论】:

【参考方案2】:

这是一种利用每个相应结果返回的Content-Type 的方法。我们使用它来发回错误信息,并且已经有 JS 来显示消息,所以我们得到了我们想要的部分视图,或者错误报告的控制信息等。

作为参考,部分视图返回text/html,JSON 响应应返回application/json

像往常一样,有趣的部分在 javascript 方面,而 JQuery ajax() 在这里不会让人失望!

在您的控制器中,根据需要返回PartialView()Json(model,);我们以try/catch 格式使用它。

public ActionResult Edit(int id) 
    try 
        var model = getYourModel();
        return PartialView("Edit", model);
    
    catch (Exception ex) 
        var mi = new MessageInfo(MessageType.Error, String.Format("Edit failed: 0", ex.Message), true);
        return Json(mi, "application/json", JsonRequestBehavior.AllowGet);
    

在 JS 端,我们使用以下函数。请注意,您需要从初始页面级 GET 重新建立您在 $(document).ready() 中挂钩的任何 JQuery 事件,因此我们有一个回调参数。

function getPartialView(action, controller, model, divId, callback) 
    var url = "/" + controller + "/" + action + "/";
    $.ajax(
        type: "GET",
        url: url,
        data: model,
        success: function (data, textStatus, jqXHR) 
            var ct = jqXHR.getResponseHeader("Content-Type");
            var mx = ct.match("text\/html");
            if (mx != null) 
                $(divId).html(data);
                if (callback) 
                    callback($(divId));
                
            
            else 
                addMessage(data.type, data.title, data.text, data.sticky);
            
        ,
        error: function (jqXHR, textStatus, errorThrown) 
            addMessage(3, "\"" + url + "\": Failed", textStatus + ": " + errorThrown, false);
        
    );

唯一棘手的一点是检查响应中的Content-Type 标头,并采取相应的行为。请注意,如果 JSON 不是 HTML,我们就是在“作弊”。我们正在调用我们预先存在的addMessage() 函数,随心所欲!

最后,这是一个示例 Anchor 元素,上面有 onclickgetPartialView() 为目标。

<a href="#" onclick="getPartialView('Action', 'Controller', model, '#partialviewdivid', function(dvx)  connectJqueryEvents(dvx); )">Cancel</a>

效果很好...

除了通过Ajax.BeginForm() 提交的表单,由于Content-Type 的验证不足,JSON 有效负载被错误地视为 HTML。结果是您的div 添加了一些 JSON,它基本上不会呈现为 HTML。 AjaxOptions.OnSuccess 回调确实会执行,但此时对于您的 DOM 来说为时已晚!

有一个简单的解决方案,但不幸的是,它需要对jquery-unobtrusive-ajax.js 进行小修复,因为asyncOnSuccess() 函数在编写时是短视的。

function asyncOnSuccess(element, data, contentType) 
  var mode;

  if (contentType.indexOf("application/x-javascript") !== -1) 
    return;
  
  if (contentType.indexOf("application/json") !== -1) 
    return;
  
...snip...

在 OOTB 版本中,缺少第二个 if 语句;添加它是防止它将您的 JSON 有效负载猛烈撞击到 DOM 的必要修复。

通过此修复,JSON 有效负载将传递到您的 AjaxOptions.OnSuccess Javascript,您可以根据需要继续操作。

是的,你可以两者兼得

希望您知道,既然您要发送 Json,您可以发送回任何类型的模型,并让 Javascript 对其进行排序; hasOwnProperty() 在那里派上用场。所以很明显你可以通过已经提到的RenderViewToString()发回一些视图HTML。

【讨论】:

【参考方案3】:

我相信您可以将呈现的 html 作为字符串返回 - 这也可以是包含要显示的错误消息的 html 字符串?

【讨论】:

确实,PartialView 响应就是这样。尽管您没有完全清楚地说明它,但这就是解决方案:让您的 AJAX 方法使用您最初用于呈现页面的该部分的相同用户控件返回呈现的 PartialView。您可以通过编写 return PartialView(model) 而不是 return Json(model) 来做到这一点。 谢谢。这确实是一个更好的解释:) 克雷格,这就是我现在所做的。我的问题是我想同时返回 Html 和 Json - 或者换一种说法:我想要从 return PartialView 返回的结果 html 然后包装在 Json 中,这样我也可以发送其他数据。有点像这个人:***.com/questions/1168791/… 我想上面的方法会起作用,但我想知道其他人是如何处理这个问题的。 您可以(轻松)返回与局部视图(HTML 片段)或 JSON 相同的模型。构建模型,然后调用您需要的任何方法。但不要编写从同一模型的 JSON 序列化复制部分视图的 JavaScript。【参考方案4】:

你也可以这样做,把它放在你的控制器里。

protected string RenderPartialViewToString(string viewName, object model)

    if (string.IsNullOrEmpty(viewName))
        viewName = ControllerContext.RouteData.GetRequiredString("action");

    ViewData.Model = model;

    using (StringWriter sw = new StringWriter()) 
        ViewEngineResult viewResult = ViewEngines.Engines.FindPartialView(ControllerContext, viewName);
        ViewContext viewContext = new ViewContext(ControllerContext, viewResult.View, ViewData, TempData, sw);
        viewResult.View.Render(viewContext, sw);

        return sw.GetStringBuilder().ToString();
    

【讨论】:

以上是关于部分视图与 Json(或两者)的主要内容,如果未能解决你的问题,请参考以下文章

WebView 或其他视图

什么是基本表?什么是视图?两者的区别和联系是什么?

以 json 形式返回部分视图?

从 ASP.NET MVC 操作返回部分视图和 JSON

如何在 iOS 中为表格视图和滚动视图设置偏移量,以便两者一起滚动

如何在控制器中为 Json 渲染部分视图