如何解决在ASP.NET Web API中将自定义标头参数与swashbuckle挂起调用一起使用
我有这种怪异的行为,当我在Swagger UI(和其他API客户端)中设置自定义标头参数时,调用只是挂起并且永远不会返回,请求没有记录(我正在用DelegatHandler记录),也没有我在浏览器或API客户端(尝试过Postman)中得到响应。
我尝试了多种添加方式。最初,我将其作为方法的参数,只是更改了名称:
Get(int id,[FromHeader("X-Request-ID")] Guid? x_Request_ID = null)
FromHeaderAttribute实现:
public class FromHeaderAttribute : ParameterBindingAttribute
{
public virtual string Name { get; set; }
public override HttpParameterBinding GetBinding(HttpParameterDescriptor parameter)
{
return new FromHeaderBinding(parameter,parameter.ParameterName);
}
}
public class FromHeaderBinding : HttpParameterBinding
{
private readonly string _name;
public FromHeaderBinding(HttpParameterDescriptor parameter,string headerName)
: base(parameter)
{
if (string.IsNullOrEmpty(headerName))
{
throw new ArgumentNullException("headerName");
}
_name = headerName;
}
public override Task ExecuteBindingAsync(ModelMetadataProvider metadataProvider,HttpActionContext actionContext,CancellationToken cancellationToken)
{
if (actionContext.Request.Headers.TryGetValues(_name,out var values))
{
var converter = TypeDescriptor.GetConverter(Descriptor.ParameterType);
try
{
actionContext.ActionArguments[Descriptor.ParameterName] = converter.ConvertFromString(values.FirstOrDefault());
}
catch (Exception exception)
{
var error = new HttpError("The request is invalid.") { MessageDetail = exception.Message };
throw new HttpResponseException(actionContext.Request.CreateErrorResponse(HttpStatusCode.BadRequest,error));
}
}
else if (Descriptor.IsOptional)
{
actionContext.ActionArguments[Descriptor.ParameterName] = Descriptor.DefaultValue;
}
else
{
var error = new HttpError("The request is invalid.") { MessageDetail = $"The `{_name}` header is required." };
throw new HttpResponseException(actionContext.Request.CreateErrorResponse(HttpStatusCode.BadRequest,error));
}
return Task.FromResult<object>(null);
}
}
并且我有一个操作过滤器,用于更改客户端的字段名称:
var headerParameters = apiDescription.ParameterDescriptions
.Where(p => p.ParameterDescriptor.ParameterBinderAttribute is FromHeaderAttribute);
if (headerParameters.Any())
{
if (operation.parameters == null)
{
operation.parameters = new List<Parameter>();
}
var temp = headerParameters.Join(operation.parameters ?? new List<Parameter>(),p1 => p1.Name,p2 => p2.name,(p1,p2) => new
{
parameterBinding = p1.ParameterDescriptor.ParameterBinderAttribute as FromHeaderAttribute,paramterDescription = p1,operationParameter = p2
})
.ToList();
temp.ForEach(p =>
{
p.operationParameter.Remove(p.operationParameter);
operation.parameters.Add(new Parameter
{
name = p.parameterBinding.Name,@in = "header",description = p.operationParameter.description,type = p.operationParameter.type,required = p.operationParameter.required,format = p.operationParameter.format
});
});
}
后来我将最后一部分更改为简单:
p.operationParameter.name = p.parameterBinding.Name;
p.operationParameter.@in = "header";
代替添加/删除参数。
问题是,无论何时传递了无效的GUID(uuid v4),调用都被挂起,从未返回,并且在我的代码中未记录任何内容,但是IIS日志显示该请求以预期的结果传递了。调试时,我的代码也没有在ExecuteBindingAsync中中断。
如果Guid格式正确,则一切正常。
我发现改名是(最有可能的)主要问题,当测试除改名外的所有内容都相同时,即只是过滤器而已:
p.operationParameter.@in = "header";
每次都能很好地工作,但是Swagger中的标头是x_Request_ID
。我以为名称更改是问题所在,因此为了进行测试,创建了一个简单的方法,在其中我刚刚添加了一个新参数:
if (operation.operationId == "API_Get2")
{
operation.parameters.Add(new Parameter
{
name = "X-Request-ID",description = "Request ID",type = "string",required = false
format = "uuid"
});
}
,并将操作的签名更改为:
Get(int id)
但是,无论它是有效还是无效的GUID,它每次都挂起。
我一直在试图找出原因,以及如何正确地以大张旗鼓显示自定义标头,并使代码正常解析两天,而且没有运气。我还尝试了ModelBinding,但是在那种情况下,标题只是被忽略了。
对我来说,如果标头是操作的参数,还是不一样,我只是希望它能以准确的说明显示出来。
非常感谢您对我在这里错过的任何解决方案或问题的指点。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。