C# 如果操作是ajax或子操作,则返回局部视图

C# 如果操作是ajax或子操作,则返回局部视图,c#,asp.net-mvc,C#,Asp.net Mvc,我已经烧掉了google试图构造某种类的功能,它将普遍决定是AJAX调用还是子操作。这样我的控制器就可以决定是返回局部视图还是完整视图。到目前为止,我运气不太好。目前,我正在使用以下代码来实现这一点: if (Request.IsAjaxRequest() || ControllerContext.IsChildAction) { return PartialView(); } return View(); 问

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

 if (Request.IsAjaxRequest() || ControllerContext.IsChildAction)
            {
                return PartialView();
            }
 return View();
问题是你必须在控制器中的每一个动作和遇到的每一种情况下都这样做,但我相信有一种方法可以通过助手实现这一点,但我不知道如何实现。你能给我指一下实现这一点的任何链接/示例代码吗

编辑:

@Aron我发布了一段代码,因为整个控制器太长了。但你可以看到我的困境。返回包含一个视图和一个对象/模型“k”

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

你很幸运,因为我编写了大量代码来执行类似的操作。这还考虑了是否要将模型作为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;
    }
}
此代码通过支持服务器端和客户端超时,更改如下:

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);
  }
}
现在(遗憾的是)从这个基本控制器派生出所有控制器:

public HomeController : MyBaseController
{
  public ActionResult Index()
  {
    var viewModel = new MyViewModel();

    return this.ViewOrAjax(viewModel);
  }
}
现在,如果浏览器将该页面作为标准get调用,则可以使用布局(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"

一个简单的解决方案可能是在视图文件夹下的
\u ViewStart.cshtml
文件中使用类似的代码:

@{
    Layout = Request.IsAjaxRequest() || ViewContext.IsChildAction
        ? null
        : "~/Views/Shared/_Layout.cshtml";
}
使用该代码,您可以从所有操作中
返回视图();


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

对Dmitry答案的改进:

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

公共抽象类CustomWebViewPage:WebViewPage
{
公共重写字符串布局
{
得到
{
return Request.IsAjaxRequest()| | ViewContext.IsChildAction?null:base.Layout;
}
设置
{
base.Layout=值;
}
}
}
公共抽象类CustomWebViewPage:CustomWebViewPage
{
}
和web.config(在视图文件夹下)



将您发布的代码放在私有方法中并返回对它的调用如何?问题是当您返回带有视图的模型时。例如
返回视图(“someview”,somemodel)因此,如果我构造一个方法,我必须为每个对象/模型一次又一次地构造相同的方法,这有点违背了该方法的目的。另一方面,我可能会尝试var。如果你发布完整的控制器,代码是重复的,我会看看我能不能用它做些什么……我不是MVC专家或其他什么,但我会我喜欢try@AaronAnodide我已经按照您的要求发布了一段代码。好的,这应该是相当完整的,如果缺少什么,请告诉我。除非您有多个布局文件,这些文件是在视图文件本身而不是在_ViewStart.cshtml中设置的。在这种情况下,您将需要多次执行上述操作在某些情况下,您可以创建一个自定义WebViewPage类,该类继承自
System.Web.Mvc.WebViewPage
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);
  }
}
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"
@{
    Layout = Request.IsAjaxRequest() || ViewContext.IsChildAction
        ? null
        : "~/Views/Shared/_Layout.cshtml";
}
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
{
}
<pages pageBaseType="Fully.Qualified.Namespace.CustomWebViewPage">