하위 도메인 정보를 사용하여 경로를 결정하는 ASP.NET MVC 경로를 가질 수 있습니까? 예를 들면 다음과 같습니다.
- user1 .domain.com 이 한 곳으로 이동
- user2 .domain.com 이 다른 사이트로 이동합니까?
또는 둘 다 username
매개 변수 가있는 동일한 컨트롤러 / 작업으로 만들 수 있습니까?
하위 도메인 정보를 사용하여 경로를 결정하는 ASP.NET MVC 경로를 가질 수 있습니까? 예를 들면 다음과 같습니다.
또는 둘 다 username
매개 변수 가있는 동일한 컨트롤러 / 작업으로 만들 수 있습니까?
답변:
global.asax의 RegisterRoutes에있는 routes 컬렉션에 새 경로를 만들어 추가하면됩니다. 다음은 맞춤 경로의 매우 간단한 예입니다.
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
등에 의해 생성 된 새 링크를 통해 전파됩니다 .
또한 query 매개 변수를 사용하면 netsh 를 사용하여 구성하거나 Administrator로 실행할 필요없이 Visual Studio 2013에서 로컬 디버깅을 수행 할 수 있습니다 . 기본적으로 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);
}
}
편의를 위해 이전과 마찬가지로 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
속성 을 사용하여 Controller 기본 클래스를 만드는 것이 좋습니다 .
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
))
;
SERVER NOT FOUND
오류가 발생했습니다 ... 코드가 작동하지 않음을 의미합니다. 다른 구성이나 무언가를 설정하고 있습니까?!
Web API를 사용할 때 하위 도메인을 캡처하려면 조치 선택기를 대체하여 subdomain
조회 매개 변수 를 삽입하십시오 . 그런 다음 컨트롤러의 작업에서 하위 도메인 쿼리 매개 변수를 다음과 같이 사용하십시오.
public string Get(string id, string subdomain)
이 방법은 실제 호스트 이름 대신 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
.
config.Services.Replace(typeof(IHttpActionSelector), new SubdomainActionSelector(config.Services.GetActionSelector()));
이러한 경로를 만들 수있는 하위 도메인 라우팅 을 위한 라이브러리를 만들었습니다 . 현재 .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을.
및에
HTML 도우미를 사용할 수도 있습니다 . 원하는 경우 태그 헬퍼 ( , ) 라는 새로운 기능을 사용할 수도 있습니다.
해당 lib에는 아직 문서가 없지만 일부 테스트 및 샘플 프로젝트가 있으므로 자유롭게 탐색하십시오.BeginForm
UrlHelper
FormTagHelper
AnchorTagHelper
에서 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();
}
나는 당신이 루크 샘슨 블로그 로 이동 참조
테넌트마다 다른 도메인 / 하위 도메인을 사용하여 프로젝트에 MultiTenancy 기능을 제공하려면 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을 사용하고 싶지 않다면 MVC6에 대한 Maarten의 도메인 라우팅 구현을 살펴볼 수 있습니다 : https://blog.maartenballiauw.be/post/2015/02/17/domain 라우팅 및 해결-현재 테넌트 -with-aspnet-mvc-6-aspnet-5.html
그러나 이러한 요점은 유지 관리되지 않으며 최신 릴리스의 ASP.NET 코어에서 작동하도록 조정해야합니다.
코드에 직접 링크 : https://gist.github.com/maartenba/77ca6f9cfef50efa96ec#file-domaintemplateroutebuilderextensions-cs
몇 달 전에 메소드 또는 컨트롤러를 특정 도메인으로 제한하는 속성을 개발했습니다.
사용하기가 매우 쉽습니다.
[IsDomain("localhost","example.com","www.example.com","*.t1.example.com")]
[HttpGet("RestrictedByHost")]
public IActionResult Test(){}
컨트롤러에 직접 적용 할 수도 있습니다.
public class IsDomainAttribute : Attribute, Microsoft.AspNetCore.Mvc.Filters.IAuthorizationFilter
{
public IsDomainAttribute(params string[] domains)
{
Domains = domains;
}
public string[] Domains { get; }
public void OnAuthorization(AuthorizationFilterContext context)
{
var host = context.HttpContext.Request.Host.Host;
if (Domains.Contains(host))
return;
if (Domains.Any(d => d.EndsWith("*"))
&& Domains.Any(d => host.StartsWith(d.Substring(0, d.Length - 1))))
return;
if (Domains.Any(d => d.StartsWith("*"))
&& Domains.Any(d => host.EndsWith(d.Substring(1))))
return;
context.Result = new Microsoft.AspNetCore.Mvc.NotFoundResult();//.ChallengeResult
}
}
제한 사항 : 다른 필터를 사용하는 다른 방법에 대해 동일한 경로를 두 개 가질 수 없을 수 있습니다. 다음은 중복 경로에 대한 예외가 발생할 수 있음을 의미합니다.
[IsDomain("test1.example.com")]
[HttpGet("/Test")]
public IActionResult Test1(){}
[IsDomain("test2.example.com")]
[HttpGet("/Test")]
public IActionResult Test2(){}