I’ve got a MVC 3 project with an area, let’s call it MyArea. I’d like to place scripts and styles that are specific to MyArea under that area’s subfolder, resulting in a project folder structure like this:
/Areas/MyArea
/Areas/MyArea/Controllers
/Areas/MyArea/Scripts <-------- I want these here
/Areas/MyArea/Styles <--------
/Areas/MyArea/ViewModels
/Areas/MyArea/Views
/Controllers
/Scripts
/Styles
/ViewModels
/Views
Fine, but now when I link to a style in the document/view it has to be written like this:
<link href="/Areas/MyArea/Styles/MyStyle.css" rel="stylesheet" type="text/css" />
I’d prefer to link it like this:
<link href="/MyArea/Styles/MyStyle.css" rel="stylesheet" type="text/css" />
This would be the same routing as for the area’s countrollers and actions.
How can I achieve this routing?
Having researched the question mentioned by Behnam Esmaili, and read further, and further, and further 🙂 this is what I came up with.
I created a new IHttpModule that checks the path of each incoming request for
/areaname/contentfolder/, whereareanameis the name of any of the application’s areas, andcontentfolderis any of any selected list of possible content folder names. I chose to hardcode a set of plausible content folder names, but you could have each area registration register all its content folder names somewhere and use that.Note: The online Microsoft doc Walkthrough: Creating and Registering a Custom HTTP Module suggests you place the HTTPModule class in the App_Code folder. Don’t! Classes in that folder are runtime compiled by ASP.Net, resulting in a binry copy of the class in the temp .Net folder, which in turn causes ambiguity when ASP.Net tries to load the HTTPModule class. Place the class in a different folder of your choice.
To find all area names, I chose to use
AppDomain.CurrentDomain.GetAssemblies()and find all subclasses ofSystem.Web.Mvc.AreaRegistration. Create an instance of each one and retrieve the value of itsAreaNameproperty.Full source code:
EDIT: Apparently, the above solution does not work for applications that ate not at the root of the domain. After some work I came up with the following solution instead: