Reputation: 5228
Should calling PartialView() within an action use the layout?
Here's my Actions:
public ActionResult SomeAction()
{
if (Request.IsAjaxRequest())
return PartialView();
else
return View();
}
Here's my _ViewStart.cshtml:
@{
Layout = "~/Views/Shared/_Layout.cshtml";
}
Scenario #1: Action calls a view with no layout specified.
@{
//Layout = "~/Views/Shared/_SomeLayout.cshtml";
}
<h2>View!</h2>
This is backed up by this response from Darin Dimitrov.
Scenario #2: Action calls a view with a layout specified.
@{
Layout = "~/Views/Shared/_SomeLayout.cshtml";
}
<h2>View!</h2>
This also seems to be backed up by this other response from Darin Dimitrov. (NOTE: Even though his answer is a catch-all for AJAX requests, this was the response to a question where the OP had two views, one full and one partial.)
So on the first, Darin is explaining that if you don't want a layout, use PartialView(), but in the second one he is saying if you don't want a layout, then here's a workaround.
Can someone explain to me if there is something I'm missing or why it is this way. Regardless of what Darin has said, if I only set the layout in _ViewStart.cshtml
, then I can ignore it with PartialView(), but if I set another layout in the View itself, then I can't ignore it.
Does this make sense? Should I be able to ignore both layouts? If not, why?
Upvotes: 3
Views: 949
Reputation: 3835
Rendering process of full page or partial page is same in Razor, because they are using same base classes. For rendering process both full page and partial page create a RazorView object but with different constructor parameters. From source code these are the two methods for rendering views. System.Web.Mvc namespace RazorViewEngine.cs
protected override IView CreatePartialView(ControllerContext controllerContext, string partialPath)
{
return new RazorView(controllerContext, partialPath,
layoutPath: null, runViewStartPages: false, viewStartFileExtensions: FileExtensions, viewPageActivator: ViewPageActivator)
{
DisplayModeProvider = DisplayModeProvider
};
}
protected override IView CreateView(ControllerContext controllerContext, string viewPath, string masterPath)
{
var view = new RazorView(controllerContext, viewPath,
layoutPath: masterPath, runViewStartPages: true, viewStartFileExtensions: FileExtensions, viewPageActivator: ViewPageActivator)
{
DisplayModeProvider = DisplayModeProvider
};
return view;
}
See that when creating partial view, layoutPath:null,runViewStartPages:false
in constructor parameters. In your scenario #1, this is why View wrapped in a layout but partialView not. According to these methods when returning PartialView, ViewStart does not executed but when returning View it does.
Default layout for partialView is null like specified in the constructor parameter. But after ViewActionResult returns, overriden layout might have been specified. That is what happens in your scenario #2. By declaringLayout = "~/Views/Shared/_SomeLayout.cshtml";
you are specifying WebPageBase.Layout
property to some path and this overrides layoutPath:null
. Even if you return PartialView() razor will generate complete view. In the same way if you declare Layout = null;
in your view and even if you return View() from controller Razor will generate partialView. So whether your view will be partial or complete view not determined by if you return View()
or PartialView()
. That is determined by whether Layout property is null or some path.So for more readable code, when you want to generate partialView use return PartialView()
and do not define any Layout inside your view.
Upvotes: 4