Pregunta

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

  • usuario1.domain.com va a un lugar
  • usuario2.domain.com se va a otra?

O, ¿puedo hacer para que ambos van a la misma controlador/acción con un username parámetro?

¿Fue útil?

Solución

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

Otros consejos

A captura el subdominio manteniendo el estándar de MVC5 características de enrutamiento, utilice el siguiente SubdomainRoute clase derivada de Route.

Además, SubdomainRoute permite que el subdominio, opcionalmente, se pueden especificar como parámetro de consulta, haciendo sub.example.com/foo/bar y example.com/foo/bar?subdomain=sub equivalente.Esto le permite probar antes de que el DNS subdominios están configurados.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 el comando netsh o ejecutar como Administrador.De forma predeterminada, IIS Express sólo se une a localhost cuando no elevados;no se unen a sinónimos como nombres de host 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, llamar a los siguientes MapSubdomainRoute método de su RegisterRoutes método tal como lo haría el viejo y simple 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()
    });
}

Por último, para acceder cómodamente a la subdominio (ya sea a partir de un cierto subdominio o un parámetro de consulta), es útil para crear un Controlador de base de la clase con este 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 para este problema. Maartin Balliauw escribió un código que crea una clase DomainRoute que se puede usar 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 API web , anule el selector de acción para inyectar un parámetro de consulta subdomain. 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 a mano cuando usa localhost en lugar del nombre de host real (consulte respuesta de enrutamiento MVC5 estándar para 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 acción predeterminado agregándolo a WebApiConfig.Register:

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

Sí, pero debe crear su propio controlador de ruta.

Normalmente, la ruta no conoce el dominio porque la aplicación podría implementarse en cualquier dominio y 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 conozca el dominio.

He creado biblioteca para el subdominio de enrutamiento que se puede crear una ruta.Se está trabajando actualmente para una .NET Core 1.1 y .NET Framework 4.6.1 pero va a ser actualizado en el futuro cercano.Esto es, ¿cómo es el trabajo:
1) el Mapa subdominio de la ruta en el Inicio.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) Los Controladores/HomeController.cs

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

3) Que lib también le permitirá generar direcciones Url y las formas.Código:

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

Generará <a href="http://user1.localhost:54575/Home/Index">User home</a> URL generada dependerá también en la actual ubicación de host y el esquema.
También puede utilizar html ayudantes para BeginForm y UrlHelper.Si te gusta también puede utilizar la nueva característica denominada etiqueta ayudantes (FormTagHelper, AnchorTagHelper)
Que lib no tiene ningún tipo de documentación, pero hay algunas pruebas y muestras de proyecto, así que siéntase libre para explorar.

En ASP.NET Core , el host está disponible a través de Request.Host.Host. Si desea permitir anular el host mediante un parámetro de consulta, primero verifique Request.Query.

Para hacer que un parámetro de consulta de host se propague a nuevas URL basadas en rutas, agregue este código a la configuración de ruta app.UseMvc:

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

Y defina HostPropagationRouter así:

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

Después de definir un nuevo controlador de ruta que vería el host pasado en la URL , puede ir con la idea de un controlador base que conozca el sitio & # 8217; s para acceder. Se ve así:

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 es una interfaz simple:

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

Recomiendo que vaya a Blog Luke Sampson

Si está buscando dar capacidades de MultiTenancy a su proyecto con diferentes dominios / subdominios para cada inquilino, debe echar un vistazo a SaasKit:

https://github.com/saaskit/saaskit

Los ejemplos de código se pueden ver aquí: http://benfoster.io/blog / saaskit-multi-tenancy-made-easy

Algunos ejemplos que usan el núcleo ASP.NET: http://andrewlock.net/forking-the-pipeline-adding-tenant-specific-files-with-saaskit-in-asp-net-core/

EDITAR: Si no desea usar SaasKit en su proyecto principal de ASP.NET, puede echar un vistazo a la implementación de Maarten de enrutamiento de dominio para MVC6: https://blog.maartenballiauw.be/post/2015/02/ 17 / domain-routing-and-resolving-current-tenant-with-aspnet-mvc-6-aspnet-5.html

Sin embargo, esos Gists no se mantienen y deben modificarse para que funcionen con la última versión de ASP.NET core.

Enlace directo al código: https://gist.github.com/ maartenba / 77ca6f9cfef50efa96ec # file-domaintemplateroutebuilderextensions-cs

Hace unos meses desarrollé un atributo que restringe los métodos o controladores a dominios específicos.

Es bastante fácil de usar:

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

También puede aplicarlo directamente en un controlador.

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

Restricción: Es posible que no pueda tener dos mismas rutas en diferentes métodos con diferentes filtros Quiero decir que lo siguiente puede arrojar una excepción para la ruta duplicada:

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

[IsDomain("test2.example.com")]
[HttpGet("/Test")]
public IActionResult Test2(){}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top