I prefer to work with one class per controller action in my MVC apps, however I'd to be able to structure my view folder with one folder per "controller".
I use routes like /Admin/Login which maps to a class called AdminLoginController and /Admin/Index which would map to AdminIndexController. However, I'd like to structure my view folder such that I have a single folder called Admin and then 2 files called login.cshtml and index.cshtml.
To do that it looks like I need to override the ViewEngine. I've got it working with the following code:
public class MyViewEngine : RazorViewEngine
{
public override ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache)
{
var controllerTypeName = controllerContext.RouteData.GetRequiredString("controller");
var controllerParts =_GetControllerNameParts(controllerTypeName);
var folderName = controllerParts.Take(controllerParts.Length - 1).Aggregate((s1, s2) => s1 + s2);
viewName = controllerParts[controllerParts.Length - 1];
var filename = _GetFilename(folderName, viewName, controllerContext);
return new ViewEngineResult(CreateView(controllerContext, filename, masterName), this);
}
private string[] _GetControllerNameParts(string controllerTypeName)
{
var r = new Regex(@"
(?<=[A-Z])(?=[A-Z][a-z]) |
(?<=[^A-Z])(?=[A-Z]) |
(?<=[A-Za-z])(?=[^A-Za-z])", RegexOptions.IgnorePatternWhitespace);
return r.Split(controllerTypeName);
}
private string _GetFilename(string folderName, string viewName, ControllerContext controllerContext)
{
var path = string.Format("~/Views/{0}/{1}.cshtml", folderName, viewName);
var filename = controllerContext.HttpContext.Server.MapPath(path);
if (File.Exists(filename)) { return path; }
return null;
}
}
I'd like to know if there's a better way, in particular, the base view engine does a bunch of caching etc which I'd like to take advantage of.
Has anyone done something similar?
Thanks, Matt