¿Es posible realizar una ruta ASP.NET MVC basada en un subdominio?
¿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 username
parámetro?
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;
}
}
Para capturar el subdominio manteniendo las funciones de enrutamiento MVC5 estándar , utilice la siguiente SubdomainRoute
clase derivada de Route
.
Además, SubdomainRoute
permite especificar opcionalmente el subdominio como parámetro de consulta , haciendo sub.example.com/foo/bar
y example.com/foo/bar?subdomain=sub
equivalente. 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 MapSubdomainRoute
método desde su RegisterRoutes
mé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 Subdomain
propiedad:
protected string Subdomain
{
get { return (string)Request.RequestContext.RouteData.Values["subdomain"]; }
}
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
))
;
Para capturar el subdominio cuando se utiliza la API web , anule el selector de acciones para inyectar un subdomain
pará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()));
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.