如果操作是ajax或通用子操作,则返回部分视图

本文关键字:操作 返回部 视图 ajax 如果 | 更新日期: 2023-09-27 18:22:35

我在谷歌上试图构建某种类,这将普遍决定它是AJAX调用还是子操作。这样我的控制器就可以确定是返回部分视图还是完整视图。到目前为止,我运气不太好。目前我正在使用以下代码来实现这一点:

 if (Request.IsAjaxRequest() || ControllerContext.IsChildAction)
            {
                return PartialView();
            }
 return View();

问题是你必须在控制器中的每一个动作和你遇到的每一种情况中都这样做,但我相信有一种方法可以通过助手来实现,但我不知道如何实现。你能给我指出任何链接/示例代码来实现这一点吗。

编辑:

@Aron我已经发布了一段代码,因为整个控制器太长了。但你可以看到我的困境。返回包含一个View和一个Object/Model";k";。

public ActionResult _Details_Message(int id = 0, int CId = 0)
        {
            ViewBag.MrnSortParm = CId;
            if (id != 0)
            {
                var k = mrn.MRNS.Where(u => u.Id == id).SingleOrDefault();
                if (k.To == User.Identity.Name)
                {
                    if (k.Type == 0) // message
                    {
                        k.Read = true;
                        mrn.Entry(k).State = EntityState.Modified;
                        mrn.SaveChanges();
                    }
                    return PartialView("_Details_Message", k);//replace the above code here
                }
                if (k.From == User.Identity.Name)
                {
                    return PartialView("_Sent", k); //replace the above code here
                }
            }
            var m = new message();
            m.CourierId = CId;
            return PartialView("_Create_Message", m); //replace the above code here
        }

编辑2我找到了一个答案——它不是一个辅助函数,而是视图中的一个修改。链接在这里。可以将我自己的问题标记为重复:(

如果操作是ajax或通用子操作,则返回部分视图

一个简单的解决方案可能具有与Views文件夹下_ViewStart.cshtml文件中使用的代码类似的代码:

@{
    Layout = Request.IsAjaxRequest() || ViewContext.IsChildAction
        ? null
        : "~/Views/Shared/_Layout.cshtml";
}

有了这个代码,您就可以从所有操作中return View();

既然所有的观点都在经历这一步,那么这可能就是你的普遍解决方案。

你很幸运,因为我写了很多代码来做类似的事情。如果您想将模型作为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; }
}

Javascript global_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);
  }
}

现在,如果浏览器将页面作为标准get调用,则可以使用Layout(也称为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"

对Dmitry答案的改进:

创建一个自定义WebViewPage类,这样您就不需要将修改添加到多个视图中(如果存在多个由视图本身而不是_ViewStart文件确定的布局文件,则相关)

public abstract class CustomWebViewPage: WebViewPage
{
    public override string Layout
    {
        get
        {
            return Request.IsAjaxRequest() || ViewContext.IsChildAction ? null : base.Layout;
        }
        set
        {
            base.Layout = value;
        }
    }
}
public abstract class CustomWebViewPage<TModel>: CustomWebViewPage
{
}

在web.config中(在Views文件夹下)

<pages pageBaseType="Fully.Qualified.Namespace.CustomWebViewPage">