Можно ли сделать ASP.NET маршрут MVC на основе поддомена?
возможно ли иметь ASP.NET маршрут MVC, который использует информацию о поддомене для определения своего маршрута? Например:
user1.domain.com идет в одно место
user2.domain.com идет к другому?
или я могу сделать так, чтобы оба они шли к одному контроллеру / действию с ?
9 ответов:
вы можете сделать это, создав новый маршрут и добавив его в коллекцию маршрутов в 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 используйте следующие
SubdomainRoute
класс, производный отRoute
.кроме того,
SubdomainRoute
позволяет субдомену необязательно быть указанным как параметр запроса, сделавsub.example.com/foo/bar
иexample.com/foo/bar?subdomain=sub
эквивалентны. Это позволяет вам проверить, прежде чем субдоменов DNS настроены. Параметр запроса (при использовании) распространяется через новые ссылки, созданныеUrl.Action
, так далее.параметр запроса также позволяет локальную отладку с Visual Studio 2013 без необходимости настройка с помощью netsh или запуск от имени администратора. По умолчанию IIS Express привязывается только к localhost когда не повышен; он не будет привязываться к синонимичным именам хостов, таким как 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); } }
для удобства позвоните по следующему номеру
MapSubdomainRoute
метод от вашегоRegisterRoutes
метод так же, как обычныйMapRoute
: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() }); }
наконец, чтобы удобно получить доступ к поддомену (либо из истинного поддомена, либо из параметра запроса), полезно создать базовый класс контроллера с этим
Subdomain
свойства:protected string Subdomain { get { return (string)Request.RequestContext.RouteData.Values["subdomain"]; } }
Это не моя работа, но я должен был добавить его на этот ответ.
вот отличное решение этой проблемы. Maartin Balliauw написал код, который создает класс 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, переопределите селектор действий, чтобы ввести
subdomain
параметр запроса. Затем используйте параметр запроса поддомена в действиях ваших контроллеров следующим образом:public string Get(string id, string subdomain)
этот подход делает отладку удобной, так как вы можете указать параметр запроса вручную при использовании localhost вместо фактического имени хоста (см. стандартный ответ маршрутизации MVC5 для деталей). Это код для Селектор Действий:
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
:config.Services.Replace(typeof(IHttpActionSelector), new SubdomainActionSelector(config.Services.GetActionSelector()));
да, но вы должны создать свой собственный обработчик маршрута.
обычно маршрут не знает о домене, потому что приложение может быть развернуто в любом домене, и маршрут не будет заботиться так или иначе. Но в вашем случае вы хотите основать контроллер и действие вне домена, поэтому вам придется создать пользовательский маршрут, который знает о домене.
Я создал библиотека для маршрутизации поддомен что вы можете создать такой маршрут. В настоящее время он работает для .NET Core 1.1 и .NET Framework 4.6.1, но будет обновлен в ближайшем будущем. Вот как это работает:
1) Карта маршрута поддомена при запуске.cspublic 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 также будет зависеть от текущего местоположения хоста и схемы.
Вы также можете использовать HTML-помощники дляBeginForm
иUrlHelper
. Если вам нравится, вы также можете использовать новую функцию под названием tag helpers (FormTagHelper
,AnchorTagHelper
)
Эта библиотека еще не имеет никакой документации, но есть некоторые тесты и образцы проекта, поэтому не стесняйтесь исследовать его.
In ASP.NET ядро, хост доступен через
Request.Host.Host
. Если вы хотите разрешить переопределение хоста с помощью параметра запроса, сначала проверьтеRequest.Query
.чтобы заставить параметр запроса хоста распространяться на новые URL-адреса на основе маршрута, добавьте этот код в
app.UseMvc
настройки маршрута: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); }
после определения нового обработчика маршрута, который будет смотреть на хост, переданный в URL, вы можете пойти с идеей базового контроллера, который знает о сайте, к которому он обращается. Выглядит это так:
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(); }
Я отсылаю вас к Блог Люка Сэмпсона
Если вы рассматриваете возможность предоставления Мультитенантности вашему проекту с различными доменами / поддоменами для каждого арендатора, вы должны взглянуть на 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/
изменить: Если вы не хотите использовать SaasKit в своем ASP.NET основной проект вы можете посмотреть на реализацию Маартена доменной маршрутизации для MVC6: https://blog.maartenballiauw.be/post/2015/02/17/domain-routing-and-resolving-current-tenant-with-aspnet-mvc-6-aspnet-5.html
однако эти Gists не поддерживаются и должны быть изменена для работы с последней версией ASP.NET ядро.
прямая ссылка на код: https://gist.github.com/maartenba/77ca6f9cfef50efa96ec#file-domaintemplateroutebuilderextensions-cs
Comments