Load PartialView for AJAX and View for non-AJAX re

2019-04-08 14:36发布

问题:

I wanna implement something like in facebook:

  • after left click on photo, it is loaded via AJAX
  • after middle click on scroll, it is loaded normally with additional layout

For now I have a View, which is loaded in Controller in two different methods:

public ActionResult Overview()
{
    return View("Overview");
}

public ActionResult OverviewPartialView()
{
    return PartialView("Overview");
}

And in jquery script it looks like this:

$(contentContainer).load(_link + 'PartialView');

My question is, is there a better way to solve that problem? I have tried with something like that in _ViewStart:

@{
    Layout = "~/Views/Shared/_Layout.cshtml";
    if (IsAjax)
    {
        Layout = null;
    }
}

And something like that in Controller:

public ActionResult Index()
{
    if (Request.IsAjaxRequest())
        return PartialView();

    return View();
}

But in those solutions I had a problem with cache, after opening a page with layout, in AJAX request also that page with layout was loaded.

回答1:

You could use a single action:

public ActionResult Overview()
{
    return View();
}

and inside _ViewStart.cshtml:

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

Another possibility is to use the following:

public ActionResult Overview()
{
    if (Request.IsAjaxRequest())
    {
        return PartialView();
    }
    return View();
}

then if you want to avoid caching problems you could use a POST request instead of GET:

$.post(_link, function(result) {
    $(contentContainer).html(result);
});

or use $.ajax with GET and specify cache: false which will append an unique query string parameter to avoid browsers caching:

$.ajax({
    url: _link,
    type: 'GET',
    cache: false,
    success: function(result) {
        $(contentContainer).html(result);
    }
});


回答2:

You can use a semi global solution with an ActionFilter. This example transforms the original ViewResult to PartialViewResult, if the request is AJAX (XHR)

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class AjaxifyFilterAttribute : ActionFilterAttribute
{
    public override void OnActionExecuted(ActionExecutedContext filterContext)
    {
        if(!filterContext.HttpContext.Request.IsAjaxRequest() ||
            !(filterContext.Result is ViewResult)) return;

        var view = filterContext.Result as ViewResult;
        filterContext.Result = new PartialViewResult
        {
            TempData = view.TempData,
            ViewData = view.ViewData,
            ViewName = view.ViewName,
            ViewEngineCollection = view.ViewEngineCollection
        };
    }
}