我正在尝试创建一个中间件来处理网址中的国家/地区代码。 我的代码非常适合删除国家/地区代码,因此它被路由到 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);
}
我遇到了同样的问题,问题的解决方案(至少是我的)是启动中中间件的顺序:您的自定义中间件必须位于
UseRouting()
之后
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseHttpsRedirection();
app.UseRouting();
app.UseMiddleware<MyCustomMiddleware>();
app.UseAuthorization();
app.UseEndpoints(endpoints => { endpoints.MapControllers(); });
}
我找到了解决方案,
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
按中间件定义: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...
}