Using Net Core 7 I have Razor Pages with a culture
route parameter:
@page "/{culture:validculture}/about"
I created a custom route constraint to check if culture
has a valid value.
When the culture
value is invalid I am redirected to a 404 error page.
public class CultureRouteConstraint : IRouteConstraint {
private readonly RequestLocalizationOptions _options;
public CultureRouteConstraint(IOptionsSnapshot<RequestLocalizationOptions> options) {
_options = options.Value;
}
public Boolean Match(HttpContext? httpContext, IRouter? route, String routeKey, RouteValueDictionary values, RouteDirection routeDirection) {
String? culture = Convert.ToString(value, CultureInfo.InvariantCulture);
List<String>? cultures = _options.SupportedCultures?.Select(x => x.TwoLetterISOLanguageName).ToList();
if (culture != null && cultures != null)
return cultures.Contains(culture, StringComparer.InvariantCultureIgnoreCase);
}
}
This works great if I hardcode de valid cultures, e.g:
List<String>? cultures = new() { "en", "pt" };
But if I inject RequestLocalizationOptions
I get the error:
RouteCreationException: An error occurred while trying to create an instance of 'CultureRouteConstraint'.
Maybe I need to use a Middleware for this? How can I do this?
CodePudding user response:
Looks like you are using DI to inject the RequestLocalizationOptions into your CultureRouteConstraint class. However, the IRouteConstraint interface does not support DI, so you cannot inject dependencies into it directly.
One option you could consider is using a middleware to handle the routing constraint. The middleware could use DI to inject the RequestLocalizationOptions and then check the culture value before passing control to the appropriate Razor page.
Here's an example of what this might look like:
public class CultureMiddleware
{
private readonly RequestDelegate _next;
private readonly RequestLocalizationOptions _options;
public CultureMiddleware(RequestDelegate next, IOptionsSnapshot<RequestLocalizationOptions> options)
{
_next = next;
_options = options.Value;
}
public async Task InvokeAsync(HttpContext context)
{
// Check the culture value
string culture = context.Request.RouteValues["culture"].ToString();
if (!_options.SupportedCultures.Select(x => x.TwoLetterISOLanguageName).Contains(culture, StringComparer.InvariantCultureIgnoreCase))
{
// Redirect to a 404 page if the culture value is invalid
context.Response.StatusCode = 404;
return;
}
// If the culture value is valid, pass control to the next middleware
await _next(context);
}
}
CodePudding user response:
Seems like you cannot use a DI constructor when working with implementations of IRouteConstraint
, but you have the HttpContext
in your Match
method. So, you can resolve the IOptionsSnapshot
from there. This should work:
var opts = ctx
.RequestServices
.GetService<IOptionsSnapshot<RequestLocalizationOptions>>();