是否有可能使一个基于子域的ASP.NET MVC路线?

是否有可能有一个ASP.NET MVC路线,使用子域信息来确定其路线? 例如:

  • user1 .domain.com去一个地方
  • user2 .domain.com转到另一个?

或者,我可以做到这一点,所有这些都与username参数相同的控制器/操作?

你可以通过创build一个新的路由并将其添加到你的global.asax中的RegisterRoutes的路由集合中。 下面是一个非常简单的自定义路由示例:

 public class ExampleRoute : RouteBase { public override RouteData GetRouteData(HttpContextBase httpContext) { var url = httpContext.Request.Headers["HOST"]; var index = url.IndexOf("."); if (index < 0) return null; var subDomain = url.Substring(0, index); if (subDomain == "user1") { var routeData = new RouteData(this, new MvcRouteHandler()); routeData.Values.Add("controller", "User1"); //Goes to the User1Controller class routeData.Values.Add("action", "Index"); //Goes to the Index action on the User1Controller return routeData; } if (subDomain == "user2") { var routeData = new RouteData(this, new MvcRouteHandler()); routeData.Values.Add("controller", "User2"); //Goes to the User2Controller class routeData.Values.Add("action", "Index"); //Goes to the Index action on the User2Controller return routeData; } return null; } public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values) { //Implement your formating Url formating here return null; } } 

在保留标准MVC5路由function的同时捕获子域 ,请使用从Route派生的以下SubdomainRoute类。

此外, SubdomainRoute允许可选地将子域指定为查询参数 ,使sub.example.com/foo/barexample.com/foo/bar?subdomain=sub等价。 这使您可以在DNS子域configuration之前进行testing。 查询参数(在使用时)通过由Url.Action等生成的新链接传播

查询参数还可以使用Visual Studio 2013进行本地debugging,而无需使用netsh进行configuration或以pipe理员身份运行 。 默认情况下,IIS Express仅在未提升时绑定到本地主机 ; 它不会绑定到像sub.localtest.me这样的同义主机名。

 class SubdomainRoute : Route { public SubdomainRoute(string url) : base(url, new MvcRouteHandler()) {} public override RouteData GetRouteData(HttpContextBase httpContext) { var routeData = base.GetRouteData(httpContext); if (routeData == null) return null; // Only look at the subdomain if this route matches in the first place. string subdomain = httpContext.Request.Params["subdomain"]; // A subdomain specified as a query parameter takes precedence over the hostname. if (subdomain == null) { string host = httpContext.Request.Headers["Host"]; int index = host.IndexOf('.'); if (index >= 0) subdomain = host.Substring(0, index); } if (subdomain != null) routeData.Values["subdomain"] = subdomain; return routeData; } public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values) { object subdomainParam = requestContext.HttpContext.Request.Params["subdomain"]; if (subdomainParam != null) values["subdomain"] = subdomainParam; return base.GetVirtualPath(requestContext, values); } } 

为了方便起见,您可以像使用普通的MapRoute一样从RegisterRoutes方法调用以下MapSubdomainRoute方法:

 static void MapSubdomainRoute(this RouteCollection routes, string name, string url, object defaults = null, object constraints = null) { routes.Add(name, new SubdomainRoute(url) { Defaults = new RouteValueDictionary(defaults), Constraints = new RouteValueDictionary(constraints), DataTokens = new RouteValueDictionary() }); } 

最后,为了方便地访问子域(从一个真实的子域或一个查询参数),创build一个具有这个Subdomain属性的控制器基类是有帮助的:

 protected string Subdomain { get { return (string)Request.RequestContext.RouteData.Values["subdomain"]; } } 

这不是我的工作,但我不得不把它添加到这个答案。

这是一个很好的解决这个问题的方法。 Maartin Balliauw写了创build一个DomainRoute类的代码,可以使用非常类似于正常的路由。

http://blog.maartenballiauw.be/post/2009/05/20/ASPNET-MVC-Domain-Routing.aspx

示例使用会是这样的…

 routes.Add("DomainRoute", new DomainRoute( "{customer}.example.com", // Domain with parameters "{action}/{id}", // URL with parameters new { controller = "Home", action = "Index", id = "" } // Parameter defaults )) 

;

要在使用Web API时捕获子域,请重写“动作select器”以注入subdomain查询参数。 然后在控制器的操作中使用子域查询参数,如下所示:

 public string Get(string id, string subdomain) 

这种方法使得debugging变得很方便,因为当使用localhost而不是实际的主机名(请参阅标准的MVC5路由答案了解详情)时,您可以手动指定查询参数。 这是Action Selector的代码:

 class SubdomainActionSelector : IHttpActionSelector { private readonly IHttpActionSelector defaultSelector; public SubdomainActionSelector(IHttpActionSelector defaultSelector) { this.defaultSelector = defaultSelector; } public ILookup<string, HttpActionDescriptor> GetActionMapping(HttpControllerDescriptor controllerDescriptor) { return defaultSelector.GetActionMapping(controllerDescriptor); } public HttpActionDescriptor SelectAction(HttpControllerContext controllerContext) { var routeValues = controllerContext.Request.GetRouteData().Values; if (!routeValues.ContainsKey("subdomain")) { string host = controllerContext.Request.Headers.Host; int index = host.IndexOf('.'); if (index >= 0) controllerContext.Request.GetRouteData().Values.Add("subdomain", host.Substring(0, index)); } return defaultSelector.SelectAction(controllerContext); } } 

通过将此添加到WebApiConfig.Register来replace默认的动作select器:

 config.Services.Replace(typeof(IHttpActionSelector), new SubdomainActionSelector(config.Services.GetActionSelector())); 

是的,但你必须创build自己的路由处理程序。

通常情况下,路由不知道域,因为应用程序可以部署到任何域,路由不会在意这种或那种方式。 但在你的情况下,你想基于控制器和行动的领域,所以你将不得不创build一个自定义路由,知道该域名。

ASP.NET Core中 ,主机通过Request.Host.Host 。 如果要允许通过查询参数覆盖主机,请首先检查Request.Query

要使主机查询参数传播到新的基于路由的URL,请将此代码添加到app.UseMvc路由configuration中:

 routes.Routes.Add(new HostPropagationRouter(routes.DefaultHandler)); 

并像这样定义HostPropagationRouter

 /// <summary> /// A router that propagates the request's "host" query parameter to the response. /// </summary> class HostPropagationRouter : IRouter { readonly IRouter router; public HostPropagationRouter(IRouter router) { this.router = router; } public VirtualPathData GetVirtualPath(VirtualPathContext context) { if (context.HttpContext.Request.Query.TryGetValue("host", out var host)) context.Values["host"] = host; return router.GetVirtualPath(context); } public Task RouteAsync(RouteContext context) => router.RouteAsync(context); } 

我创build了子域路由的库 ,您可以创build这样的路线。 它目前正在为.NET Core 1.1和.NET Framework 4.6.1工作,但将在不久的将来更新。 这是如何工作的:
1)在Startup.cs中映射子域路由

 public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) { var hostnames = new[] { "localhost:54575" }; app.UseMvc(routes => { routes.MapSubdomainRoute( hostnames, "SubdomainRoute", "{username}", "{controller}/{action}", new { controller = "Home", action = "Index" }); )}; 

2)控制器/ HomeController.cs

 public IActionResult Index(string username) { //code } 

3)该lib还将允许您生成URL和表单。 码:

 @Html.ActionLink("User home", "Index", "Home" new { username = "user1" }, null) 

将生成<a href="http://user1.localhost:54575/Home/Index">User home</a>生成的URL也将取决于当前的主机位置和架构。
您也可以使用BeginFormUrlHelper html助手。 如果你喜欢,你也可以使用称为标签助手( FormTagHelperAnchorTagHelper )的新function,
那个lib还没有任何文档,但是有一些testing和示例项目,所以可以随意探索它。

在定义了一个新的Route处理程序来查看在URL中传递的主机之后 ,可以使用基本Controller的想法来知道它正在被访问的Site。 它看起来像这样:

 public abstract class SiteController : Controller { ISiteProvider _siteProvider; public SiteController() { _siteProvider = new SiteProvider(); } public SiteController(ISiteProvider siteProvider) { _siteProvider = siteProvider; } protected override void Initialize(RequestContext requestContext) { string[] host = requestContext.HttpContext.Request.Headers["Host"].Split(':'); _siteProvider.Initialise(host[0]); base.Initialize(requestContext); } protected override void OnActionExecuting(ActionExecutingContext filterContext) { ViewData["Site"] = Site; base.OnActionExecuting(filterContext); } public Site Site { get { return _siteProvider.GetCurrentSite(); } } } 

ISiteProvider是一个简单的界面:

 public interface ISiteProvider { void Initialise(string host); Site GetCurrentSite(); } 

我指你去卢克·桑普森博客

如果您正在考虑为您的项目提供多租户function,并为每个租户提供不同的域/子域名,则应该查看SaasKit:

https://github.com/saaskit/saaskit

代码示例可以在这里看到: http : //benfoster.io/blog/saaskit-multi-tenancy-made-easy

一些使用ASP.NET核心的例子: http : //andrewlock.net/forking-the-pipeline-adding-tenant-specific-files-with-saaskit-in-asp-net-core/

编辑:如果你不想在你的ASP.NET核心项目中使用SaasKit,你可以看看Maarten为MVC6的域路由实现: https ://blog.maartenballiauw.be/post/2015/02/17/domain -routing-和分辨电stream租户与- ASPNET-MVC -6- ASPNET-5.html

但是这些Gist没有被维护,需要调整以使用最新版本的ASP.NET核心。

直接链接到代码: https : //gist.github.com/maartenba/77ca6f9cfef50efa96ec#file-domaintemplateroutebuilderextensions-cs