3

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

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

问题是您必须在控制器中的每个操作以及遇到的每个条件中都执行此操作,但我确信有一种方法可以通过帮助程序实现此目的,但无法弄清楚如何。您能否指出我的任何链接/示例代码来实现这一点。

编辑:

@Aron 我已经发布了一段代码,因为整个控制器太长了。但你可以看到我的困境。返回包含一个视图和一个对象/模型“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 我找到了一个答案,它不是辅助函数,而是视图中的修改。链接在这里。可以将我自己的问题标记为重复:(

4

3 回答 3

8

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

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

使用该代码,您可以return View();执行所有操作。

由于所有视图都经过该步骤,因此这可能是您的通用解决方案。

于 2013-07-17T02:48:20.180 回答
6

好吧,您很幸运,因为我编写了大量代码来做类似的事情。如果您想将模型作为 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"
于 2013-07-17T02:41:41.227 回答
1

改进德米特里的回答:

创建一个自定义的 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">
于 2015-01-08T12:02:22.793 回答