Is het mogelijk om een ​​ASP.NET MVC-route te maken op basis van een subdomein?

Is het mogelijk om een ​​ASP.NET MVC-route te hebben die subdomeininformatie gebruikt om de route te bepalen? Bijvoorbeeld:

  • gebruiker1.domain.comgaat naar één plaats
  • gebruiker2.domein.comnaar een ander gaat?

Of kan ik ervoor zorgen dat beide naar dezelfde controller/actie gaan met een usernameparameter?


Antwoord 1, autoriteit 100%

U kunt dit doen door een nieuwe route te maken en deze toe te voegen aan de routesverzameling in RegisterRoutes in uw global.asax. Hieronder ziet u een heel eenvoudig voorbeeld van een aangepaste route:

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

Antwoord 2, autoriteit 32%

Om het subdomein vast te leggen met behoud van de standaard MVC5-routeringsfuncties, gebruikt u de volgende SubdomainRoute-klasse die is afgeleid van Route.

Bovendien staat SubdomainRoutetoe dat het subdomein optioneel kan worden gespecificeerd als een queryparameter, waardoor sub.example.com/foo/baren example.com/foo/bar?subdomain=subequivalent. Hiermee kunt u testen voordat de DNS-subdomeinen worden geconfigureerd. De queryparameter (wanneer in gebruik) wordt gepropageerd via nieuwe links die worden gegenereerd door Url.Action, enz.

De queryparameter maakt ook lokale foutopsporing met Visual Studio 2013 mogelijk zonder met netsh te configureren of als beheerder uit te voeren. Standaard bindt IIS Express alleen aan localhostwanneer niet-verhoogd; het bindt niet aan synonieme hostnamen zoals 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);
    }
}

Voor het gemak roept u de volgende MapSubdomainRoute-methode aan vanuit uw RegisterRoutes-methode, net zoals u zou doen met de gewone oude 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()
    });
}

Ten slotte, om gemakkelijk toegang te krijgen tot het subdomein (vanuit een echt subdomein of een queryparameter), is het handig om een ​​Controller-basisklasse te maken met deze eigenschap Subdomain:

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

Antwoord 3, autoriteit 14%

Dit is niet mijn werk, maar ik moest het toevoegen aan dit antwoord.

Hier is een geweldige oplossing voor dit probleem. Maartin Balliauw schreef code die een DomainRoute-klasse creëert die op dezelfde manier kan worden gebruikt als de normale routering.

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

Voorbeeldgebruik zou als volgt zijn…

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

;


Antwoord 4, autoriteit 2%

Als u het subdomein wilt vastleggen bij gebruik van Web API, overschrijft u de actiekiezer om een ​​Subdomain-queryparameter in te voegen. Gebruik vervolgens de subdomein-queryparameter in de acties van uw controllers als volgt:

public string Get(string id, string subdomain)

Deze aanpak maakt foutopsporing gemakkelijk, aangezien u de queryparameter handmatig kunt opgeven wanneer u localhostgebruikt in plaats van de daadwerkelijke hostnaam (zie de standaard MVC5-routeringsantwoordvoor details). Dit is de code voor 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);
    }
}

Vervang de standaard actiekiezer door deze toe te voegen aan WebApiConfig.Register:

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

Antwoord 5, autoriteit 2%

Ja, maar u moet uw eigen route-handler maken.

Normaal gesproken is de route niet op de hoogte van het domein, omdat de applicatie in elk domein kan worden geïmplementeerd en de route op de een of andere manier niets kan schelen. Maar in jouw geval wil je de controller en actie buiten het domein baseren, dus je zult een aangepaste route moeten maken die op de hoogte is van het domein.


Antwoord 6, autoriteit 2%

Ik heb een bibliotheek voor subdomeinrouteringgemaakt waarmee je zo’n route kunt maken. Het werkt momenteel voor een .NET Core 1.1 en .NET Framework 4.6.1, maar zal in de nabije toekomst worden bijgewerkt. Zo werkt het:
1) Kaart subdomeinroute in 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) Controllers/HomeController.cs

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

3) Met die lib kun je ook URL’s en formulieren genereren. Code:

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

Genereert <a href="http://user1.localhost:54575/Home/Index">User home</a>
De gegenereerde URL is ook afhankelijk van de huidige hostlocatie en het schema.

Je kunt ook html-helpers gebruiken voor BeginFormen UrlHelper. Als je wilt, kun je ook een nieuwe functie gebruiken genaamd tag helpers (FormTagHelper, AnchorTagHelper)
Dat lib heeft nog geen documentatie, maar er zijn enkele tests en voorbeelden van projecten, dus voel je vrij om het te verkennen.


Antwoord 7

In ASP.NET Coreis de host beschikbaar via Request.Host.Host. Als u het overschrijven van de host via een queryparameter wilt toestaan, vinkt u eerst Request.Queryaan.

Om ervoor te zorgen dat een hostqueryparameter zich verspreidt naar nieuwe op routes gebaseerde URL’s, voegt u deze code toe aan de app.UseMvc-routeconfiguratie:

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

En definieer HostPropagationRouterals volgt:

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

Other episodes