Question

Est-il possible d’avoir un itinéraire ASP.NET MVC qui utilise les informations de sous-domaine pour déterminer son itinéraire? Par exemple:

  • utilisateur1 .domaine.com se rend au même endroit
  • utilisateur2 .domaine.com passe à un autre?

Ou puis-je faire en sorte que ces deux éléments soient redirigés vers le même contrôleur / action avec un paramètre username?

Était-ce utile?

La solution

Vous pouvez le faire en créant un nouvel itinéraire et en l’ajoutant à la collection d’itinéraires de RegisterRoutes dans votre fichier global.asax. Vous trouverez ci-dessous un exemple très simple d'itinéraire personnalisé:

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

Autres conseils

Pour capturer le sous-domaine tout en conservant les fonctionnalités de routage MVC5 standard , utilisez la SubdomainRoute classe suivante dérivée de Route.

De plus, sub.example.com/foo/bar permet de spécifier le sous-domaine en tant que paramètre de requête , ce qui rend example.com/foo/bar?subdomain=sub et Url.Action équivalents. Cela vous permet de tester avant que les sous-domaines DNS soient configurés. Le paramètre de requête (en cours d'utilisation) est propagé via de nouveaux liens générés par MapSubdomainRoute, etc.

.

Le paramètre de requête active également le débogage local avec Visual Studio 2013 sans avoir à configurer avec netsh ou s'exécuter en tant qu'administrateur . Par défaut, IIS Express ne lie à localhost que s'il est non élevé; cela ne se liera pas à des noms d’hôtes 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 plus de commodité, appelez la méthode RegisterRoutes suivante à partir de votre MapRoute méthode, comme vous le feriez avec l'ancien Subdomain:

.
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 (à partir d'un vrai sous-domaine ou d'un paramètre de requête), il est utile de créer une classe de base de contrôleur avec cette <=> propriété:

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

Ce n'est pas mon travail, mais je devais l'ajouter à 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 de manière très similaire au routage normal.

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

L’utilisation de l’échantillon ressemblerait à 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 
))

;

Pour capturer le sous-domaine lors de l'utilisation de Web API , remplacez le sélecteur d'action pour injecter un paramètre de requête subdomain. Utilisez ensuite le paramètre de requête de sous-domaine dans les actions de vos contrôleurs, comme suit:

public string Get(string id, string subdomain)

Cette approche facilite le débogage car vous pouvez spécifier manuellement le paramètre de requête lorsque vous utilisez localhost à la place du nom d'hôte réel (voir réponse d'acheminement standard MVC5 pour plus de détails). C'est le code pour 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);
    }
}

Remplacez le sélecteur d'action par défaut en l'ajoutant à WebApiConfig.Register:

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

Oui, mais vous devez créer votre propre gestionnaire d’itinéraires.

Généralement, la route n’a pas connaissance du domaine car l’application peut être déployée dans n’importe quel domaine et la route n’a aucune importance. Mais dans votre cas, vous souhaitez baser le contrôleur et l’action sur le domaine. Vous devez donc créer une route personnalisée tenant compte du domaine.

J'ai créé la bibliothèque de routage de sous-domaine à partir de laquelle vous pouvez créer un tel itinéraire. Il fonctionne actuellement pour un .NET Core 1.1 et .NET Framework 4.6.1 mais sera mis à jour dans un proche avenir. Voici comment ça marche:
1) Mapper un itinéraire de sous-domaine dans 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) Contrôleurs / HomeController.cs

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

3) Cette bibliothèque vous permettra également de générer des URL 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 de l'hôte actuel.
Vous pouvez également utiliser des aides HTML pour BeginForm et UrlHelper. Si vous le souhaitez, vous pouvez également utiliser une nouvelle fonctionnalité appelée assistant de balise (FormTagHelper, AnchorTagHelper)
Cette bibliothèque n'a pas encore de documentation, mais il y a des tests et des exemples de projet, alors n'hésitez pas à l'explorer.

Dans ASP.NET Core , l'hôte est disponible via Request.Host.Host. Si vous souhaitez autoriser le remplacement de l'hôte via un paramètre de requête, vérifiez d'abord Request.Query.

Pour que le paramètre de requête d'un hôte se propage dans de nouvelles URL basées sur une route, ajoutez ce code à la app.UseMvc configuration de la route:

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

Et définissez 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);
}

Après avoir défini un nouveau gestionnaire Route qui prend en compte l'hôte transmis dans l'URL , vous pouvez utiliser un contrôleur de base connaissant le site & # 8217; s être accédé pour. Cela 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 au blog de Luke Sampson

Si vous souhaitez doter votre projet de fonctionnalités MultiTenancy, avec différents domaines / sous-domaines pour chaque client hébergé, consultez SaasKit:

https://github.com/saaskit/saaskit

Des exemples de code sont disponibles ici: http://benfoster.io/blog. / saaskit-multi-tenancy-made-easy-

Quelques exemples utilisant le noyau ASP.NET: http://andrewlock.net/forking-the-pipeline-adding-tenant-specific-files-with-saaskit-in-asp-net-core/

EDIT: Si vous ne souhaitez pas utiliser SaasKit dans votre projet ASP.NET, vous pouvez jeter un coup d'œil à la mise en œuvre du routage de domaine de Maarten pour MVC6: https://blog.maartenballiauw.be/post/2015/02/ 17 / domaine-routage-et-résolution-actuel-locataire-avec-aspnet-mvc-6-aspnet-5.html

Cependant, ces listes de contrôle ne sont pas conservées et doivent être modifiées pour fonctionner avec la dernière version du noyau ASP.NET.

Lien direct vers le code: https://gist.github.com/ maartenba / 77ca6f9cfef50efa96ec # fichier-domaintemplateroutebuilderextensions-cs

Il y a quelques mois, j'ai développé un attribut qui limite les méthodes ou les contrôleurs à des domaines spécifiques.

Il est assez facile à utiliser:

[IsDomain("localhost","example.com","www.example.com","*.t1.example.com")]
[HttpGet("RestrictedByHost")]
public IActionResult Test(){}

Vous pouvez également l'appliquer directement sur un contrôleur.

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

Restriction: il se peut que vous ne puissiez pas avoir deux mêmes itinéraires sur des méthodes différentes avec des filtres différents Je veux dire que les personnes suivantes peuvent lever une exception pour l’itinéraire dupliqué:

[IsDomain("test1.example.com")]
[HttpGet("/Test")]
public IActionResult Test1(){}

[IsDomain("test2.example.com")]
[HttpGet("/Test")]
public IActionResult Test2(){}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top