Wednesday, January 8, 2014

Is there really no difference between a partial view and a regular view in MVC?

The question


I've read several posts on the net about there being no real difference between a partial view and a regular view in ASP.NET MVC, only that the convention of using them was different. Is this really the case?



I decided to find out the details for myself as part of the new "MVC for Web Forms Developers" course I'm working on for pluralsight.com so I could see exactly what all this entailed outside of just being a convention difference. Let it be known, there is indeed several differences you should be aware of. This post isn't meant to state when you should use one vs the other, there are plenty of resources for that. Here we just want to delve into how they are different, which in turn can help you decide when to use a View vs PartialView (and to confuse things more the decision there is really View vs PartialView vs Html.Action vs Html.Partial vs Ajax in any combination)


The differences


The differences that were obvious from the code are
  1. Partial Views don't have a layout processed. Very important to know.
  2. Partial Views don't check for a _ViewStart.cshtml. Note this is typically where layouts are specified but technically you could specify one in your partial and it would be ignored. Very important to know.
  3. Partial Views can throw a slightly different exception, the details included to InvalidOperationException in PartialViewResult vs ViewResult classes. This is pretty minor.

There is a slight difference in how they are processed.
Lets look at the code, shall we?

First, the differences between a PartialViewResult and a ViewResult as contained in the following files from the MVC source code:
  1. c:\source\aspnetwebstack\src\System.Web.Mvc\PartialViewResult.cs (link to source here)
  2. c:\source\aspnetwebstack\src\System.Web.Mvc\ViewResult.cs (link to source here)


Lets dive into FindPartialView and FindView. These are the functions called when you "return View()" and "return Partial()" from inside a controller.

The comparison of PartialViewResult and ViewResult


First check out a comparison side by side, this may give you an easy quick view with one of the best tools of all time,Beyond Compare


The codez


 public virtual ViewEngineResult FindPartialView(ControllerContext controllerContext, string partialViewName, bool useCache)
        {
            if (controllerContext == null)
            {
                throw new ArgumentNullException("controllerContext");
            }
            if (String.IsNullOrEmpty(partialViewName))
            {
                throw new ArgumentException(MvcResources.Common_NullOrEmpty, "partialViewName");
            }

            string[] searched;
            string controllerName = controllerContext.RouteData.GetRequiredString("controller");
            string partialPath = GetPath(controllerContext, PartialViewLocationFormats, AreaPartialViewLocationFormats, "PartialViewLocationFormats", partialViewName, controllerName, CacheKeyPrefixPartial, useCache, out searched);

            if (String.IsNullOrEmpty(partialPath))
            {
                return new ViewEngineResult(searched);
            }

            //********* note the call here to CreatePartialView *****
            return new ViewEngineResult(CreatePartialView(controllerContext, partialPath), this);
        }

        public virtual ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache)
        {
            if (controllerContext == null)
            {
                throw new ArgumentNullException("controllerContext");
            }
            if (String.IsNullOrEmpty(viewName))
            {
                throw new ArgumentException(MvcResources.Common_NullOrEmpty, "viewName");
            }

            string[] viewLocationsSearched;
            string[] masterLocationsSearched;

            string controllerName = controllerContext.RouteData.GetRequiredString("controller");
            string viewPath = GetPath(controllerContext, ViewLocationFormats, AreaViewLocationFormats, "ViewLocationFormats", viewName, controllerName, CacheKeyPrefixView, useCache, out viewLocationsSearched);
            string masterPath = GetPath(controllerContext, MasterLocationFormats, AreaMasterLocationFormats, "MasterLocationFormats", masterName, controllerName, CacheKeyPrefixMaster, useCache, out masterLocationsSearched);

            if (String.IsNullOrEmpty(viewPath) || (String.IsNullOrEmpty(masterPath) && !String.IsNullOrEmpty(masterName)))
            {
                return new ViewEngineResult(viewLocationsSearched.Union(masterLocationsSearched));
            }
            //********* note the call here to CreateView *****
            return new ViewEngineResult(CreateView(controllerContext, viewPath, masterPath), this);
        }

The differences in view processing


The function calls below to create a partial view or a regular view do indeed differ. One has a pipeline that uses a layout, the other doesn't. The regular view processing uses viewstart pages as well. For those unfamilar with the viewstart file, this is a file MVC looks for since MVC3.

MVC will look in the /Views/Shared folder and in the current view folder as well for a file named _ViewStart.cshtml. This file contains code that will be executed before the view is processed, typically it's used to store the path to the layout in it and again, can be set for all views or overridden in a particular views folder, ex /Views/Customer/_ViewStart.cshtml to set a different Layout for views in that folder as one example.
@{
    Layout = "~/Views/Shared/_MasterPage.cshtml";
}
protected override IView CreatePartialView(ControllerContext controllerContext, string partialPath)
        {
            //**NOTE a partial view has a null layout and runViewStartPages is false! **
            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)
        {
            //note the usage of a masterPath below.
            var view = new RazorView(controllerContext, viewPath,
                                     layoutPath: masterPath, runViewStartPages: true, viewStartFileExtensions: FileExtensions, viewPageActivator: ViewPageActivator)
            {
                DisplayModeProvider = DisplayModeProvider
            };
            return view;
        }



In closing


So there are some differences as probably expected. Nothing groundbreaking but it is important to understand the shortcut pipeline the PartialView takes hence making them perform a bit better as well. Ok, now you know the exact differences and have seen it from the source, in other words - heard it from
Enjoy!

2 comments:

  1. Thanks for the information.

    SyonIndia is a Software Development, Website development and SEO company in Bhubaneswar. We offer professional software development services in Bhubaneswar India. Our developers are highly skilled, advance and expert to execute things up to the mark and are efficient enough to cope up with new platforms. We are the leading software development company in Bhubaneswar.
    http://syonindia.com

    ReplyDelete
  2. Nice information you have shared with us. This will very helpful to us. Thanks for sharing such a valuable blog.
    web design company India | Webzin Infotech

    ReplyDelete