I'm trying to create a middleware to handle country code in the url. The code i have works great for removing the country code, so it's routed to the correct endpoint in the mvc pipeline.
The problem i have is that i need to do some actions depending on if the endpoint has a certain attribute or not.
I see that HttpContext
has a method GetEndpoint
, and this is exactly what i need.
When the countryCode is in the url (mysite.com/us/home/Index), the
GetEndpoint
returns null.
But if i enter the site without the countryCode in the url (mysite.com/home/Index), then the GetEndpoint
works.
How can i use the GetEndpoint()
method on the modified request url?
Is it another property on HttpContext
i need to change?
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);
}
I found a solution to this,
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;
}
Then i can do this
ControllerActionDescriptor controller = GetControllerByUrl(httpContext);
var countryCodeAttribute = controller.MethodInfo.GetCustomAttribute<MyAttribute>();
I don't know how well this scales, but it will work for now. I found the main part of the code here: Changing Request Path in .Net Core 3.1