Je travaille sur une nouvelle application mvc principale Asp.Net. J'ai défini un itinéraire avec une contrainte personnalisée, qui définit la culture actuelle de l'application à partir de l'URL. J'essaie de gérer la localisation de mon application en créant un IRequestCultureProvider
personnalisé qui ressemble à ceci:
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);
}
}
Mon MyCustomRequestCultureProvider
est touché à chaque demande, ce qui est correct. Mon problème est que dans le pipeline MVC, la méthode DetermineProviderCultureResult
de mon fournisseur est frappée avant le processus de routage, donc httpContext.GetRouteValue("language")
retourne toujours null.
Dans la version précédente de MVC, j'avais la possibilité de traiter manuellement mon URL via le processus de routage en faisant ceci
var wrapper = new HttpContextWrapper(HttpContext.Current);
var routeData = RouteTable.Routes.GetRouteData(wrapper);
var language = routeData.GetValue("language")
Je ne trouve pas de moyen de faire la même chose dans le nouveau framewrok en ce moment. En outre, je veux utiliser les données de l'itinéraire pour découvrir mes langues, analyser ma chaîne d'URL avec certaines fonctions de chaîne pour trouver la langue n'est pas une option.
Il n'y a pas de moyen facile de le faire, et l'équipe ASP.Net n'a pas encore décidé de mettre en œuvre cette fonctionnalité. IRoutingFeature
n'est disponible qu'une fois que MVC a terminé la demande.
J'ai cependant pu trouver une solution qui devrait fonctionner pour vous. Cela configurera les routes que vous passez dans UseMvc()
ainsi que tous les routages d'attributs afin de remplir IRoutingFeature. Une fois cette opération terminée, vous pouvez accéder à cette classe via 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);
}
Déplacement des routes vers un délégué (pour réutilisation), même fichier/classe:
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?}");
};
Ajouter un nouveau 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);
}
}
Vous devrez peut-être également définir cette classe ...
public class RoutingFeature : IRoutingFeature
{
public RouteData RouteData { get; set; }
}
Sur la base de la réponse d'Ashley Lee, voici une approche optimisée qui empêche la configuration de route en double.
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);
}
Cela dépend des deux méthodes suivantes qui doivent être ajoutées à la classe StartUp:
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();
var routeBuilder = new RouteBuilder(app)
{
DefaultHandler = app.ApplicationServices.GetRequiredService<MvcRouteHandler>()
};
configureRoutes(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);
};
}