¿Es posible realizar una ruta ASP.NET MVC basada en un subdominio?

Resuelto Dan Esparza asked hace 16 años • 10 respuestas

¿Es posible tener una ruta ASP.NET MVC que utilice información de subdominio para determinar su ruta? Por ejemplo:

  • usuario1 .dominio.ejemplo va a un lugar
  • usuario2 .dominio.ejemplo va a otro?

¿O puedo hacer que ambos vayan al mismo controlador/acción con un usernameparámetro?

Dan Esparza avatar Nov 11 '08 01:11 Dan Esparza
Aceptado

Puede hacerlo creando una nueva ruta y agregándola a la colección de rutas en RegisterRoutes en su global.asax. A continuación se muestra un ejemplo muy simple de una Ruta personalizada:

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;
    }
}
Jon Cahill avatar Feb 12 '2009 14:02 Jon Cahill

Para capturar el subdominio manteniendo las funciones de enrutamiento MVC5 estándar , utilice la siguiente SubdomainRouteclase derivada de Route.

Además, SubdomainRoutepermite especificar opcionalmente el subdominio como parámetro de consulta , haciendo sub.example.com/foo/bary example.com/foo/bar?subdomain=subequivalente. Esto le permite realizar pruebas antes de configurar los subdominios DNS. El parámetro de consulta (cuando está en uso) se propaga a través de nuevos enlaces generados por Url.Action, etc.

El parámetro de consulta también permite la depuración local con Visual Studio 2013 sin tener que configurar con netsh o ejecutar como administrador . De forma predeterminada, IIS Express sólo se vincula al host local cuando no está elevado; no se vinculará a nombres de host sinónimos como 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);
    }
}

Para mayor comodidad, llame al siguiente MapSubdomainRoutemétodo desde su RegisterRoutesmétodo tal como lo haría anteriormente 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()
    });
}

Finalmente, para acceder cómodamente al subdominio (ya sea desde un subdominio verdadero o desde un parámetro de consulta), es útil crear una clase base de Controlador con esta Subdomainpropiedad:

protected string Subdomain
{
    get { return (string)Request.RequestContext.RouteData.Values["subdomain"]; }
}
Edward Brey avatar Mar 08 '2013 05:03 Edward Brey

Este no es mi trabajo, pero tuve que agregarlo en esta respuesta.

Aquí hay una gran solución a este problema. Maartin Balliauw escribió código que crea una clase DomainRoute que puede usarse de manera muy similar al enrutamiento normal.

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

El uso de muestra sería así...

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

;

Jim Blake avatar Apr 27 '2010 18:04 Jim Blake

Para capturar el subdominio cuando se utiliza la API web , anule el selector de acciones para inyectar un subdomainparámetro de consulta. Luego use el parámetro de consulta de subdominio en las acciones de sus controladores de esta manera:

public string Get(string id, string subdomain)

Este enfoque hace que la depuración sea conveniente ya que puede especificar el parámetro de consulta manualmente cuando usa localhost en lugar del nombre de host real (consulte la respuesta de enrutamiento estándar MVC5 para obtener más detalles). Este es el código para el Selector de acciones:

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

Reemplace el Selector de acciones predeterminado agregando esto a WebApiConfig.Register:

config.Services.Replace(typeof(IHttpActionSelector), new SubdomainActionSelector(config.Services.GetActionSelector()));
Edward Brey avatar Sep 10 '2013 19:09 Edward Brey

Sí, pero debes crear tu propio controlador de ruta.

Normalmente, la ruta no conoce el dominio porque la aplicación podría implementarse en cualquier dominio y a la ruta no le importaría de una forma u otra. Pero en su caso desea basar el controlador y la acción fuera del dominio, por lo que tendrá que crear una ruta personalizada que tenga en cuenta el dominio.

Nick Berardi avatar Nov 10 '2008 18:11 Nick Berardi