Est-il possible de faire ASP.NET MVC route basée sur un sous-domaine?

est-il possible d'avoir un ASP.NET route MVC qui utilise l'information du sous-domaine pour déterminer sa route? Par exemple:

  • user1 .domain.com va à un endroit
  • user2 .domain.com un autre?

Ou, puis-je faire à la fois de ces aller pour le même contrôleur/action avec un username paramètre?

228
demandé sur tereško 2008-11-10 21:04:23

9 réponses

vous pouvez le faire en créant une nouvelle route et en l'ajoutant à la collection routes dans Registrterroutes dans votre global.asax. Ci-dessous un exemple très simple d'une Route personnalisée:

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
répondu Jon Cahill 2009-02-12 14:30:49

à capturer le sous-domaine tout en conservant les caractéristiques d'acheminement standard MVC5 , utiliser la classe suivante SubdomainRoute dérivée de Route .

en outre, SubdomainRoute permet au sous-domaine éventuellement d'être spécifié comme un paramètre de requête , ce qui rend sub.example.com/foo/bar et example.com/foo/bar?subdomain=sub équivalent. Cela vous permet de tester avant que les sous-domaines DNS ne soient configurés. Le paramètre de requête (lorsqu'en service) est propagée par de nouveaux liens générés par Url.Action , etc.

le paramètre query permet également le débogage local avec Visual Studio 2013 sans avoir à configurer avec netsh ou exécuter comme administrateur . Par défaut, IIS Express ne se lie qu'à localhost lorsqu'il n'est pas élevé; il ne se liera pas à des noms d'hôtes synonymes comme 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);
    }
}

pour pour plus de commodité, appelez la méthode MapSubdomainRoute de votre méthode RegisterRoutes comme vous le feriez avec la vieille méthode 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()
    });
}

enfin, pour accéder facilement au sous-domaine (soit à partir d'un sous-domaine true ou d'un paramètre query), il est utile de créer une classe de base de Controller avec cette propriété Subdomain :

protected string Subdomain
{
    get { return (string)Request.RequestContext.RouteData.Values["subdomain"]; }
}
52
répondu Edward Brey 2017-05-23 11:47:31

Ce n'est pas mon travail, mais j'ai dû l'ajouter sur cette réponse.

Voici une excellente solution à ce problème. Maartin Balliauw a écrit un code qui crée une classe DomainRoute qui peut être utilisée très similaire au routage normal.

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

L'utilisation de L'échantillon serait comme ceci...

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
répondu Jim Blake 2011-03-23 12:27:26

pour capturer le sous-domaine en utilisant API Web , Outrepasser le sélecteur d'Action pour injecter un paramètre de requête subdomain . Ensuite, utilisez le paramètre de requête du sous-domaine dans les actions de vos contrôleurs comme ceci:

public string Get(string id, string subdomain)

cette approche rend le débogage commode puisque vous pouvez spécifier le paramètre de requête à la main en utilisant localhost au lieu du nom d'hôte réel (voir le routage standard MVC5 répondez pour plus de détails). C'est le code du sélecteur D'Action:

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

remplacer le sélecteur d'Action par défaut par WebApiConfig.Register :

config.Services.Replace(typeof(IHttpActionSelector), new SubdomainActionSelector(config.Services.GetActionSelector()));
4
répondu Edward Brey 2017-05-23 11:55:03

Oui, mais vous devez créer votre propre gestionnaire d'itinéraire.

généralement, la route n'est pas au courant du domaine parce que l'application pourrait être déployée dans n'importe quel domaine et la route ne se soucierait pas d'une manière ou d'une autre. Mais dans votre cas, vous voulez baser le contrôleur et l'action hors du domaine, donc vous devrez créer une route personnalisée qui est au courant du domaine.

3
répondu Nick Berardi 2008-11-10 18:13:16

j'ai créé bibliothèque pour le routage de sous-domaine que vous pouvez créer une telle route. Il fonctionne actuellement pour un .net Core 1.1 et un .net Framework 4.6.1 mais sera mis à jour dans un proche avenir. C'est comme ça que ça marche:

1) Route du sous-domaine Map au démarrage.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) Contrôleurs/Contrôleur HomeController.cs

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

3) que lib vous permettra également de générer des URLs et des formulaires. Code:

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

générera <a href="http://user1.localhost:54575/Home/Index">User home</a> L'URL générée dépendra également de l'emplacement et du schéma actuels de l'hôte.

Vous pouvez également utiliser des helpers html pour BeginForm et UrlHelper . Si vous le souhaitez, vous pouvez également utiliser une nouvelle fonctionnalité appelée helpers d'étiquettes( FormTagHelper , AnchorTagHelper )

Cette lib n'a pas encore de documentation, mais il y a des tests et des projets d'échantillons donc n'hésitez pas à l'explorer.

3
répondu Mariusz 2017-10-17 17:08:17

Dans ASP.NET de Base , l'hôte est disponible via Request.Host.Host . Si vous voulez autoriser la suppression de l'hôte via un paramètre de requête, cochez d'abord Request.Query .

pour faire en sorte qu'un paramètre de requête de l'hôte se propage dans de nouvelles URL basées sur la route, ajoutez ce code à la configuration de route app.UseMvc :

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

et définir HostPropagationRouter comme ceci:

/// <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
répondu Edward Brey 2017-06-14 13:12:59

après avoir défini un nouveau gestionnaire de Route qui regarderait l'hôte passé dans L'URL , vous pouvez aller avec l'idée d'un contrôleur de base qui est conscient du Site pour lequel il est accédé. Il ressemble à ceci:

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 est une interface simple:

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

je vous renvoie aller à Luc Sampson Blog

1
répondu Amirhossein Mehrvarzi 2015-06-19 08:10:33

si vous cherchez à donner des capacités de Multitenance à votre projet avec différents domaines / sous-domaines pour chaque locataire, vous devriez jeter un oeil à SaasKit:

https://github.com/saaskit/saaskit

des exemples de Code peuvent être consultés ici: http://benfoster.io/blog/saaskit-multi-tenancy-made-easy

quelques exemples d'utilisation ASP.NET central: http://andrewlock.net/forking-the-pipeline-adding-tenant-specific-files-with-saaskit-in-asp-net-core /

EDIT: Si vous ne voulez pas utiliser SaasKit dans votre ASP.NET vous pouvez jeter un coup d'oeil à L'implémentation par Maarten du routage des domaines pour MVC6: https://blog.maartenballiauw.be/post/2015/02/17/domain-routing-and-resolving-current-tenant-with-aspnet-mvc-6-aspnet-5.html

cependant ces Gists ne sont pas maintenu et doit être modifié pour fonctionner avec la dernière version de ASP.NET noyau.

lien Direct vers le code: https://gist.github.com/maartenba/77ca6f9cfef50efa96ec#file-domaintemplateroutebuilderextensions-cs

1
répondu Darxtar 2016-10-05 22:48:07