A Custom View Engine with Dynamic View Location

Posted by imran_ku07 on ASP.net Weblogs See other posts from ASP.net Weblogs or by imran_ku07
Published on Mon, 27 Jun 2011 05:46:00 GMT Indexed on 2011/06/27 16:23 UTC
Read the original article Hit count: 420

Filed under:
|
|
|

    Introduction:

          One of the nice feature of ASP.NET MVC framework is its pluggability. This means you can completely replace the default view engine(s) with a custom one. One of the reason for using a custom view engine is to change the default views location and sometimes you need to change the views location at run-time. For doing this, you can extend the default view engine(s) and then change the default views location variables at run-time.  But, you cannot directly change the default views location variables at run-time because they are static and shared among all requests. In this article, I will show you how you can dynamically change the views location without changing the default views location variables at run-time.

 

    Description:

          Let's say you need to synchronize the views location with controller name and controller namespace. So, instead of searching to the default views location(Views/ControllerName/ViewName) to locate views, this(these) custom view engine(s) will search in the Views/ControllerNameSpace/ControllerName/ViewName folder to locate views.

          First of all create a sample ASP.NET MVC 3 application and then add these custom view engines to your application,

 

    public class MyRazorViewEngine : RazorViewEngine
    {
        public MyRazorViewEngine() : base()
        {
            AreaViewLocationFormats = new[] {
                "~/Areas/{2}/Views/%1/{1}/{0}.cshtml",
                "~/Areas/{2}/Views/%1/{1}/{0}.vbhtml",
                "~/Areas/{2}/Views/%1/Shared/{0}.cshtml",
                "~/Areas/{2}/Views/%1/Shared/{0}.vbhtml"
            };

            AreaMasterLocationFormats = new[] {
                "~/Areas/{2}/Views/%1/{1}/{0}.cshtml",
                "~/Areas/{2}/Views/%1/{1}/{0}.vbhtml",
                "~/Areas/{2}/Views/%1/Shared/{0}.cshtml",
                "~/Areas/{2}/Views/%1/Shared/{0}.vbhtml"
            };

            AreaPartialViewLocationFormats = new[] {
                "~/Areas/{2}/Views/%1/{1}/{0}.cshtml",
                "~/Areas/{2}/Views/%1/{1}/{0}.vbhtml",
                "~/Areas/{2}/Views/%1/Shared/{0}.cshtml",
                "~/Areas/{2}/Views/%1/Shared/{0}.vbhtml"
            };

            ViewLocationFormats = new[] {
                "~/Views/%1/{1}/{0}.cshtml",
                "~/Views/%1/{1}/{0}.vbhtml",
                "~/Views/%1/Shared/{0}.cshtml",
                "~/Views/%1/Shared/{0}.vbhtml"
            };

            MasterLocationFormats = new[] {
                "~/Views/%1/{1}/{0}.cshtml",
                "~/Views/%1/{1}/{0}.vbhtml",
                "~/Views/%1/Shared/{0}.cshtml",
                "~/Views/%1/Shared/{0}.vbhtml"
            };

            PartialViewLocationFormats = new[] {
                "~/Views/%1/{1}/{0}.cshtml",
                "~/Views/%1/{1}/{0}.vbhtml",
                "~/Views/%1/Shared/{0}.cshtml",
                "~/Views/%1/Shared/{0}.vbhtml"
            };
        }

        protected override IView CreatePartialView(ControllerContext controllerContext, string partialPath)
        {
            var nameSpace = controllerContext.Controller.GetType().Namespace;
            return base.CreatePartialView(controllerContext, partialPath.Replace("%1", nameSpace));
        }

        protected override IView CreateView(ControllerContext controllerContext, string viewPath, string masterPath)
        {
            var nameSpace = controllerContext.Controller.GetType().Namespace;
            return base.CreateView(controllerContext, viewPath.Replace("%1", nameSpace), masterPath.Replace("%1", nameSpace));
        }

        protected override bool FileExists(ControllerContext controllerContext, string virtualPath)
        {
            var nameSpace = controllerContext.Controller.GetType().Namespace;
            return base.FileExists(controllerContext, virtualPath.Replace("%1", nameSpace));
        }

    }



    public class MyWebFormViewEngine : WebFormViewEngine
    {
        public MyWebFormViewEngine() : base()
        {
            MasterLocationFormats = new[] {
                "~/Views/%1/{1}/{0}.master",
                "~/Views/%1/Shared/{0}.master"
            };

            AreaMasterLocationFormats = new[] {
                "~/Areas/{2}/Views/%1/{1}/{0}.master",
                "~/Areas/{2}/Views/%1/Shared/{0}.master",
            };

            ViewLocationFormats = new[] {
                "~/Views/%1/{1}/{0}.aspx",
                "~/Views/%1/{1}/{0}.ascx",
                "~/Views/%1/Shared/{0}.aspx",
                "~/Views/%1/Shared/{0}.ascx"
            };

            AreaViewLocationFormats = new[] {
                "~/Areas/{2}/Views/%1/{1}/{0}.aspx",
                "~/Areas/{2}/Views/%1/{1}/{0}.ascx",
                "~/Areas/{2}/Views/%1/Shared/{0}.aspx",
                "~/Areas/{2}/Views/%1/Shared/{0}.ascx",
            };

            PartialViewLocationFormats = ViewLocationFormats;
            AreaPartialViewLocationFormats = AreaViewLocationFormats;
        }

        protected override IView CreatePartialView(ControllerContext controllerContext, string partialPath)
        {
            var nameSpace = controllerContext.Controller.GetType().Namespace;
            return base.CreatePartialView(controllerContext, partialPath.Replace("%1", nameSpace));
        }

        protected override IView CreateView(ControllerContext controllerContext, string viewPath, string masterPath)
        {
            var nameSpace = controllerContext.Controller.GetType().Namespace;
            return base.CreateView(controllerContext, viewPath.Replace("%1", nameSpace), masterPath.Replace("%1", nameSpace));
        }

        protected override bool FileExists(ControllerContext controllerContext, string virtualPath)
        {
            var nameSpace = controllerContext.Controller.GetType().Namespace;
            return base.FileExists(controllerContext, virtualPath.Replace("%1", nameSpace));
        }

    }

 

          Here, I am extending the RazorViewEngine and WebFormViewEngine class and then appending /%1 in each views location variable, so that we can replace /%1 at run-time. I am also overriding the FileExists, CreateView and CreatePartialView methods. In each of these method implementation, I am replacing /%1 with controller namespace. Now, just register these view engines in Application_Start method in Global.asax.cs file,

 

    protected void Application_Start()
    {
	ViewEngines.Engines.Clear();
	ViewEngines.Engines.Add(new MyRazorViewEngine());
	ViewEngines.Engines.Add(new MyWebFormViewEngine());
	................................................
	................................................
    }

 

          Now just create a controller and put this controller's view inside Views/ControllerNameSpace/ControllerName folder and then run this application. You will find that everything works just fine.

 

    Summary:

          ASP.NET MVC uses convention over configuration to locate views. For many applications this convention to locate views is acceptable. But sometimes you may need to locate views at run-time. In this article, I showed you how you can dynamically locate your views by using a custom view engine. I am also attaching a sample application. Hopefully you will enjoy this article too.

 

© ASP.net Weblogs or respective owner

Related posts about ASP.NET

Related posts about ASP.NET MVC