tutorial net mvc entre diferencias asp asp.net-mvc routing asp.net-mvc-routing

asp.net-mvc - net - razor partial



¿Es posible hacer una ruta ASP.NET MVC basada en un subdominio? (9)

Creé una biblioteca para el enrutamiento de subdominios que puede crear una ruta de este tipo Actualmente funciona para .NET Core 1.1 y .NET Framework 4.6.1, pero se actualizará en un futuro próximo. Así es como funciona:
1) Mapa de ruta del subdominio en 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) Controladores / HomeController.cs

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

3) Esa biblioteca también te permitirá generar URL y formularios. 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 también dependerá de la ubicación del host actual y del esquema.
También puede usar ayudantes html para BeginForm y UrlHelper . Si lo desea, también puede usar una nueva función llamada ayudantes de etiquetas ( FormTagHelper , AnchorTagHelper )
Esa libreta aún no tiene documentación, pero hay algunas pruebas y proyectos de muestras, así que siéntase libre de explorarla.

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

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

O, ¿puedo hacer que ambos vayan al mismo controlador / acción con un parámetro de username ?


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

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

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

Y define HostPropagationRouter esta manera:

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


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

Aquí hay una gran solución a 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 la 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 mientras se conservan las funciones de enrutamiento MVC5 estándar , use la siguiente clase SubdomainRoute derivada de Route .

Además, SubdomainRoute permite que el subdominio se especifique opcionalmente como un parámetro de consulta , haciendo que sub.example.com/foo/bar y example.com/foo/bar?subdomain=sub equivalentes. Esto le permite probar antes de configurar los subdominios de 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 solo se enlaza a localhost cuando no está elevado; No se unirá a nombres de host 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 su comodidad, llame al siguiente método MapSubdomainRoute desde su método RegisterRoutes tal como lo haría con el viejo 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 de manera conveniente al subdominio (ya sea desde un subdominio verdadero o un parámetro de consulta), es útil crear una clase base de Controlador con esta propiedad de Subdomain :

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


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

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 use localhost en lugar del nombre de host real (consulte la respuesta de enrutamiento MVC5 estándar para obtener más información). Este es el código del selector de acción:

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 agregando esto a WebApiConfig.Register :

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


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


Sí, pero tienes que crear tu propio controlador de ruta.

Por lo general, la ruta no tiene conocimiento del 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 en el dominio, por lo que tendrá que crear una ruta personalizada que sea consciente del dominio.


Si está pensando en otorgarle a su proyecto capacidades de multitenancia con diferentes dominios / subdominios para cada inquilino, debería 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 utilizan el núcleo de ASP.NET: http://andrewlock.net/forking-the-pipeline-adding-tenant-specific-files-with-saaskit-in-asp-net-core/

EDITAR: Si no desea utilizar SaasKit en su proyecto central de ASP.NET, puede echar un vistazo a la implementación de Maarten del enrutamiento de dominios 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 del núcleo de ASP.NET.

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


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 al que se accede. Se parece a esto:

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

Te recomiendo que vayas al blog de Luke Sampson.