Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>Well you're in luck because I wrote a TON of code to do something similar. This also takes into account if you want to return the model as a JSON object or a View. It also wraps all the Ajax calls into a wrapper response element</p> <p>Basically if you have a UI guy doing stuff, you NEVER need to know what he wants. Let him write the views, or make AJAX calls. This completely decouples the UI person from the C# developer (as long as he understands how to write MVC Views, he doesn't need to know at all how the controller works, just the model being passed).</p> <p>The <code>ControllerBase</code> class:</p> <pre><code>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&lt;T&gt; GetAjaxResponse&lt;T&gt;(T model) { JsonResponse&lt;T&gt; result = new JsonResponse&lt;T&gt;(); result.Data = model; result.IsValid = true; return result; } private JsonResponse&lt;string&gt; GetAjaxHtmlResponse() { JsonResponse&lt;string&gt; result = new JsonResponse&lt;string&gt;(); result.Data = this.PartialViewToString(this.ControllerContext.RouteData.Values["Action"].ToString(), null); result.IsValid = true; return result; } private JsonResponse&lt;string&gt; GetAjaxHtmlResponse&lt;T&gt;(T model) { JsonResponse&lt;string&gt; result = new JsonResponse&lt;string&gt;(); result.Data = this.PartialViewToString(this.ControllerContext.RouteData.Values["Action"].ToString(), model); result.IsValid = true; return result; } private JsonResponse&lt;string&gt; GetAjaxHtmlResponse&lt;T&gt;(T model, string viewName) { JsonResponse&lt;string&gt; result = new JsonResponse&lt;string&gt;(); 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&lt;T&gt;(T model) { return this.ViewOrAjax&lt;T&gt;(model, JsonRequestBehavior.DenyGet); } public ActionResult ViewOrAjax&lt;T&gt;(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&lt;T&gt;(model), jsonRequestBehavior); } return this.View(model); } public ActionResult ViewOrAjax&lt;T&gt;(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&lt;T&gt;(model), jsonRequestBehavior); } return this.View(view, model); } public ActionResult ViewOrAjax&lt;T&gt;(string viewName, T model) { return this.ViewOrAjax&lt;T&gt;(viewName, model, JsonRequestBehavior.DenyGet); } public ActionResult ViewOrAjax&lt;T&gt;(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&lt;T&gt;(model), jsonRequestBehavior); } return this.View(viewName, model); } public ActionResult ViewOrAjax&lt;T&gt;(string viewName, string masterName, T model) { return this.ViewOrAjax&lt;T&gt;(viewName, masterName, model, JsonRequestBehavior.DenyGet); } public ActionResult ViewOrAjax&lt;T&gt;(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; } } </code></pre> <p>The <code>JsonResponse&lt;&gt;</code> global wrapper for Ajax Calls:</p> <pre><code>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&lt;T&gt; : JsonResponse { public JsonResponse() : base() { } public T Data { get; set; } } </code></pre> <p>The Javascript <code>global_getJsonResponse</code> code (require jQuery):</p> <pre><code>function global_getJsonResult(Controller, View, data, successCallback, completeCallback, methodType, returnType, jsonDataType) { if (IsString(Controller) &amp;&amp; IsString(View) &amp;&amp; !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) &amp;&amp; jsonResult.hasOwnProperty("RedirectTo") &amp;&amp; !IsUndefinedOrNull(jsonResult.RedirectTo) &amp;&amp; jsonResult.RedirectTo.length &gt; 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; } } </code></pre> <p>This code supports both server side and client side TimeOuts via <a href="https://stackoverflow.com/questions/5238854/handling-session-timeout-in-ajax-calls/5242746#5242746">Handling session timeout in ajax calls</a>, with a change like:</p> <pre><code>protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext) { if (filterContext.HttpContext.Request.IsAjaxRequest()) { filterContext.Result = new JsonResult { Data = new JsonResponse&lt;bool&gt; { IsValid = false, RedirectTo = FormsAuthentication.LoginUrl }, JsonRequestBehavior = JsonRequestBehavior.AllowGet }; } else { base.HandleUnauthorizedRequest(filterContext); } } </code></pre> <p>A couple of Extension Methods on controller to allow you to return rendered partial views as text in json (this code was from SO, I usually document such but I lost it):</p> <pre><code>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; } } </code></pre> <p>Now derive (sadly) all your controllers from this base controller:</p> <pre><code>public HomeController : MyBaseController { public ActionResult Index() { var viewModel = new MyViewModel(); return this.ViewOrAjax(viewModel); } } </code></pre> <p>Now if the page is called by the browser as your standard get, you get the page rendered normally with a Layout (aka <code>this.View(viewModel)</code>).</p> <p>If you call it using Ajax via the Javascript:</p> <pre><code>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" </code></pre>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload