posts - 81, comments - 262, trackbacks - 0

Allowing for Dynamic Embedded View Substitution with MVC


A while back I found an interesting post on embedding resources in MVC at "The Glass is Too Big" (http://www.wynia.org/wordpress/2008/12/05/aspnet-mvc-plugins/). Following the method was straightforward and allowed views to be embedded within a Component Class Library. Well, two extra items would be nice. It would be nice to not have to write that large plug-in path, and if a view was defined in the views folder it would be returned in lieu of the embedded view.

Adding this support required two modifications. First the AssemblyResourceProvider was modified to check for the view's existence by adding a Regex pattern match and checking for the file. If the file is found within the view folder, the file is returned, if not the embedded resource will return.

 

   58             // Check to see if a file has been added to the views folder.  If so, return that view.

   59             Match m = Regex.Match(path, @"~/Plugin/[\w\.]+.dll/([\w\.]+).Views.([\w\.]+).aspx");

   60             if (m.Success)

   61             {

   62                 string assemblyMatch = m.Groups[1].Value;

   63                 string viewPath = m.Groups[2].Value;

   64                 string physicalPath = HttpContext.Current.Server.MapPath(String.Format("~/Views/{0}/{1}.aspx",

   65                     assemblyMatch, viewPath.Replace(".", "/")));

   66                 if (File.Exists(physicalPath))

   67                     return File.Open(physicalPath,FileMode.Open);

   68             }

http://www.codeplex.com/unifico/SourceControl/changeset/view/1491#9855

 

To avoid having to write out the plug-in strings I wrote an extension method to write it and return the ViewResult. Reflection is used to gather the assembly name.

 

    9     public static class ControllerPluginPathExtender

   10     {

   11         public static ViewResult PluginView(this Controller controller)

   12         {

   13             string controllerName = controller.RouteData.GetRequiredString("controller");

   14             string viewName = controller.RouteData.GetRequiredString("action");

   15             string assemblyName = controller.GetType().Assembly.FullName.Split(',')[0];

   16             string pluginPath = String.Format(

   17                     @"~/Plugin/{0}.dll/{0}.Views.{1}.{2}.aspx",

   18                     assemblyName,controllerName,viewName

   19                     );

   20             return new ViewResult{

   21                 ViewName = pluginPath

   22             };

   23         }

   24     }

http://www.codeplex.com/unifico/SourceControl/changeset/view/1491#52892

Now using the embedded option is less tedious, for example:

 

   33 

   34         [Authorize(Roles="Admin")]

   35         public ActionResult Index()

   36         {

   37             ViewData["Title"] = "Account Admin Home";

   38             ViewData["Message"] = "Welcome to the account admin";

   39 

   40             return this.PluginView();

   41             //return View("~/Plugin/App.Account.dll/App.Account.Views.Admin.Index.aspx");

   42         }

 

It would be nice to not have to use 'this', but I can't see a way around it without rebuilding MVC, not something I want to start doing. Also some caching and less reflection might be nice.



Update: The VewData and TempData have to be added to pass the models to the view

   11         public static ViewResult PluginView(this Controller controller)

   12         {

   13             string controllerName = controller.RouteData.GetRequiredString("controller");

   14             string viewName = controller.RouteData.GetRequiredString("action");

   15             string assemblyName = controller.GetType().Assembly.FullName.Split(',')[0];

   16             string pluginPath = String.Format(

   17                     @"~/Plugin/{0}.dll/{0}.Views.{1}.{2}.aspx",

   18                     assemblyName,controllerName,viewName

   19                     );

   20             return new ViewResult{

   21                 ViewName = pluginPath,

   22                 ViewData = controller.ViewData,

   23                 TempData = controller.TempData

   24             };

   25         }


Print | posted on Friday, January 2, 2009 10:18 PM | Filed Under [ Web Programming ]

Powered by:
Powered By Subtext Powered By ASP.NET