1

我有一个 ASP.NET MVC 4 应用程序,其中有两个区域:

  • 后台
  • 注册

我有一个名为的类DomainRoute,可以将整个子域路由到一个区域:

using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using System.Web.Mvc;
using System.Web.Routing;

namespace Admin.Web.PresentationLogic
{
    /// <summary>
    /// DomainRoute is an extension of the default Route, that makes it possible to route domains and subdomains the specific controllers.
    /// </summary>
    public class DomainRoute : Route
    {
        private string _subDomain;

        private string[] _namespaces;

        /// <summary>
        /// Initializes a new instance of the <see cref="DomainRoute"/> class.
        /// </summary>
        /// <param name="subDomain">The sub domain.</param>
        /// <param name="url">The URL format.</param>
        /// <param name="defaults">The defaults.</param>
        public DomainRoute(string subDomain, string url, RouteValueDictionary defaults)
            : base(url, defaults, new MvcRouteHandler())
        {
            this._subDomain = subDomain;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="DomainRoute" /> class.
        /// </summary>
        /// <param name="subDomain">The sub domain.</param>
        /// <param name="url">The URL format.</param>
        /// <param name="defaults">The defaults.</param>
        /// <param name="namespaces">The namespaces.</param>
        public DomainRoute(string subDomain, string url, RouteValueDictionary defaults, string[] namespaces)
            : base(url, defaults, new MvcRouteHandler())
        {
            this._subDomain = subDomain;
            this._namespaces = namespaces;
        }

        /// <summary>
        /// Returns information about the requested route.
        /// </summary>
        /// <param name="httpContext">An object that encapsulates information about the HTTP request.</param>
        /// <returns>
        /// An object that contains the values from the route definition.
        /// </returns>
        public override RouteData GetRouteData(System.Web.HttpContextBase httpContext)
        {
            // Request information
            string requestDomain = httpContext.Request.Headers["HOST"];

            if (!string.IsNullOrEmpty(requestDomain))
            {
                if (requestDomain.IndexOf(":") > 0)
                {
                    requestDomain = requestDomain.Substring(0, requestDomain.IndexOf(":"));
                }
            }
            else
            {
                requestDomain = httpContext.Request.Url.Host;
            }

            var index = requestDomain.IndexOf(".");

            if (index < 0)
            {
                return RouteTable.Routes["Default"].GetRouteData(httpContext);
            }

            var subDomain = requestDomain.Substring(0, index);

            if (!String.IsNullOrWhiteSpace(subDomain))
            {
                if (this._subDomain.Equals(subDomain, StringComparison.InvariantCultureIgnoreCase))
                {
                    RouteData data = new RouteData(this, this.RouteHandler);

                    // Add defaults first 
                    if (Defaults != null)
                    {
                        foreach (KeyValuePair<string, object> item in Defaults)
                        {
                            data.Values[item.Key] = item.Value;
                        }
                    }

                    var pathRegex = this.CreateRegex(Url);
                    var requestPath = httpContext.Request.AppRelativeCurrentExecutionFilePath.Substring(2) + httpContext.Request.PathInfo;

                    // Match domain and route
                    Match pathMatch = pathRegex.Match(requestPath);

                    // Iterate matching path groups 
                    for (int i = 1; i < pathMatch.Groups.Count; i++)
                    {
                        Group group = pathMatch.Groups[i];
                        if (group.Success)
                        {
                            string key = pathRegex.GroupNameFromNumber(i);
                            if (!string.IsNullOrEmpty(key) && !char.IsNumber(key, 0))
                            {
                                if (!string.IsNullOrEmpty(group.Value))
                                {
                                    data.Values[key] = group.Value;
                                }
                            }
                        }
                    }

                    if (!data.Values.ContainsKey("action"))
                    {
                        data.Values.Add("action", "Index");
                    }

                    data.DataTokens["Namespaces"] = this._namespaces;
                    data.DataTokens["area"] = data.Values["area"] ?? this._subDomain;

                    return data;
                }
            }

            return RouteTable.Routes["Default"].GetRouteData(httpContext);
        }

        /// <summary>
        /// Creates the regex.
        /// </summary>
        /// <param name="source">The source.</param>
        /// <returns>Returns the Regex for the source.</returns>
        private Regex CreateRegex(string source)
        {
            // Perform replacements
            source = source.Replace("/", @"\/?");
            source = source.Replace(".", @"\.?");
            source = source.Replace("-", @"\-?");
            source = source.Replace("{", @"(?<");
            source = source.Replace("}", @">([a-zA-Z0-9_]*))");

            return new Regex("^" + source + "$");
        }
    }
}

当我注册区域时,我这样做:

context.Routes.Add("Signup_default", 
    new DomainRoute("signup", "{controller}/{action}/{id}", 
    new RouteValueDictionary(new { area = "Signup", controller = "Home", action = "Index", id = UrlParameter.Optional }), 
    new string[] { "Admin.Web.Areas.Signup.Controllers" }));

因此,问题与DomainRoute'GetRouteData方法的执行方式有关。

每当我尝试访问该类signup.localhost的实例时,就是我在注册 Backstage 区域时使用的实例。DomainRoute

我尝试禁用后台区域,然后注册区域工作。

它使用的实例DomainRoute首先出现在RouteTable.

我错过了什么?

4

1 回答 1

1

我错过了RouteCollection.

在逐步调试到 .Net 源代码后,我意识到在我的 .Net 中DomainRoute,如果子域不匹配,我应该返回而不是返回默认路由数据null

这就是 ASP.NET Routing 确定使用哪个路由的方式——通过调用GetRouteDataHttpContext让特定路由确定“我是否匹配HttpContext?”

于 2012-10-19T11:55:20.517 回答