【问题标题】:Asp.Net core get RouteData value from urlAsp.Net core 从 url 获取 RouteData 值
【发布时间】:2016-11-25 02:27:26
【问题描述】:

我正在开发一个新的 Asp.Net 核心 mvc 应用程序。我定义了一个带有自定义约束的路由,它从 url 设置当前的应用程序文化。我正在尝试通过创建一个自定义的IRequestCultureProvider 来管理我的应用程序的本地化,如下所示:

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

我的MyCustomRequestCultureProvider 在每次请求时都会被点击,这没关系。我的问题是,在 MVC 管道中,来自我的提供程序的 DetermineProviderCultureResult 方法在路由过程之前被命中,所以 httpContext.GetRouteValue("language") 总是返回 null。

在以前版本的 MVC 中,我可以通过这样做来通过路由过程手动处理我的 url

var wrapper = new HttpContextWrapper(HttpContext.Current);
var routeData = RouteTable.Routes.GetRouteData(wrapper);
var language = routeData.GetValue("language")

我现在找不到在新框架中做同样事情的方法。另外,我想使用路由数据来找出我的语言,用一些字符串函数分析我的 url 字符串来查找语言不是一个选项。

【问题讨论】:

  • 这个question and its answer 可能会有所帮助
  • @nboisvert 你能解决这个问题吗?
  • @SherleyDev 看到我的回答

标签: asp.net-core asp.net-core-mvc asp.net-core-1.0


【解决方案1】:

没有一种简单的方法可以做到这一点,而且 ASP.Net 团队还没有决定实现这个功能。 IRoutingFeature 仅在 MVC 完成请求后可用。

我能够整理出一个适合您的解决方案。这将设置您传递到UseMvc() 的路由以及所有属性路由,以填充 IRoutingFeature。完成后,您可以通过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);
}

将路由移至委托(为了可重用性),相同的文件/类:

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?}");
    };

添加新的中间件:

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

您可能还必须定义此类...

public class RoutingFeature : IRoutingFeature
{
    public RouteData RouteData { get; set; }
}

【讨论】:

  • 哇,只能编辑 cmets 5 分钟太痛苦了!这就是我的意思:我需要访问其他中间件中的参数,这对我来说几乎没有修改! 5* 会再次使用
【解决方案2】:

根据 Ashley Lee 的回答,这是一种防止重复路由配置的优化方法。

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

这取决于必须添加到 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);
    };
}

【讨论】:

    【解决方案3】:

    添加了端点路由功能后,这变得更容易了。 本文解释了如何使用端点路由功能https://aregcode.com/blog/2019/dotnetcore-understanding-aspnet-endpoint-routing/

    var endpointFeature = context.Features[typeof(Microsoft.AspNetCore.Http.Features.IEndpointFeature)]
                                           as Microsoft.AspNetCore.Http.Features.IEndpointFeature;
    
    Microsoft.AspNetCore.Http.Endpoint endpoint = endpointFeature?.Endpoint;
    
    //Note: endpoint will be null, if there was no
    //route match found for the request by the endpoint route resolver middleware
    if (endpoint != null)
    {
        var routePattern = (endpoint as Microsoft.AspNetCore.Routing.RouteEndpoint)?.RoutePattern
                                                                                   ?.RawText;
    
        Console.WriteLine("Name: " + endpoint.DisplayName);
        Console.WriteLine($"Route Pattern: {routePattern}");
        Console.WriteLine("Metadata Types: " + string.Join(", ", endpoint.Metadata));
    }
    

    【讨论】:

      猜你喜欢
      • 2019-02-02
      • 1970-01-01
      • 2021-01-05
      • 2011-04-02
      • 1970-01-01
      • 2017-09-26
      • 2020-07-27
      • 2021-04-09
      • 1970-01-01
      相关资源
      最近更新 更多