1

我有一个带有区域的 MVC 3 项目,我们称之为 MyArea。我想将特定于 MyArea 的脚本和样式放在该区域的子文件夹下,从而产生如下的项目文件夹结构:

/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

很好,但是现在当我链接到文档/视图中的样式时,它必须这样写:

<link href="/Areas/MyArea/Styles/MyStyle.css" rel="stylesheet" type="text/css" />

我更喜欢这样链接它:

<link href="/MyArea/Styles/MyStyle.css" rel="stylesheet" type="text/css" />

这将与该地区的反对者和行动的路线相同。

我怎样才能实现这个路由?

4

1 回答 1

3

研究了 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() { }
于 2012-12-06T10:36:31.407 回答