研究了 Behnam Esmaili 提到的问题,并进一步阅读,进一步阅读 :-) 这就是我想出的。
我创建了一个新的 IHttpModule 来检查每个传入请求的路径/areaname/contentfolder/
,其中areaname
是任何应用程序区域的名称,并且contentfolder
是任何选定的可能内容文件夹名称列表中的任何一个。我选择硬编码一组合理的内容文件夹名称,但您可以让每个区域注册在某处注册其所有内容文件夹名称并使用它。
注意:在线 Microsoft 文档演练:创建和注册自定义 HTTP 模块建议您将 HTTPModule 类放在 App_Code 文件夹中。不!该文件夹中的类由 ASP.Net 运行时编译,从而在 temp .Net 文件夹中生成该类的二进制副本,这反过来在 ASP.Net 尝试加载 HTTPModule 类时会导致歧义。将课程放在您选择的不同文件夹中。
为了查找所有区域名称,我选择使用AppDomain.CurrentDomain.GetAssemblies()
并查找System.Web.Mvc.AreaRegistration
. 创建每个实例并检索其AreaName
属性的值。
完整源代码:
public class HTTPModuleAreaContent : IHttpModule
{
private List<string> allAreaNames = null;
public HTTPModuleAreaContent()
{
}
public String ModuleName
{
get { return "HTTPModuleAreaContent"; }
}
public void Init(HttpApplication application)
{
application.BeginRequest +=
(new EventHandler(this.BeginRequest));
}
private void GetAreaNames(HttpContext context)
{
allAreaNames = AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(ass => ass.GetTypes())
.Where(t => t.IsSubclassOf(typeof(AreaRegistration)))
.Select(t => ((AreaRegistration)Activator.CreateInstance(t)).AreaName)
.ToList();
}
private void BeginRequest(object sender, EventArgs e)
{
HttpApplication application = (HttpApplication)sender;
HttpContext context = application.Context;
if (allAreaNames == null)
GetAreaNames(context);
string filePath = context.Request.FilePath.ToUpper();
string areaName = allAreaNames
.FirstOrDefault(an => filePath.StartsWith('/' + an + '/', StringComparison.OrdinalIgnoreCase));
if (string.IsNullOrEmpty(areaName))
return;
string areaNameUpper = areaName.ToUpper();
if (filePath.StartsWith('/' + areaNameUpper + "/STYLES/")
|| filePath.StartsWith('/' + areaNameUpper + "/SCRIPT/")
|| filePath.StartsWith('/' + areaNameUpper + "/SCRIPTS/")
|| filePath.StartsWith('/' + areaNameUpper + "/JS/")
|| filePath.StartsWith('/' + areaNameUpper + "/JAVASCRIPT/")
|| filePath.StartsWith('/' + areaNameUpper + "/JAVASCRIPTS/")
|| filePath.StartsWith('/' + areaNameUpper + "/CONTENT/")
|| filePath.StartsWith('/' + areaNameUpper + "/IMAGES/")
)
context.RewritePath("/Areas/" + context.Request.Path);
}
public void Dispose() { }
}
编辑:显然,上述解决方案不适用于不在域根目录的应用程序。经过一些工作,我想出了以下解决方案:
public class HTTPModuleAreaContent : IHttpModule
{
private List<string> allAreaNames = null;
private HashSet<string> folderNamesToRewrite = new HashSet<string>();
public HTTPModuleAreaContent()
{
}
public String ModuleName
{
get { return "HTTPModuleAreaContent"; }
}
public void Init(HttpApplication application)
{
application.BeginRequest +=
(new EventHandler(this.BeginRequest));
folderNamesToRewrite.Add("STYLES");
folderNamesToRewrite.Add("SCRIPT");
folderNamesToRewrite.Add("SCRIPTS");
folderNamesToRewrite.Add("JS");
folderNamesToRewrite.Add("JAVASCRIPT");
folderNamesToRewrite.Add("JAVASCRIPTS");
folderNamesToRewrite.Add("CONTENT");
folderNamesToRewrite.Add("IMAGES");
}
private void GetAreaNames(HttpContext context)
{
allAreaNames = AppDomain.CurrentDomain.GetAssemblies().SelectMany(ass => ass.GetTypes()).Where(t => t.IsSubclassOf(typeof(AreaRegistration))).Select(t => ((AreaRegistration)Activator.CreateInstance(t)).AreaName).ToList();
}
private void BeginRequest(object sender, EventArgs e)
{
HttpApplication application = (HttpApplication)sender;
HttpContext context = application.Context;
if (allAreaNames == null)
GetAreaNames(context);
string filePath = context.Request.FilePath;
string areaName = allAreaNames.FirstOrDefault(an => Regex.IsMatch(filePath, '/' + an + '/', RegexOptions.IgnoreCase | RegexOptions.CultureInvariant));
if (string.IsNullOrEmpty(areaName))
return;
string areaNameUpper = areaName.ToUpperInvariant();
Regex regex = new Regex('/' + areaNameUpper + "/([^/]+)/", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant);
Match m = regex.Match(filePath);
if (m.Success && m.Groups.Count > 1)
{
string folderName = m.Groups[1].Value;
string folderNameUpper = folderName.ToUpperInvariant();
if (folderNamesToRewrite.Contains(folderNameUpper))
context.RewritePath(regex.Replace(context.Request.Path, string.Format("/Areas/{0}/{1}/", areaName, folderName), 1));
}
}
public void Dispose() { }