I want to create an IRouteConstraint that filters a value against possibl开发者_运维技巧e values of an enum. I tried to google it for myself, but that didn't result in anything.
Any ideas?
This is what I came up with:
public class EnumRouteConstraint<T> : IRouteConstraint
where T : struct
{
private readonly HashSet<string> enumNames;
public EnumRouteConstraint()
{
string[] names = Enum.GetNames(typeof(T));
enumNames = new HashSet<string>(from name in names select name.ToLowerInvariant());
}
public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
{
return enumNames.Contains(values[parameterName].ToString().ToLowerInvariant());
}
}
I think a HashSet will perform much better than Enum.GetNames on each Match. Also the use generics makes it look a bit more fluent when you use the constraint.
Unfortunately, where T : Enum is not allowed by the compiler.
See this
Essentially, you need
private Type enumType;
public EnumConstraint(Type enumType)
{
this.enumType = enumType;
}
public bool Match(HttpContextBase httpContext,
Route route,
string parameterName,
RouteValueDictionary values,
RouteDirection routeDirection)
{
// You can also try Enum.IsDefined, but docs say nothing as to
// is it case sensitive or not.
return Enum.GetNames(enumType).Any(s => s.ToLowerInvariant() == values[parameterName].ToString());
}
----------------- 2022 Update -----------------
Try to use a generic RouteConstraint
builder.Services.Configure<RouteOptions>(routeOptions =>
{
routeOptions.ConstraintMap.Add(nameof(Status) , typeof(EnumConstraint<Status>));
});
public class EnumConstraint<TEnum> : IRouteConstraint
where TEnum : struct, IConvertible
{
bool IRouteConstraint.Match(HttpContext? httpContext, IRouter? route, string routeKey, RouteValueDictionary values, RouteDirection routeDirection)
{
if (httpContext == null)
throw new ArgumentNullException(nameof(httpContext));
if (route == null)
throw new ArgumentNullException(nameof(route));
if (routeKey == null)
throw new ArgumentNullException(nameof(routeKey));
if (values == null)
throw new ArgumentNullException(nameof(values));
if (values.TryGetValue(routeKey, out var routeValue))
{
if(!typeof(TEnum).IsEnum)
throw new ArgumentException($"{nameof(TEnum)} is not enum!");
var parameterValueString = Convert.ToString(routeValue, CultureInfo.InvariantCulture);
if (parameterValueString is null)
return false;
EnumConverter enumConverter = new (typeof(TEnum));
if (enumConverter.ConvertFromString(parameterValueString) is not null)
return true;
}
return false;
}
}
精彩评论