We have a strange issue with reflexion in ServiceStack.Api.Swagger (using .NET framework 4.6, nugget package 4.5.4).
Before commit 92646b3aa0e1e9d66911163b3057c39db83eb083, we were implementing IApiResponseDescription for custom api response attributes.
Now we have to override ApiResponseAttribute and there is a strange behaviour: only first custom attribute is retrieved, so only one status code is displayed in Swagger.
Step to reproduce:
Create new custom response attribute
/// <summary>
/// Custom API response attribute
/// </summary>
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = true)]
public sealed class CustomApiResponseAttribute : ApiResponseAttribute
{
private static int errCode = 402;
public CustomApiResponseAttribute()
: base(++errCode, Guid.NewGuid().ToString())
{}
}
Sample request:
/// <summary>
/// Sample request
/// </summary>
[ApiResponse(400, "Code 1")]
[CustomApiResponse()]
[ApiResponse(402, "Code 2")]
[CustomApiResponse()]
[CustomApiResponse()]
[ApiResponse(401, "Code 3")]
[Route("/sample", Verbs = "POST", Summary = "Sample request")]
public sealed class SampleRequest : IReturnVoid
{}
Issue is located here:
ServiceStack.Api.Swagger
=> SwaggerApi FormatMethodDescription(RestPath restPath, Dictionary<string, SwaggerModel> models)
=> ErrorResponses = GetMethodResponseCodes(requestType)
Debugging method content:
var requestType = typeof(SampleRequest);
requestType
.AllAttributes<ApiResponseAttribute>()
.Select(x => new ErrorResponseStatus
{
StatusCode = x.StatusCode,
Reason = x.Description
})
.OrderBy(x => x.StatusCode)
.ToList()
.ForEach(x => Debug.WriteLine("{0}:{1}", x.StatusCode, x.Reason));
Result:
400:Code 1
401:Code 3
402:Code 2
403:5009a341-4c64-4c0d-896a-09c144d52d54
Replacing .AllAttributes() with method content
requestType
.GetCustomAttributes(typeof(ApiResponseAttribute), true)
.OfType<ApiResponseAttribute>()
//.Union(requestType.GetRuntimeAttributes<ApiResponseAttribute>())
.ToArray()
.Select(x => new ErrorResponseStatus
{
StatusCode = x.StatusCode,
Reason = x.Description
})
.OrderBy(x => x.StatusCode)
.ToList()
.ForEach(x => Debug.WriteLine("{0}:{1}", x.StatusCode, x.Reason));
Result:
400:Code 1
401:Code 3
402:Code 2
406:d4bbdc55-d743-4b58-ad95-b1a43d0e2148
407:0e8d45ab-0727-49e8-9736-fb8fa75aceaa
408:ab2d8882-82bb-4042-91bb-f277d910623a
Do you have any idea?