环境说明

项目采用mvc4,有个area,名称为 demo,访问路径 http://localhost:8098/demo,需要把demo.abc.com 映射到该路径

hosts 配置

127.0.0.1    demo.abc.com

核心代码

 

    public class AreaDomainRegistrationContext
    {
        /// <summary>
        /// 
        /// </summary>
        /// <param name="_domainName">子域名 如:www.xxx.com 可以传 abc</param>
        public AreaDomainRegistrationContext(AreaRegistrationContext _context, string _domainName)
        {
            domainName = _domainName; context = _context;
        }
        private string domainName; private AreaRegistrationContext context;
        private RouteCollection Routes
        {
            get
            {
                if (!DomainRouteTable.DomainRoutes.ContainsKey(domainName))
                {
                    DomainRouteTable.DomainRoutes[domainName] = new RouteCollection();
                }
                return DomainRouteTable.DomainRoutes[domainName];
            }
        }


        public Route MapRoute(string name, string url, object defaults, object constraints = null, string[] namespaces = null)
        {
            if (namespaces == null && context.Namespaces != null)
            {
                namespaces = context.Namespaces.ToArray();
            }

            Route route = Routes.MapRoute(name, url, defaults, constraints, namespaces);
            route.DataTokens["area"] = context.AreaName;
            route.DataTokens["UseNamespaceFallback"] = false;
            route.DataTokens["SubDomain"] = domainName;
            return route;
        }
    }

    public class DomainRouteTable
    {
        private static Dictionary<string, RouteCollection> _instance = new Dictionary<string, RouteCollection>();

        public static Dictionary<string, RouteCollection> DomainRoutes
        {
            get
            {
                return _instance;
            }
        }
    }

    public class DomainRoute : RouteBase
    {
        public ResolveDomainName resolveDomainName = DependencyResolver.Current.GetService<ResolveDomainName>();
        public RouteData d = new RouteData(null, new StopRoutingHandler());

        public override RouteData GetRouteData(HttpContextBase httpContext)
        {
            string domainName = resolveDomainName.Resolve(httpContext);
            //该主机头没有配置,返回 null 继续查找路由
            if (domainName == null) return null;

            if (!DomainRouteTable.DomainRoutes.ContainsKey(domainName)) return d;

            var rs = DomainRouteTable.DomainRoutes[domainName];
            RouteData routeData = rs.GetRouteData(httpContext);
            if (routeData == null) return d;
            return routeData;
        }

        public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
        {
            string domainName = resolveDomainName.Resolve(requestContext.HttpContext);

            if (domainName == null) return null;
            if (!DomainRouteTable.DomainRoutes.ContainsKey(domainName)) return null;

            var rs = DomainRouteTable.DomainRoutes[domainName];
            VirtualPathData vpd = rs.GetVirtualPathForArea(requestContext, values);
            return vpd;
        }
    }
    public class ResolveDomainName
    {
        public static Dictionary<string, string> DomainMap = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
        public string Resolve(HttpContextBase httpContext)
        {
            string key = httpContext.Request.Headers["host"];
            string value;
            if (DomainMap.TryGetValue(key, out value)) { return value; }
            else return null;
        }
    }

调用代码

//Global.asax.cs 的 Application_Start 放在最前面
RouteTable.Routes.Add(new DomainRoute());
ResolveDomainName.DomainMap.Add("demo.abc.com:8098", "demo");

// Area demo 的路由注册
public class demoAreaRegistration : AreaRegistration
{
    public override string AreaName
    {
        get { return "demo"; }
    }

    public override void RegisterArea(AreaRegistrationContext context)
    {
        context.MapRoute(
            name: "demo_default",
            url: "demo/{controller}/{action}",
            defaults: new { controller = "index", action = "index" },
            namespaces: new string[] { "xxx.xxx" });

        var context2 = new AreaDomainRegistrationContext(context, "demo");

        context2.MapRoute(
            name: "demo_default",
            url: "{controller}/{action}",
            defaults: new { controller = "index", action = "index" },
            namespaces: new string[] { "xxx.xxx" });
    }
}

视图使用 bool b = (string)ViewContext.RouteData.DataTokens["SubDomain"] != null; 可以判断请求是否使用demo.abc.com域名访问

使用 http://demo.abc.com:8098/ 和 http://localhost:8098/demo 都可以访问Area demo