修改请求路径上的 HttpContext GetEndpoint .net 5

问题描述 投票:0回答:3

我正在尝试创建一个中间件来处理网址中的国家/地区代码。 我的代码非常适合删除国家/地区代码,因此它被路由到 mvc 管道中的正确端点。

我遇到的问题是我需要根据端点是否具有特定属性来执行一些操作。

我看到

HttpContext
有一个方法
GetEndpoint
,这正是我所需要的。

当国家/地区代码位于 url (mysite.com/us/home/Index) 中时,

GetEndpoint
返回 null。

但是,如果我输入网址中没有国家/地区代码的网站 (mysite.com/home/Index),则

GetEndpoint
有效。

如何在修改后的请求 URL 上使用

GetEndpoint()
方法?

这是我需要更改的

HttpContext
上的另一个属性吗?

public async Task InvokeAsync(HttpContext httpContext)
{
    // mysite.com/us/home/Index
    var currentAddress = httpContext.Request.Path; 
    
    // mysite.com/home/Index
    httpContext.Request.Path = ExtractCountryCodeFromUrl(currentAddress); 

    var endpoint = httpContext.GetEndpoint(); // null

    var hasMyAttribute = endPoint.Metadata.GetMetadata<MyAttribute>();
    // Do something...

    await next(httpContext);
}
c# asp.net-core model-view-controller middleware .net-5
3个回答
15
投票

我遇到了同样的问题,问题的解决方案(至少是我的)是启动中中间件的顺序:您的自定义中间件必须位于

UseRouting()

之后
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    app.UseHttpsRedirection();

    app.UseRouting();

    app.UseMiddleware<MyCustomMiddleware>();

    app.UseAuthorization();

    app.UseEndpoints(endpoints => { endpoints.MapControllers(); });
}

0
投票

我找到了解决方案,

private static ControllerActionDescriptor GetControllerByUrl(HttpContext httpContext)
{
    var pathElements = httpContext.Request.Path.ToString().Split("/").Where(m => m != "");
    string controllerName = (pathElements.ElementAtOrDefault(0) == "" ? null : pathElements.ElementAtOrDefault(0)) ?? "w";
    string actionName = (pathElements.ElementAtOrDefault(1) == "" ? null : pathElements.ElementAtOrDefault(1)) ?? "Index";

    var actionDescriptorsProvider = httpContext.RequestServices.GetRequiredService<IActionDescriptorCollectionProvider>();
    ControllerActionDescriptor controller = actionDescriptorsProvider.ActionDescriptors.Items
    .Where(s => s is ControllerActionDescriptor bb
                && bb.ActionName == actionName
                && bb.ControllerName == controllerName
                && (bb.ActionConstraints == null
                    || (bb.ActionConstraints != null
                        && bb.ActionConstraints.Any(x => x is HttpMethodActionConstraint cc
                        && cc.HttpMethods.Any(m => m.ToLower() == httpContext.Request.Method.ToLower())))))
    .Select(s => s as ControllerActionDescriptor)
    .FirstOrDefault();
    return controller;
}

那我就可以这样做

ControllerActionDescriptor controller = GetControllerByUrl(httpContext);
var countryCodeAttribute = controller.MethodInfo.GetCustomAttribute<MyAttribute>();

我不知道它的扩展效果如何,但它现在可以工作。 我在这里找到了代码的主要部分:Changing Request Path in .Net Core 3.1


0
投票

按中间件定义:ASP.NET Core 中间件

如果您的

httpContext.GetEndpoint()
为空;您位于
//logic

您应该运行

await next(httpContext);
并等待值填写
EndPoint
;

所以你的代码应该在

//more logic
,所以你的代码就像:

public async Task InvokeAsync(HttpContext httpContext)
{
    await next(httpContext);//wait other middleware run.

    //more logic


    // mysite.com/us/home/Index
    var currentAddress = httpContext.Request.Path; 
    
    // mysite.com/home/Index
    httpContext.Request.Path = ExtractCountryCodeFromUrl(currentAddress); 

    var endpoint = httpContext.GetEndpoint(); // it may not null

    var hasMyAttribute = endPoint.Metadata.GetMetadata<MyAttribute>();
    // Do something...

}
© www.soinside.com 2019 - 2024. All rights reserved.