[asp.net-mvc] 하위 도메인을 기반으로 ASP.NET MVC 경로를 만들 수 있습니까?

하위 도메인 정보를 사용하여 경로를 결정하는 ASP.NET MVC 경로를 가질 수 있습니까? 예를 들면 다음과 같습니다.

  • user1 .domain.com 이 한 곳으로 이동
  • user2 .domain.com 이 다른 사이트로 이동합니까?

또는 둘 다 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/barexample.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메소드에서 다음 메소드를 호출하십시오 .RegisterRoutesMapRoute

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 
))

;


답변

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에는 아직 문서가 없지만 일부 테스트 및 샘플 프로젝트가 있으므로 자유롭게 탐색하십시오.BeginFormUrlHelperFormTagHelperAnchorTagHelper


답변

에서 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);
}