asp.net mvc 路由绑定域名
原文地址:https://gist.github.com/IDisposable/77f11c6f7693f9d181bb
using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Net.Http; using System.Text.RegularExpressions; using System.Web; using System.Web.Http; using System.Web.Http.Routing; using System.Web.Mvc; using System.Web.Routing; namespace Alerts.Helpers { internal static class DomainRegexCache { // since we're often going to have the same pattern used in multiple routes, it's best to build just one regex per pattern private static ConcurrentDictionary<string, Regex> _domainRegexes = new ConcurrentDictionary<string, Regex>(); internal static Regex CreateDomainRegex(string domain) { return _domainRegexes.GetOrAdd(domain, (d) => { d = d.Replace("/", @"\/") .Replace(".", @"\.") .Replace("-", @"\-") .Replace("{", @"(?<") .Replace("}", @">(?:[a-zA-Z0-9_-]+))"); return new Regex("^" + d + "$", RegexOptions.Compiled | RegexOptions.CultureInvariant | RegexOptions.ExplicitCapture); }); } } public class DomainRoute : Route { private const string DomainRouteMatchKey = "DomainRoute.Match"; private const string DomainRouteInsertionsKey = "DomainRoute.Insertions"; private Regex _domainRegex; public string Domain { get; private set; } public DomainRoute(string domain, string url, RouteValueDictionary defaults) : this(domain, url, defaults, new MvcRouteHandler()) { } public DomainRoute(string domain, string url, object defaults) : this(domain, url, new RouteValueDictionary(defaults), new MvcRouteHandler()) { } public DomainRoute(string domain, string url, object defaults, IRouteHandler routeHandler) : this(domain, url, new RouteValueDictionary(defaults), routeHandler) { } public DomainRoute(string domain, string url, RouteValueDictionary defaults, IRouteHandler routeHandler) : base(url, defaults, routeHandler) { Domain = domain; _domainRegex = DomainRegexCache.CreateDomainRegex(Domain); } public override RouteData GetRouteData(HttpContextBase httpContext) { var requestDomain = httpContext.Request.Url.Host; var domainMatch = _domainRegex.Match(requestDomain); if (!domainMatch.Success) return null; var existingMatch = httpContext.Items[DomainRouteMatchKey] as string; if (existingMatch == null) httpContext.Items[DomainRouteMatchKey] = Domain; else if (existingMatch != Domain) return null; var data = base.GetRouteData(httpContext); if (data == null) return null; var myInsertions = new HashSet<string>(); for (var i = 1; i < domainMatch.Groups.Count; i++) { var group = domainMatch.Groups[i]; if (group.Success) { var key = _domainRegex.GroupNameFromNumber(i); if (!String.IsNullOrEmpty(key) && !String.IsNullOrEmpty(group.Value)) { // could throw here if data.Values.ContainsKey(key) if we wanted to prevent multiple matches data.Values[key] = group.Value; myInsertions.Add(key); } } } httpContext.Items[DomainRouteInsertionsKey] = myInsertions; return data; } public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values) { return base.GetVirtualPath(requestContext, RemoveDomainTokens(requestContext, values)); } private RouteValueDictionary RemoveDomainTokens(RequestContext requestContext, RouteValueDictionary values) { var myInsertions = requestContext.HttpContext.Items[DomainRouteInsertionsKey] as HashSet<string>; if (myInsertions != null) { foreach (var key in myInsertions) { if (values.ContainsKey(key)) values.Remove(key); } } return values; } } // For MVC routes public class DomainRouteCollection { private string Domain { get; set; } private RouteCollection Routes { get; set; } public DomainRouteCollection(string domain, RouteCollection routes) { Domain = domain; Routes = routes; } public Route MapRoute(string name, string url) { return MapRoute(name, url, null, null, null); } public Route MapRoute(string name, string url, object defaults) { return MapRoute(name, url, defaults, null, null); } public Route MapRoute(string name, string url, string[] namespaces) { return MapRoute(name, url, null, null, namespaces); } public Route MapRoute(string name, string url, object defaults, object constraints) { return MapRoute(name, url, defaults, constraints, null); } public Route MapRoute(string name, string url, object defaults, string[] namespaces) { return MapRoute(name, url, defaults, null, namespaces); } public Route MapRoute(string name, string url, object defaults, object constraints, string[] namespaces) { if (name == null) throw new ArgumentNullException("name"); if (url == null) throw new ArgumentNullException("url"); var route = new DomainRoute(Domain, url, defaults, new MvcRouteHandler()) { Constraints = new RouteValueDictionary(constraints), DataTokens = new RouteValueDictionary() }; if (namespaces != null && namespaces.Length > 0) route.DataTokens["Namespaces"] = namespaces; Routes.Add(name, route); return route; } } // For Areas routes public class DomainAreaRegistrationContext { private AreaRegistrationContext Context { get; set; } private DomainRouteCollection Routes { get; set; } public DomainAreaRegistrationContext(string domain, AreaRegistrationContext context) { Context = context; Routes = new DomainRouteCollection(domain, Context.Routes); } public Route MapRoute(string name, string url) { return MapRoute(name, url, null, null, null); } public Route MapRoute(string name, string url, object defaults) { return MapRoute(name, url, defaults, null, null); } public Route MapRoute(string name, string url, string[] namespaces) { return MapRoute(name, url, null, null, namespaces); } public Route MapRoute(string name, string url, object defaults, object constraints) { return MapRoute(name, url, defaults, constraints, null); } public Route MapRoute(string name, string url, object defaults, string[] namespaces) { return MapRoute(name, url, defaults, null, namespaces); } public Route MapRoute(string name, string url, object defaults, object constraints, string[] namespaces) { if (namespaces == null && Context.Namespaces != null) namespaces = Context.Namespaces.ToArray(); var route = Routes.MapRoute(name, url, defaults, constraints, namespaces); route.DataTokens["area"] = Context.AreaName; // disabling the namespace lookup fallback mechanism keeps this area from accidentally picking up // controllers belonging to other areas bool useNamespaceFallback = (namespaces == null || namespaces.Length == 0); route.DataTokens["UseNamespaceFallback"] = useNamespaceFallback; return route; } } // WebApi Routes public class DomainHttpRoute : HttpRoute { private const string DomainRouteMatchKey = "DomainHttpRoute.Match"; private const string DomainRouteInsertionsKey = "DomainHttpRoute.Insertions"; private Regex _domainRegex; public string Domain { get; private set; } public DomainHttpRoute(string domain) : this(domain, (string)null, (HttpRouteValueDictionary)null, (HttpRouteValueDictionary)null, (HttpRouteValueDictionary)null, (HttpMessageHandler)null) { } public DomainHttpRoute(string domain, string routeTemplate) : this(domain, routeTemplate, (HttpRouteValueDictionary)null, (HttpRouteValueDictionary)null, (HttpRouteValueDictionary)null, (HttpMessageHandler)null) { } public DomainHttpRoute(string domain, string routeTemplate, HttpRouteValueDictionary defaults) : this(domain, routeTemplate, defaults, (HttpRouteValueDictionary)null, (HttpRouteValueDictionary)null, (HttpMessageHandler)null) { } public DomainHttpRoute(string domain, string routeTemplate, HttpRouteValueDictionary defaults, HttpRouteValueDictionary constraints) : this(domain, routeTemplate, defaults, constraints, (HttpRouteValueDictionary)null, (HttpMessageHandler)null) { } public DomainHttpRoute(string domain, string routeTemplate, HttpRouteValueDictionary defaults, HttpRouteValueDictionary constraints, HttpRouteValueDictionary dataTokens) : this(domain, routeTemplate, defaults, constraints, dataTokens, (HttpMessageHandler)null) { } public DomainHttpRoute(string domain, string routeTemplate, HttpRouteValueDictionary defaults, HttpRouteValueDictionary constraints, HttpRouteValueDictionary dataTokens, HttpMessageHandler handler) : base(routeTemplate, defaults, constraints, dataTokens, handler) { Domain = domain; _domainRegex = DomainRegexCache.CreateDomainRegex(Domain); } public override IHttpRouteData GetRouteData(string virtualPathRoot, HttpRequestMessage request) { var requestDomain = request.RequestUri.Host; var domainMatch = _domainRegex.Match(requestDomain); if (!domainMatch.Success) return null; object existingMatch; if (!request.Properties.TryGetValue(DomainRouteMatchKey, out existingMatch)) request.Properties[DomainRouteMatchKey] = Domain; else if (Domain != existingMatch as string) return null; var data = base.GetRouteData(virtualPathRoot, request); if (data == null) return null; var myInsertions = new HashSet<string>(); for (var i = 1; i < domainMatch.Groups.Count; i++) { var group = domainMatch.Groups[i]; if (group.Success) { var key = _domainRegex.GroupNameFromNumber(i); if (!String.IsNullOrEmpty(key) && !String.IsNullOrEmpty(group.Value)) { // could throw here if data.Values.ContainsKey(key) if we wanted to prevent multiple matches data.Values[key] = group.Value; myInsertions.Add(key); } } } request.Properties[DomainRouteInsertionsKey] = myInsertions; return data; } public override IHttpVirtualPathData GetVirtualPath(HttpRequestMessage request, IDictionary<string, object> values) { return base.GetVirtualPath(request, RemoveDomainTokens(request, values)); } private IDictionary<string, object> RemoveDomainTokens(HttpRequestMessage request, IDictionary<string, object> values) { var myInsertions = request.Properties[DomainRouteInsertionsKey] as HashSet<string>; if (myInsertions != null) { foreach (var key in myInsertions) { if (values.ContainsKey(key)) values.Remove(key); } } return values; } } // for WebApi routes public class DomainHttpRouteCollection { private string Domain { get; set; } private HttpRouteCollection Routes { get; set; } public DomainHttpRouteCollection(string domain, HttpRouteCollection routes) { Domain = domain; Routes = routes; } public IHttpRoute MapDomainHttpRoute(string name, string routeTemplate) { return MapDomainHttpRoute(name, routeTemplate, null, null, null); } public IHttpRoute MapDomainHttpRoute(string name, string routeTemplate, object defaults) { return MapDomainHttpRoute(name, routeTemplate, defaults, null, null); } public IHttpRoute MapDomainHttpRoute(string name, string routeTemplate, object defaults, object constraints) { return MapDomainHttpRoute(name, routeTemplate, defaults, constraints, null); } public IHttpRoute MapDomainHttpRoute(string name, string routeTemplate, object defaults, object constraints, HttpMessageHandler handler) { if (name == null) throw new ArgumentNullException("name"); if (routeTemplate == null) throw new ArgumentNullException("routeTemplate"); var route = new DomainHttpRoute(Domain, routeTemplate, new HttpRouteValueDictionary(defaults), new HttpRouteValueDictionary(constraints)); Routes.Add(name, route); return route; } } }
使用方法:
using System.Web.Mvc; using YourApplication; namespace YourApplication.Areas.Login { public class LoginAreaRegistration : AreaRegistration { public override string AreaName { get { return "Login"; } } public override void RegisterArea(AreaRegistrationContext context) { var loginAreaContext = new DomainAreaRegistrationContext("login" + MvcApplication.DnsSuffix, context); loginAreaContext.MapRoute( name: "Login", url: "", defaults: new { controller = "Login", action = "Login", id = UrlParameter.Optional } ); } } }
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; using System.Web.Routing; namespace YourApplication { public class RouteConfig { public static void RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); var clientRoutes = new DomainRouteCollection("{clientHost}" + MvcApplication.DnsSuffix, routes); RegisterRootRoutes(clientRoutes); } private static void RegisterRootRoutes(DomainRouteCollection routes) { routes.MapRoute( name: "Root/Index", url: "", defaults: new { controller = "Root", action = "Index" } ); } } }
using System.Web.Http; using System.Web.Http.ExceptionHandling; using System.Web.Http.ModelBinding; using YourApi; namespace YourApi { public static class WebApiConfig { public static void Register(HttpConfiguration config) { var clientApiRoutes = new DomainHttpRouteCollection("{clientHost}" + MvcApplication.ClientSuffix, config.Routes); clientApiRoutes.MapDomainHttpRoute( name: "DefaultApi", routeTemplate: "api/v1/{controller}/{action}" ); } } }
Categories:
.net
已禁用评论。