好吧,您很幸运,因为我编写了大量代码来做类似的事情。如果您想将模型作为 JSON 对象或视图返回,这也会考虑在内。它还将所有 Ajax 调用包装到一个包装器响应元素中
基本上,如果你有一个 UI 人在做事,你永远不需要知道他想要什么。让他编写视图,或进行 AJAX 调用。这将 UI 人员与 C# 开发人员完全解耦(只要他了解如何编写 MVC 视图,他根本不需要知道控制器是如何工作的,只需要知道传递的模型)。
ControllerBase
班级:
public abstract class MyControllerBase : Controller
{
// could be moved to web.config
private const _jsonDataType = "JsonDataType";
public bool IsAjaxRequest
{
get
{
return this.HttpContext.Request.IsAjaxRequest();
}
}
public bool IsAjaxHtmlRequest
{
get
{
return string.Equals(this.Request.Headers[MyControllerBase._jsonDataType], "html", StringComparison.CurrentCultureIgnoreCase);
}
}
private JsonResponse GetAjaxResponse()
{
JsonResponse result = new JsonResponse();
result.IsValid = true;
return result;
}
private JsonResponse<T> GetAjaxResponse<T>(T model)
{
JsonResponse<T> result = new JsonResponse<T>();
result.Data = model;
result.IsValid = true;
return result;
}
private JsonResponse<string> GetAjaxHtmlResponse()
{
JsonResponse<string> result = new JsonResponse<string>();
result.Data = this.PartialViewToString(this.ControllerContext.RouteData.Values["Action"].ToString(), null);
result.IsValid = true;
return result;
}
private JsonResponse<string> GetAjaxHtmlResponse<T>(T model)
{
JsonResponse<string> result = new JsonResponse<string>();
result.Data = this.PartialViewToString(this.ControllerContext.RouteData.Values["Action"].ToString(), model);
result.IsValid = true;
return result;
}
private JsonResponse<string> GetAjaxHtmlResponse<T>(T model, string viewName)
{
JsonResponse<string> result = new JsonResponse<string>();
result.Data = this.PartialViewToString(viewName, model);
result.IsValid = true;
return result;
}
public ActionResult ViewOrAjax()
{
return this.ViewOrAjax(JsonRequestBehavior.DenyGet);
}
public ActionResult ViewOrAjax(JsonRequestBehavior jsonRequestBehavior)
{
if (this.ControllerContext.IsChildAction)
{
return this.PartialView(this.ControllerContext.RouteData.Values["Action"].ToString(), null);
}
if (this.IsAjaxRequest)
{
if (this.IsAjaxHtmlRequest)
{
return this.Json(this.GetAjaxHtmlResponse(), jsonRequestBehavior);
}
return this.Json(this.GetAjaxResponse(), jsonRequestBehavior);
}
return this.View(this.ControllerContext.RouteData.Values["Action"].ToString(), null);
}
public ActionResult ViewOrAjax<T>(T model)
{
return this.ViewOrAjax<T>(model, JsonRequestBehavior.DenyGet);
}
public ActionResult ViewOrAjax<T>(T model, JsonRequestBehavior jsonRequestBehavior)
{
if (this.ControllerContext.IsChildAction)
{
return this.PartialView(model);
}
if (this.IsAjaxRequest)
{
if (this.IsAjaxHtmlRequest)
{
return this.Json(this.GetAjaxHtmlResponse(model), jsonRequestBehavior);
}
return this.Json(this.GetAjaxResponse<T>(model), jsonRequestBehavior);
}
return this.View(model);
}
public ActionResult ViewOrAjax<T>(IView view, T model, JsonRequestBehavior jsonRequestBehavior)
{
if (this.ControllerContext.IsChildAction)
{
return this.PartialView(model);
}
if (this.IsAjaxRequest)
{
if (this.IsAjaxHtmlRequest)
{
return this.Json(this.GetAjaxHtmlResponse(model), jsonRequestBehavior);
}
return this.Json(this.GetAjaxResponse<T>(model), jsonRequestBehavior);
}
return this.View(view, model);
}
public ActionResult ViewOrAjax<T>(string viewName, T model)
{
return this.ViewOrAjax<T>(viewName, model, JsonRequestBehavior.DenyGet);
}
public ActionResult ViewOrAjax<T>(string viewName, T model, JsonRequestBehavior jsonRequestBehavior)
{
if (this.ControllerContext.IsChildAction)
{
return this.PartialView(model);
}
if (this.IsAjaxRequest)
{
if (this.IsAjaxHtmlRequest)
{
return this.Json(this.GetAjaxHtmlResponse(model, viewName), jsonRequestBehavior);
}
return this.Json(this.GetAjaxResponse<T>(model), jsonRequestBehavior);
}
return this.View(viewName, model);
}
public ActionResult ViewOrAjax<T>(string viewName, string masterName, T model)
{
return this.ViewOrAjax<T>(viewName, masterName, model, JsonRequestBehavior.DenyGet);
}
public ActionResult ViewOrAjax<T>(string viewName, string masterName, T model, JsonRequestBehavior jsonRequestBehavior)
{
if (this.ControllerContext.IsChildAction)
{
return this.PartialView(model);
}
if (this.IsAjaxRequest)
{
if (this.IsAjaxHtmlRequest)
{
return this.Json(this.GetAjaxHtmlResponse(model, viewName), jsonRequestBehavior);
}
return this.Json(this.GetAjaxResponse(model), jsonRequestBehavior);
}
return this.View(viewName, masterName, model);
}
protected internal new ViewResult View(string viewName, string masterName, object model)
{
if (model != null)
{
ViewData.Model = model;
}
ViewResult result = new ViewResult
{
ViewName = viewName,
MasterName = masterName,
ViewData = ViewData,
TempData = TempData
};
return result;
}
}
Ajax 调用的JsonResponse<>
全局包装器:
public class JsonResponse
{
public JsonResponse()
{
}
public bool IsValid { get; set; }
public bool IsAjaxRequestUnsupported { get; set; }
public string RedirectTo { get; set; }
public string CanonicalUrl { get; set; }
}
public class JsonResponse<T> : JsonResponse
{
public JsonResponse() : base()
{
}
public T Data { get; set; }
}
Javascriptglobal_getJsonResponse
代码(需要 jQuery):
function global_getJsonResult(Controller, View, data, successCallback, completeCallback, methodType, returnType, jsonDataType) {
if (IsString(Controller)
&& IsString(View)
&& !IsUndefinedOrNull(data)) {
var ajaxData;
var ajaxType;
if (typeof (data) == "string") {
ajaxData = data;
ajaxType = "application/x-www-form-urlencoded"
}
else {
ajaxData = JSON.stringify(data);
ajaxType = "application/json; charset=utf-8";
}
var method = 'POST';
if (methodType) {
method = methodType;
}
var dataType = 'json';
if (returnType) {
dataType = returnType;
}
var jsonType = 'html';
if (jsonDataType) {
jsonType = jsonDataType;
}
var jqXHR = $.ajax({
url: '/' + Controller + '/' + View,
headers: { JsonDataType: jsonType },
data: ajaxData,
type: method,
dataType: dataType,
contentType: ajaxType,
success: function (jsonResult) {
if (!IsUndefinedOrNull(jsonResult)
&& jsonResult.hasOwnProperty("RedirectTo")
&& !IsUndefinedOrNull(jsonResult.RedirectTo)
&& jsonResult.RedirectTo.length > 0) {
$.fn.notify('error', 'Login Expired', 'You have been inactive for a prolonged period of time, and have been logged out of the system.');
window.setTimeout(function () { window.location = jsonResult.RedirectTo }, 5000);
}
else if (IsFunction(successCallback)) {
successCallback(jsonResult, Controller + '/' + View);
}
},
error: function (jqXHR, textStatus, errorThrown) {
if (errorThrown != 'abort') {
$.fn.notify('error', 'Whoops! Something went wrong.', 'We have been notified of the error.'/* textStatus + ': ' + errorThrown*/);
}
log('ERROR IN global_getJsonResult() : ', textStatus, errorThrown, jqXHR);
},
complete: function (jqXHR, textStatus) {
if (IsFunction(completeCallback)) {
completeCallback(jqXHR, textStatus, Controller + '/' + View);
}
}
});
return jqXHR;
}
}
此代码通过处理 ajax 调用中的会话超时同时支持服务器端和客户端超时,更改如下:
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
if (filterContext.HttpContext.Request.IsAjaxRequest())
{
filterContext.Result = new JsonResult
{
Data = new JsonResponse<bool>
{
IsValid = false,
RedirectTo = FormsAuthentication.LoginUrl
},
JsonRequestBehavior = JsonRequestBehavior.AllowGet
};
}
else
{
base.HandleUnauthorizedRequest(filterContext);
}
}
控制器上的几个扩展方法允许您将渲染的部分视图作为 json 中的文本返回(此代码来自 SO,我通常记录此类但我丢失了它):
internal static class ControllerExtensions
{
public static string PartialViewToString(this Controller instance, object model)
{
string viewName = instance.ControllerContext.RouteData.GetRequiredString("action");
return ControllerExtensions.PartialViewToString(instance, viewName, model);
}
public static string PartialViewToString(this Controller instance, string viewName, object model)
{
string result;
ViewDataDictionary viewData = instance.ViewData;
viewData.Model = model;
using (var sw = new StringWriter())
{
var viewResult = ViewEngines.Engines.FindPartialView(instance.ControllerContext, viewName);
var viewContext = new ViewContext(instance.ControllerContext, viewResult.View, viewData, instance.TempData, sw);
viewResult.View.Render(viewContext, sw);
viewResult.ViewEngine.ReleaseView(instance.ControllerContext, viewResult.View);
result = sw.GetStringBuilder().ToString();
}
return result;
}
}
现在(可悲地)从这个基本控制器派生所有控制器:
public HomeController : MyBaseController
{
public ActionResult Index()
{
var viewModel = new MyViewModel();
return this.ViewOrAjax(viewModel);
}
}
现在,如果浏览器调用该页面作为您的标准获取,您将使用 Layout (aka this.View(viewModel)
) 正常呈现该页面。
如果您通过 Javascript 使用 Ajax 调用它:
global_getJsonResult("Home", // Controller or 'Area/Home' for areas
"Index", // View
$('#form').serialize(), // Json object or a serialized Form
jsCallBack, // call back function or null
"Post", // Get or Post
"Html"); // "Html" to return a Partial View in "Data"
// or "Json" to return a serialized view model in "Data"