我正在实现HashId,目的是将实体ID透明地转换为短哈希以供API使用。
目标:
/api/tag/dY7je
的请求应具有/api/tag/1
的效果(或已将其转换为)int
:public ActionResult<TagViewModel> Get(int id)
问题:
我创建了一个ActionFilterAttribute
来拦截请求,并将hash
转换为适当的id
,并更改RouteData
以使其匹配。但是,即使在更改RouteData
之后,任何使用[ApiController]
的控制器仍会返回错误消息"The value 'dY7je' is not valid."
。 如果我删除了[ApiController]
,修改后的值将传递到控制器操作,一切都很好。
问题:
[ApiController]
正在查看哪些数据,我可以通过ActionFilter
进行修改以避免出现此问题,我该怎么做?我已经搜索了ActionExecutingContext
,但是找不到那里的值。
我的粗糙动作过滤器:
public class HashIdFilterAttribute : ActionFilterAttribute, IOrderedFilter
{
public new int Order => int.MinValue;
public override void OnActionExecuting(ActionExecutingContext context)
{
foreach ((string paramKey, object value) in context.RouteData.Values)
{
if (paramKey.EndsWith("id", StringComparison.OrdinalIgnoreCase))
{
int id = HashIdsUtility.DecodeInt(value as string);
context.RouteData.Values[paramKey] = HashIdsUtility.DecodeInt(id);
context.ActionArguments[paramKey] = HashIdsUtility.DecodeInt(id);
}
}
base.OnActionExecuting(context);
}
}
答案 0 :(得分:0)
解决方案是使用在任何ResourceFilter
之前执行的ActionFilters
。 MSDocs
public class HashIdFilterAttribute : ActionFilterAttribute, IOrderedFilter, IResourceFilter
{
public new int Order => int.MinValue;
public void OnResourceExecuted(ResourceExecutedContext context)
{
return;
}
public void OnResourceExecuting(ResourceExecutingContext context)
{
ProcessRouteData(context.RouteData);
}
private void ProcessRouteData(RouteData routeData)
{
foreach ((string paramKey, object value) in routeData.Values)
{
if (paramKey.EndsWith("id", StringComparison.OrdinalIgnoreCase))
{
routeData.Values[paramKey] = HashIdsUtility.DecodeInt(value as string);
}
}
}
}