如果动作是ajax或子动作,则返回部分视图

时间:2013-07-17 01:52:59

标签: c# asp.net-mvc

大家好我已经把谷歌试图构建某种类,如果它是一个AJAX调用或子动作或动作,将确定 UNIVERSALLY ,以便我的控制器可以确定是否返回部分查看或完整视图。到目前为止,我没有多少运气。目前我正在使用以下代码来实现此目的

 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 我找到了一个答案,它不是辅助函数,而是视图中的修改。链接是here。可以将我自己的问题标记为重复:(

3 个答案:

答案 0 :(得分:8)

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

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

使用该代码,您只需return View();即可完成所有操作。

由于所有观点都经过了这一步骤,这可能只是您的通用解决方案。

答案 1 :(得分:6)

嗯,你很幸运,因为我写了一些TON代码来做类似的事情。如果要将模型作为JSON对象或View返回,也会考虑这一点。它还将所有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 Calls的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;
    }
}

此代码通过Handling session timeout in ajax calls支持服务器端和客户端TimeOuts,其变化如下:

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

现在,如果浏览器调用该页面作为标准获取,则可以通过布局(又名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"

答案 2 :(得分:1)

改善德米特里的答案:

创建一个自定义WebViewPage类,这样就不需要将修改添加到多个视图中(相关的地方有多个布局文件,这些文件由View本身而不是_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">