NSwag: Bug in Error serialization openapi2csclient
my yaml:
Error:
type: object
properties:
code:
$ref: '#/components/schemas/ErrorCode'
description:
type: string
Errors:
type: object
properties:
errors:
type: array
items:
$ref: '#/components/schemas/Error'
ErrorCode:
description: Enum of errors
type: string
enum:
- NOTFOUND
- GENERAL_EXCEPTION
service I am calling returns this:
{
"errors": [
{
"code": "GENERAL_EXCEPTION",
"description": "03396370-ddc4-41c4-ae03-ed07249a9d1b - Not supported yet."
}
]
}
I cannot get serialized object Errors in proper format with current error handling. This is current generated c# code
if (status_ == "500")
{
var objectResponse_ = await ReadJsonObjectResponseAsync<Errors>(response_, headers_).ConfigureAwait(false);
throw new ApiException<Errors>("Error", (int)response_.StatusCode, objectResponse_.Text, headers_, objectResponse_.Object, null);
}
objectResponse_ contains Errors object which is what I get from service I am calling but Text property is empty and the Errors object is not seriliazed correctly
this used to work in my previously generated code:
if (status_ == "500")
{
var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
var result_ = default(Errors);
try
{
result_ = Newtonsoft.Json.JsonConvert.DeserializeObject<Errors>(responseData_, _settings.Value);
}
catch (System.Exception exception_)
{
throw new SwaggerException("Could not deserialize the response body.", (int)response_.StatusCode, responseData_, headers_, exception_);
}
throw new SwaggerException<Errors>("Errors", (int)response_.StatusCode, responseData_, headers_, result_, null);
}
About this issue
- Original URL
- State: closed
- Created 5 years ago
- Comments: 19 (15 by maintainers)
@rars Oh, I see there’s a new NSwag template
Client.Class.Constructorthat you can override (so you don’t need any other*.liquidtemplates) to set the property - that’s probably the best approach.@rars
There are several options.
The simplest is to set
ReadResponseAsStringin a partial method - which requires addingpartial classdeclarations in another file and keeping it in-sync with the NSwag-generated clients. TheProcessResponsepartial method is the best place to setReadResponseAsStringas it’s always called right before deserialization:Another approach, which uses MEDI, and is documented by Microsoft as the prescribed way for customizing registered typed-clients is to use
ITypedHttpClientFactory.Unfortunately because the
ReadResponseAsStringproperty isn’t attached to any superclass or interface we can’t use a common factory method for all of your typed clients - also you’ll need to reimplementITypedHttpClientFactory- which is a pain. And I won’t go into details here.I think the best approach here is to override the Liquid template that NSwag is using to generate a client class constructor that sets the
this.ReadResponseAsString = false;…or just subclass all of the typed clients and set the property there:
…which is about the same amount of effort as using partial classes.
@RicoSuter I think the option to use
ReadResponseAsStringshould be a configurable option in NSwag client generation options - as well as adding an optional interfaceITypedClientthat exposes common members to external consumers, such as theReadResponseAsStringproperty.On the generated client class