【问题标题】:Route MVC area content the same way as controllers and actions?以与控制器和操作相同的方式路由 MVC 区域内容?
【发布时间】:2012-12-05 11:17:27
【问题描述】:

我有一个带有区域的 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" />

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

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

【问题讨论】:

标签: asp.net-mvc-3 asp.net-mvc-routing asp.net-mvc-areas


【解决方案1】:

研究了 Behnam Esmaili 提到的问题,并进一步阅读,进一步阅读 :-) 这就是我想出的。

我创建了一个新的 IHttpModule,它检查 /areaname/contentfolder/ 的每个传入请求的路径,其中 areaname 是任何应用程序区域的名称,contentfolder 是任何选定的可能内容文件夹名称列表中的任何一个.我选择硬编码一组合理的内容文件夹名称,但您可以让每个区域注册在某处注册其所有内容文件夹名称并使用它。

注意:在线 Microsoft 文档 Walkthrough: Creating and Registering a Custom HTTP Module 建议您将 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() { }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-02-13
    相关资源
    最近更新 更多