ASP.NET Core WebApi判断当前请求的API类型

上次,我们判断了《当前请求是否健康检查API》,避免其写入日志。

但是,对于我们自己开发的API来说,最好也能来区分,比如调试用API,就不需要再写调用日志了。

DisplayName方式

直接判断路由地址的方式就不考虑了。

本来想使用和上次一样的DisplayName方式,但是发现没有地方为Controller设置。

查看源码,发现ActionDisplayName属性的实现在ControllerActionDescriptor.cs.

public override string? DisplayName
{
    get
    {
        if (base.DisplayName == null && ControllerTypeInfo != null && MethodInfo != null)
        {
            base.DisplayName = string.Format(
                CultureInfo.InvariantCulture,
                "{0}.{1} ({2})",
                TypeNameHelper.GetTypeDisplayName(ControllerTypeInfo),
                MethodInfo.Name,
                ControllerTypeInfo.Assembly.GetName().Name);
        }

        return base.DisplayName!;
    }

    set
    {
        if (value == null)
        {
            throw new ArgumentNullException(nameof(value));
        }

        base.DisplayName = value;
    }
}

DisplayName是由"Controller类名.方法名 (Assembly名)"组成。

如果你的Controller类名/方法名命名有规律,可以考虑DisplayName方式。

Metadata方式

此路不通,考虑其他方式。

我们知道将Controller的方法添加为API端点是通过endpoints.MapControllers();,查看其实现源码,最终定位到ActionEndpointFactory.cs,其中有这样一段代码:

// MVC guarantees that when two of it's endpoints have the same route name they are equivalent. 
// 
// The case for this looks like: 
// 
// [HttpGet] 
// [HttpPost] 
// [Route("/Foo", Name = "Foo")] 
// public void DoStuff() { } 
// 
// However, Endpoint Routing requires Endpoint Names to be unique. 
// 
// We can use the route name as the endpoint name if it's not set. Note that there's no 
// attribute for this today so it's unlikley. Using endpoint name on a 
if (routeName != null && 
!suppressLinkGeneration && 
routeNames.Add(routeName) && 
builder.Metadata.OfType<IEndpointNameMetadata>().LastOrDefault()?.EndpointName == null) 
{ 
builder.Metadata.Add(new EndpointNameMetadata(routeName)); 
} 

通过注释,我们可以知道Asp.Net Core会把RouteName写入端点的Metadata属性。

那么,我们只需要判断EndpointNameMetadata即可:

var endpointName = context.GetEndpoint()?.Metadata.GetMetadata<EndpointNameMetadata>()?.EndpointName;
if (!string.IsNullOrEmpty(endpointName) && endpointName.StartsWith("Debug_"))
{
}
else
{
    //Log
}