Home > Mobile >  How to create a Net Core Middleware to validate a route parameter
How to create a Net Core Middleware to validate a route parameter

Time:01-08

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>>();
  • Related