Czy możliwe jest wykonanie ASP.NET trasa MVC oparta na subdomenie?

Czy możliwe jest posiadanie ASP.NET trasa MVC, która wykorzystuje informacje o subdomenie do określenia swojej trasy? Na przykład:

  • user1.domain.com goes to one place
  • user2.domain.com idzie do innego?

Lub, Czy Mogę sprawić, że oba te elementy trafią do tego samego kontrolera / akcji z parametrem username?

Author: tereško, 2008-11-10

9 answers

Możesz to zrobić, tworząc nową trasę i dodając ją do kolekcji tras w RegisterRoutes w Twojej globalnej.asax. Poniżej znajduje się bardzo prosty przykład niestandardowej trasy:

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;
    }
}
 166
Author: Jon Cahill,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-02-12 14:30:49

Aby przechwycić subdomenę zachowując standardowe funkcje routingu MVC5, użyj następującej klasy SubdomainRoute pochodzącej z Route.

Dodatkowo, SubdomainRoutepozwala na opcjonalne określenie subdomeny jako parametru zapytania , co sprawia, że sub.example.com/foo/bar i example.com/foo/bar?subdomain=sub są równoważne. Pozwala to na przetestowanie przed skonfigurowaniem poddomen DNS. Parametr zapytania (gdy jest używany) jest propagowany przez nowe linki generowane przez Url.Action, itd.

Parametr zapytania również umożliwia lokalne debugowanie za pomocą programu Visual Studio 2013 bez konieczności konfigurowania za pomocą netsh lub uruchamiania jako Administrator . Domyślnie IIS Express wiąże się tylko z localhost, gdy nie jest podniesiony; nie będzie wiązać się z synonimicznymi nazwami hostów, takimi jak 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);
    }
}

Dla wygody, wywołaj następującą metodę MapSubdomainRoute z Twojej metody RegisterRoutes, tak jak stara 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()
    });
}

Wreszcie, aby wygodnie uzyskać dostęp do subdomeny (albo z prawdziwego subdomena lub parametr zapytania), pomocne jest utworzenie klasy bazowej kontrolera z tą właściwością Subdomain:

protected string Subdomain
{
    get { return (string)Request.RequestContext.RouteData.Values["subdomain"]; }
}
 52
Author: Edward Brey,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:47:31

To nie jest moja praca, ale musiałem ją dodać do tej odpowiedzi.

Oto świetne rozwiązanie tego problemu. Maartin Balliauw napisał kod, który tworzy klasę DomainRoute, która może być używana bardzo podobnie do normalnego routingu.

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

Użycie próbki byłoby takie...

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

;

 22
Author: Jim Blake,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-03-23 12:27:26

Aby przechwycić subdomenę podczas korzystania z Web API, Nadpisz Selektor akcji, aby wprowadzić parametr zapytania subdomain. Następnie użyj parametru query subdomeny w akcjach kontrolerów:

public string Get(string id, string subdomain)

To podejście sprawia, że debugowanie jest wygodne, ponieważ możesz podać parametr zapytania ręcznie podczas używania localhost zamiast rzeczywistej nazwy hosta (zobacz standardową odpowiedź routingu MVC5 Po szczegóły). To jest kod do działania Selektor:

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

Zastąp domyślny Selektor akcji dodając to do WebApiConfig.Register:

config.Services.Replace(typeof(IHttpActionSelector), new SubdomainActionSelector(config.Services.GetActionSelector()));
 4
Author: Edward Brey,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:55:03

Tak, ale musisz stworzyć własną obsługę trasy.

Zazwyczaj trasa nie jest świadoma domeny, ponieważ aplikacja może być wdrożona do dowolnej domeny, a trasa nie obchodzi tak czy inaczej. Ale w Twoim przypadku chcesz oprzeć kontroler i akcję poza domeną, więc będziesz musiał utworzyć niestandardową trasę, która jest świadoma domeny.

 3
Author: Nick Berardi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-11-10 18:13:16

Stworzyłembibliotekę do routingu subdomen , którą można utworzyć taką trasę. Obecnie pracuje dla. Net Core 1.1 i. NET Framework 4.6.1, ale zostanie zaktualizowany w niedalekiej przyszłości. Tak to działa:
1) trasa subdomeny mapy podczas uruchamiania.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) Kontrolery / HomeController.cs

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

3) lib pozwala również na generowanie adresów URL i formularzy. Kod:

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

Wygeneruje <a href="http://user1.localhost:54575/Home/Index">User home</a> Wygenerowany adres URL zależy również od bieżącego hosta lokalizacja i schemat.
Możesz również użyć helperów html dla BeginForm i UrlHelper. Jeśli chcesz, możesz również użyć nowej funkcji o nazwie Tag helpers (FormTagHelper, AnchorTagHelper)
Ta lib nie ma jeszcze żadnej dokumentacji, ale istnieje kilka testów i projektów próbek, więc nie krępuj się go zbadać.

 3
Author: Mariusz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-10-17 17:08:17

W ASP.NET Core , host jest dostępny przez Request.Host.Host. Jeśli chcesz zezwolić na nadpisywanie hosta przez parametr zapytania, najpierw sprawdź Request.Query.

Aby spowodować, że parametr zapytania hosta będzie propagowany do nowych adresów URL opartych na trasie, dodaj ten kod do konfiguracji trasy app.UseMvc:

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

I zdefiniuj HostPropagationRouter Tak:

/// <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);
}
 2
Author: Edward Brey,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-06-14 13:12:59

Po zdefiniowaniu nowej funkcji obsługi trasy, która będzie patrzeć na host przekazywany w adresie URL , możesz wybrać Kontroler bazowy, który jest świadomy strony, dla której jest dostępny. Wygląda to tak:

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 jest prostym interfejsem:

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

Odsyłam do Luke Sampson Blog

 1
Author: Amirhossein Mehrvarzi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-06-19 08:10:33

Jeśli chcesz nadać projektowi możliwości Multitenancji z różnymi domenami/subdomenami dla każdego dzierżawcy, powinieneś rzucić okiem na SaasKit:

Https://github.com/saaskit/saaskit

Przykłady kodu można zobaczyć tutaj: http://benfoster.io/blog/saaskit-multi-tenancy-made-easy

Kilka przykładów wykorzystujących ASP.NET rdzeń: http://andrewlock.net/forking-the-pipeline-adding-tenant-specific-files-with-saaskit-in-asp-net-core/

Edytuj: Jeśli nie chcesz używać SaasKit w swoim ASP.NET core project możesz rzucić okiem na implementację routingu domeny Maarten dla MVC6: https://blog.maartenballiauw.be/post/2015/02/17/domain-routing-and-resolving-current-tenant-with-aspnet-mvc-6-aspnet-5.html

Jednak te Gist nie są utrzymywane i muszą być poprawione, aby pracować z najnowsze wydanie ASP.NET rdzeń.

Bezpośredni link do kodu: https://gist.github.com/maartenba/77ca6f9cfef50efa96ec#file-domaintemplateroutebuilderextensions-cs

 1
Author: Darxtar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-10-05 22:48:07