Skip to content

Instantly share code, notes, and snippets.

@GeorgDangl
Last active August 4, 2021 21:52
Show Gist options
  • Save GeorgDangl/acecc279b2cbf7f366a6487eb50d3833 to your computer and use it in GitHub Desktop.
Save GeorgDangl/acecc279b2cbf7f366a6487eb50d3833 to your computer and use it in GitHub Desktop.
[HttpGet("")]
[LightQuery]
[Authorize(Policy = DanglIdentityConstants.Authorization.AUTHENTICATION_CONNECTOR_OR_ADMIN_POLICY_NAME)]
[NSwag.Annotations.SwaggerResponse((int)HttpStatusCode.OK, typeof(PaginationResult<ClientGet>))]
[NSwag.Annotations.SwaggerResponse((int)HttpStatusCode.OK, typeof(IEnumerable<ClientGet>))]
public IActionResult GetAllClients(string filter = null)
{
var clientsQuery = _identityServerClientsRepository.GetAllClients()
.ProjectTo<ClientGet>();
if (!string.IsNullOrWhiteSpace(filter))
{
clientsQuery = clientsQuery.Where(c => c.ClientName.Contains(filter) || c.ClientUri.Contains(filter));
}
return Ok(clientsQuery);
}
[HttpGet("")]
[LightQuery]
[Authorize(Policy = DanglIdentityConstants.Authorization.AUTHENTICATION_CONNECTOR_OR_ADMIN_POLICY_NAME)]
[ProducesResponseType(typeof(PaginationResult<ClientGet>), 200)]
[ProducesResponseType(typeof(ClientGet), 200)]
public IActionResult GetAllClients(string filter = null)
{
var clientsQuery = _identityServerClientsRepository.GetAllClients()
.ProjectTo<ClientGet>();
if (!string.IsNullOrWhiteSpace(filter))
{
clientsQuery = clientsQuery.Where(c => c.ClientName.Contains(filter) || c.ClientUri.Contains(filter));
}
return Ok(clientsQuery);
}
{
"operationId": "Clients_GetAllClients",
"responses": {
"200": {
"x-nullable": true,
"description": "",
"schema": {},
"x-expectedSchemas": [
{
"description": "",
"schema": {
"$ref": "#/definitions/PaginationResultOfClientGet"
}
},
{
"description": "",
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/ClientGet"
}
}
}
]
}
}
}
{
"operationId": "Clients_GetAllClients",
"responses": {
"200": {
"x-nullable": true,
"description": "",
"schema": {
"$ref": "#/definitions/PaginationResultOfClientGet"
}
}
}
}
// With the framework-provided ProducesResponseTypeAttribute, it just used the first response type
System.Threading.Tasks.Task<PaginationResult<ClientGet>> GetAllClientsAsync(string filter);
// While the NSwag specific attribute correctly recognized there are two schemas and thus typed the response as 'object'
System.Threading.Tasks.Task<object> GetAllClientsAsync(string filter);
[Fact]
public async Task GeneratesPaginationResultAndEnumerableForGetAllClientsAction()
{
_url = "http://example.com/swagger/swagger.json";
await MakeRequest();
var responseString = await _response.Content.ReadAsStringAsync();
var json = JObject.Parse(responseString);
var expectedSchemas = json["paths"]["/api/clients"]["get"]["responses"]["200"]["x-expectedSchemas"] as JArray;
Assert.NotNull(expectedSchemas);
Assert.Equal(2, expectedSchemas.Count);
}
[Fact]
public void NoControllerHasMultipleResponseTypesDefined()
{
// There was a behavior change between NSwag 11.19 and 11.20. Previously,
// having two attributes of type [ResponseType] was OK and resulted in
// both being considered int he Swagger specification. After the update,
// only the first attribute was considered, thus creating incorrect
// Swagger clients.
var controllerMethods = typeof(Dangl.Identity.Startup)
.GetTypeInfo()
.Assembly
.DefinedTypes
.Where(t => typeof(Microsoft.AspNetCore.Mvc.ControllerBase).GetTypeInfo().IsAssignableFrom(t))
.SelectMany(controllerType => controllerType.DeclaredMethods)
.ToList();
Assert.NotEmpty(controllerMethods);
foreach (var controllerMethod in controllerMethods)
{
var methodAttributes = controllerMethod.CustomAttributes
.Where(att => att.AttributeType == typeof(Microsoft.AspNetCore.Mvc.ProducesResponseTypeAttribute))
.Where(att => att.ConstructorArguments.Count == 2) // Only taking the overload which defines a status code and a response type
.Where(att => att.ConstructorArguments.Any(arg => arg.Value is int statusCode && (statusCode >= 200 && statusCode <= 299))) // Only where success status codes are defined
.ToList();
Assert.False(methodAttributes.Count > 1);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment