Asp.Net core obtiene el valor de RouteData de url
asp.net-core asp.net-core-mvc (2)
Basado en la respuesta de Ashley Lee, este es un enfoque optimizado que evita la configuración de rutas duplicadas.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
// setup routes
var mvcRouter = BuildMvcRouter(app, routes =>
{
routes.MapRoute(
name: "custom",
template: "{language=fr-FR}/{controller=Home}/{action=Index}/{id?}");
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
};
// add route data initialization middleware
app.Use(next => SetRouteData(next, mvcRouter));
// add localization middleware
var requestLocalizationOptions = new RequestLocalizationOptions
{
DefaultRequestCulture = new RequestCulture("en-US")
};
requestLocalizationOptions.RequestCultureProviders.Clear();
requestLocalizationOptions.RequestCultureProviders.Add(
new MyCustomRequestCultureProvider()
);
app.UseRequestLocalization(requestLocalizationOptions);
// add mvc routing middleware
app.UseRouter(mvcRouter);
}
Esto depende de los dos métodos siguientes que se deben agregar a la clase de inicio:
private static IRouter BuildMvcRouter(IApplicationBuilder app, Action<IRouteBuilder> configureRoutes)
{
if (app == null) throw new ArgumentNullException(nameof(app));
if (configureRoutes == null) throw new ArgumentNullException(nameof(configureRoutes));
app.ApplicationServices.GetRequiredService<MiddlewareFilterBuilder>().ApplicationBuilder = app.New();
RouteBuilder routeBuilder = new RouteBuilder(app)
{
DefaultHandler = app.ApplicationServices.GetRequiredService<MvcRouteHandler>()
};
configureRoutes((IRouteBuilder)routeBuilder);
routeBuilder.Routes.Insert(0, AttributeRouting.CreateAttributeMegaRoute(app.ApplicationServices));
return routeBuilder.Build();
}
private static RequestDelegate SetRouteData(RequestDelegate next, IRouter router)
{
return async context =>
{
var routeContext = new RouteContext(context);
await router.RouteAsync(routeContext);
if (routeContext.Handler != null)
{
context.Features[typeof(IRoutingFeature)] = new RoutingFeature()
{
RouteData = routeContext.RouteData
};
}
await next(context);
};
}
Estoy trabajando en una nueva aplicación Asp.Net core mvc. Definí una ruta con una restricción personalizada, que establece la cultura de la aplicación actual desde la url. Estoy tratando de administrar la localización de mi aplicación creando un IRequestCultureProvider
personalizado que tiene este aspecto:
public class MyCustomRequestCultureProvider : IRequestCultureProvider
{
public Task<ProviderCultureResult> DetermineProviderCultureResult(HttpContext httpContext)
{
var language= httpContext.GetRouteValue("language");
var result = new ProviderCultureResult(language, language);
return Task.FromResult(result);
}
}
Mi MyCustomRequestCultureProvider
encuentra en todas las solicitudes, lo cual está bien. Mi problema es que en la canalización de MVC, el método DetermineProviderCultureResult
de mi proveedor se encuentra antes del proceso de enrutamiento, por lo que httpContext.GetRouteValue("language")
siempre devuelve null.
En la versión anterior de MVC, tuve la posibilidad de procesar manualmente mi url a través del proceso de enrutamiento al hacer esto
var wrapper = new HttpContextWrapper(HttpContext.Current);
var routeData = RouteTable.Routes.GetRouteData(wrapper);
var language = routeData.GetValue("language")
No puedo encontrar una manera de hacer lo mismo en el nuevo framewrok en este momento. Además, quiero usar los datos de la ruta para averiguar mi idioma, analizar mi cadena de URL con algunas funciones de cadena para encontrar el idioma no es una opción.
No hay una manera fácil de hacer esto, y el equipo de ASP.Net aún no ha decidido implementar esta funcionalidad. IRoutingFeature
solo está disponible después de que MVC haya completado la solicitud.
Sin embargo, pude armar una solución que debería funcionar para usted. Esto configurará las rutas que está pasando a UseMvc()
, así como todo el enrutamiento de atributos para completar IRoutingFeature. Después de que se complete, puede acceder a esa clase a través de httpContext.GetRouteValue("language");
.
Startup.cs
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
// setup routes
app.UseGetRoutesMiddleware(GetRoutes);
// add localization
var requestLocalizationOptions = new RequestLocalizationOptions
{
DefaultRequestCulture = new RequestCulture("en-US")
};
requestLocalizationOptions.RequestCultureProviders.Clear();
requestLocalizationOptions.RequestCultureProviders.Add(
new MyCustomRequestCultureProvider()
);
app.UseRequestLocalization(requestLocalizationOptions);
// add mvc
app.UseMvc(GetRoutes);
}
Movió las rutas a un delegado (para reutilización), mismo archivo / clase:
private readonly Action<IRouteBuilder> GetRoutes =
routes =>
{
routes.MapRoute(
name: "custom",
template: "{language=fr-FR}/{controller=Home}/{action=Index}/{id?}");
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
};
Añadir nuevo middleware:
public static class GetRoutesMiddlewareExtensions
{
public static IApplicationBuilder UseGetRoutesMiddleware(this IApplicationBuilder app, Action<IRouteBuilder> configureRoutes)
{
if (app == null)
{
throw new ArgumentNullException(nameof(app));
}
var routes = new RouteBuilder(app)
{
DefaultHandler = app.ApplicationServices.GetRequiredService<MvcRouteHandler>(),
};
configureRoutes(routes);
routes.Routes.Insert(0, AttributeRouting.CreateAttributeMegaRoute(app.ApplicationServices));
var router = routes.Build();
return app.UseMiddleware<GetRoutesMiddleware>(router);
}
}
public class GetRoutesMiddleware
{
private readonly RequestDelegate next;
private readonly IRouter _router;
public GetRoutesMiddleware(RequestDelegate next, IRouter router)
{
this.next = next;
_router = router;
}
public async Task Invoke(HttpContext httpContext)
{
var context = new RouteContext(httpContext);
context.RouteData.Routers.Add(_router);
await _router.RouteAsync(context);
if (context.Handler != null)
{
httpContext.Features[typeof (IRoutingFeature)] = new RoutingFeature()
{
RouteData = context.RouteData,
};
}
// proceed to next...
await next(httpContext);
}
}
Puede que tengas que definir esta clase también ...
public class RoutingFeature : IRoutingFeature
{
public RouteData RouteData { get; set; }
}