Created
May 2, 2013 02:09
-
-
Save MattHoneycutt/5499729 to your computer and use it in GitHub Desktop.
A Razor view engine that supports several methods of organizing views and controllers within the same folder.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class ModularConventionViewEngine : RazorViewEngine | |
{ | |
//This needs to be initialized to the root namespace of your MVC project. | |
//Usually, the namespace of your Global.asax's codebehind will do the trick. | |
private static readonly string RootNamespace = typeof(MvcApplication).Namespace; | |
private static IEnumerable<string> GetPath(ControllerContext controllerContext, string viewName) | |
{ | |
var paths = new List<string>(); | |
//TODO: Cache? | |
var controllerType = controllerContext.Controller.GetType(); | |
var controllerName = controllerType.Name.Replace("Controller", string.Empty); | |
var featureFolder = "~" + controllerType.Namespace.Replace(RootNamespace, string.Empty).Replace(".", "/"); | |
//View in the same folder as controller (controller-folder/view.cshtml) | |
paths.Add(string.Format("{0}/{1}.cshtml", featureFolder, viewName)); | |
//View in a view-folder within controller-folder (controller-folder/views/view.cshtml) | |
paths.Add(string.Format("{0}/Views/{1}.cshtml", featureFolder, viewName)); | |
//View in folder with controller name within a view-folder within a controller-folder (controller-folder/views/controller-name/view.cshtml) | |
paths.Add(string.Format("{0}/Views/{1}/{2}.cshtml", featureFolder, controllerName, viewName)); | |
return paths; | |
} | |
public override ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache) | |
{ | |
var paths = GetPath(controllerContext, viewName); | |
var path = paths.FirstOrDefault(p => VirtualPathProvider.FileExists(p)); | |
if (path != null) | |
{ | |
return new ViewEngineResult(CreateView(controllerContext, path, null), this); | |
} | |
//Check the usual suspects | |
return base.FindView(controllerContext, viewName, masterName, useCache); | |
} | |
public override ViewEngineResult FindPartialView(ControllerContext controllerContext, string partialViewName, bool useCache) | |
{ | |
var paths = GetPath(controllerContext, partialViewName); | |
var path = paths.FirstOrDefault(p => VirtualPathProvider.FileExists(p)); | |
if (path != null) | |
{ | |
return new ViewEngineResult(CreateView(controllerContext, path, null), this); | |
} | |
//check the usual suspects | |
return base.FindPartialView(controllerContext, partialViewName, useCache); | |
} | |
} |
private string GetPath(ControllerContext controllerContext, string viewName)
{
string path;
var ctrlProps = GetControllerProperties(controllerContext, viewName);
//check if in cache
var found = ViewPathCache.TryGetValue(ctrlProps.cachekey, out path);
if (!found && ctrlProps.controllerNameSpace != null)
{
IEnumerable<string> paths = GetPossiblePaths(ctrlProps.controllerNameSpace, ctrlProps.controllerName, viewName);
path = paths.FirstOrDefault(p => VirtualPathProvider.FileExists(p));
//add to cache or indicate to delegate processing by adding a null for path
ViewPathCache.TryAdd(ctrlProps.cachekey, path);
}
return path;
}
Fix to render a partial as a partial not as a view
public override ViewEngineResult FindPartialView(ControllerContext controllerContext, string partialViewName, bool useCache)
{
var path = GetPath(controllerContext, partialViewName);
if (path != null)
{
return new ViewEngineResult(CreatePartialView(controllerContext, path), this);
}
//check the usual suspects
return base.FindPartialView(controllerContext, partialViewName, useCache);
}
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Attempt at caching the valid view locations