Created
May 13, 2011 14:06
-
-
Save hugoware/970596 to your computer and use it in GitHub Desktop.
Handles finding views for ASP.NET MVC on case-sensitive file systems
This file contains 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
// Call CaseInsensitiveViewEngine.Register(...) from Global.asax | |
using System; | |
using System.Web; | |
using System.Web.Mvc; | |
using System.Collections.Generic; | |
using System.IO; | |
using System.Linq; | |
using System.Web.Routing; | |
/// <summary> | |
/// Works around case sensitive file systems by locating | |
/// views regardless of the case they are in | |
/// </summary> | |
public class CaseInsensitiveViewEngine : WebFormViewEngine { | |
private static string _Root = HttpContext.Current.Server.MapPath("~/"); | |
//adds a new CaseInsensitiveViewEngine to the routes provided | |
public static void Register(ViewEngineCollection engines) { | |
//clear the existing WebForm View Engines | |
IViewEngine[] webforms = engines.Where(engine => | |
engine is WebFormViewEngine).ToArray(); | |
foreach(IViewEngine engine in webforms) | |
ViewEngines.Engines.Remove(engine); | |
//add the new case-insensitive engine | |
ViewEngines.Engines.Add(new CaseInsensitiveViewEngine()); | |
} | |
//holds all of the actual paths to the required files | |
private static Dictionary<string, string> _ViewPaths = | |
new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); | |
//update the path to match a real file | |
protected override IView CreateView (ControllerContext controllerContext, | |
string viewPath, string masterPath) { | |
viewPath = this._GetActualFilePath(viewPath); | |
masterPath = this._GetActualFilePath(masterPath); | |
return base.CreateView (controllerContext, viewPath, masterPath); | |
} | |
//finds partial views by detecting matches | |
protected override IView CreatePartialView (ControllerContext controllerContext, | |
string partialPath) { | |
partialPath = this._GetActualFilePath(partialPath); | |
return base.CreatePartialView (controllerContext, partialPath); | |
} | |
//perform a case-insensitive file search | |
protected override bool FileExists (ControllerContext context, string virtualPath) { | |
virtualPath = this._GetActualFilePath(virtualPath); | |
return base.FileExists(context, virtualPath); | |
} | |
//determines (and caches) the actual path for a file | |
private string _GetActualFilePath(string virtualPath) { | |
//check if this has already been matched before | |
if (CaseInsensitiveViewEngine._ViewPaths.ContainsKey(virtualPath)) | |
return CaseInsensitiveViewEngine._ViewPaths[virtualPath]; | |
//break apart the path | |
string[] segments = virtualPath.Split(new char[] { '/' }); | |
//get the root folder to work from | |
var folder = new DirectoryInfo(CaseInsensitiveViewEngine._Root); | |
//start stepping up the folders to replace with the correct cased folder name | |
for(int i = 0; i < segments.Length; i++) { | |
string part = segments[i]; | |
bool last = i == segments.Length - 1; | |
//ignore the root | |
if (part.Equals("~")) continue; | |
//process the file name if this is the last segment | |
else if (last) part = this._GetFileName(part, folder); | |
//step up the directory for another part | |
else part = this._GetDirectoryName(part, ref folder); | |
//if no matches were found, just return the original string | |
if (part == null || folder == null) return virtualPath; | |
//update the segment with the correct name | |
segments[i] = part; | |
} | |
//save this path for later use | |
virtualPath = string.Join("/", segments); | |
CaseInsensitiveViewEngine._ViewPaths.Remove(virtualPath); | |
CaseInsensitiveViewEngine._ViewPaths.Add(virtualPath, virtualPath); | |
return virtualPath; | |
} | |
//searches for a matching file name in the current directory | |
private string _GetFileName(string part, DirectoryInfo folder) { | |
//try and find a matching file, regardless of case | |
FileInfo match = folder.GetFiles().FirstOrDefault(file => | |
file.Name.Equals(part, StringComparison.OrdinalIgnoreCase)); | |
return match is FileInfo ? match.Name : null; | |
} | |
//searches for a folder in the current directory and steps up a level | |
private string _GetDirectoryName(string part, ref DirectoryInfo folder) { | |
folder = folder.GetDirectories().FirstOrDefault(dir => | |
dir.Name.Equals(part, StringComparison.OrdinalIgnoreCase)); | |
return folder is DirectoryInfo ? folder.Name : null; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment