我将ASP.NET MVC与jQuery一起使用,并且向我的控制器发出了很多Ajax请求。
使用部分视图(usercontrols)在加载页面时构建初始视图。然后,如果我需要根据我的Ajax请求追加/替换数据,我会从Json响应中构建HTML。
这种方法让我完全掌控,即。如果出现问题,我可以从我的控制器获取额外信息,然后根据该信息显示错误消息。
然而,最近我对在部分视图和从Json生成HTML的部分中维护HTML结构所做的所有额外工作感到非常恼火。
我喜欢制作一个jQuery ajax请求,然后让控制器返回PartialView(“mypartialview”),然后在视图中使用jQuery替换为HTML。
但是,这样我就无法从控制器中附加额外的数据 - 无论是局部视图给我的是什么 - 或者什么都没有。至少那是我目前对它的看法。
如果我的控制器操作中某些验证出错,我不想返回局部视图的HTML。
那么你如何处理这个问题?
感谢阅读。
答案 0 :(得分:20)
基于this stackoverflow 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();
}
}
然后在controllers动作方法中返回json。
return Json(new
{
Html = this.RenderViewToString("MyView", model),
SomeExtraData = data
});
您的ajax请求现在将收到包含在其中的html的json。仍在尝试使用这种方法来返回普通的Html片段。
希望有所帮助。
编辑已更新以使用剃须刀
答案 1 :(得分:4)
这是一种利用每个相应结果返回的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
标头,并相应地执行操作。请注意,如果不是HTML,我们假设JSON是“作弊”。我们称之为预先存在的addMessage()
函数,随心所欲!
最后,这是一个示例Anchor元素,onclick
定位于上面的getPartialView()
。
<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。
答案 2 :(得分:2)
我相信你可以将渲染的html作为字符串返回 - 这可能是一个包含要显示的错误消息的html字符串?
答案 3 :(得分:0)
你也可以这样做,把它放在你的控制器内。
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();
}
}