NSwag: nswag v13 can't handle text\plain and string response
This is very old issue and it was fixed in v12, but appears again in v13: #701
Controller’s attributes:
[Produces("text/plain")]
[ProducesResponseType(typeof(FileContentResult), (int)HttpStatusCode.OK)]
[ProducesResponseType(typeof(string), (int)HttpStatusCode.OK)]
[ProducesResponseType(typeof(ErrorResponseMessage), (int)HttpStatusCode.BadRequest)]
[ProducesResponseType(typeof(ErrorResponseMessage), (int)HttpStatusCode.NotFound)]
Swagger:
"get": {
"tags": [ "Binary" ],
"summary": "Download binary as base64 string.",
"operationId": "DownloadBinaryAsBase64",
"consumes": [],
"produces": [ "text/plain" ],
"parameters": [
{
"name": "binaryId",
"in": "path",
"description": "Id of binary to fetch.",
"required": true,
"type": "string",
"format": "guid"
}
],
"responses": {
"200": {
"description": "Content downloaded.",
"schema": { "type": "string" }
},
"400": {
"description": "Request contains wrong data.",
"schema": { "$ref": "#/definitions/ErrorResponseMessage" }
},
"404": {
"description": "Not Found",
"schema": { "$ref": "#/definitions/ErrorResponseMessage" }
}
}
Produced code (part):
var status_ = ((int)response_.StatusCode).ToString();
if (status_ == "200")
{
var objectResponse_ = await ReadObjectResponseAsync<string>(response_, headers_).ConfigureAwait(false);
return objectResponse_.Object;
}
ReadObjectResponseAsync always try to deserialize the string and of course it will fail.
Revert to v12.2.5 fix the issue.
About this issue
- Original URL
- State: open
- Created 5 years ago
- Reactions: 8
- Comments: 64 (17 by maintainers)
Commits related to this issue
- Restoring special-case handling of text/plain (`IsPlainText`) responses. See GitHub issue #2384. — committed to daiplusplus/NSwag by daiplusplus 5 years ago
- Restoring special-case handling of text/plain (`IsPlainText`) responses. See GitHub issue #2384. (#2587) — committed to RicoSuter/NSwag by Jehoel 5 years ago
- Properly generate client code for string and array of string responses See Github issues #2384 and #2596. Attempt to resolve both issues handling plain text and JSON lists by checking for the respon... — committed to abborg/NSwag by abborg 3 years ago
Any idea when this patch will be released?
Done.
Yes, tested with 13.16.1.
This is still an issue with the default templates.
I worked around it by altering lines 13 to 22 in the
Client.Class.ReadResponseObject.liquidtemplate.Client.Class.ReadObjectResponse.liquid.txt (remove the .txt extension if you want to use this file)
I was having the same issue with OpenAPI spec generated from a .NET core API (Swashbuckle.AspNetCore 6.4.0), and then using Visual Studio’s Connected Services in a MAUI app to consume it. There are multiple pieces in this chain you need to get right.
TL;DR:
Microsoft.Extensions.ApiDescription.Clientto the latest 6.0.10, not 3.xNSwag.ApiDescription.Clientto version 13.17.0 not 13.05<CodeGenerator>NSwagCSharp</CodeGenerator>) make sure you:swaggerClient.csas it won’t regenerate or delete otherwiseThe following action method and attributes:
doesn’t produce any content in the spec:
(In fact any set of attributes that included application/json in the 200 response, made the generated code return nothing). So I settled on this:
and now the spec shows
So long as I have only one content type,
text/plain, and return a string, with the includedNSwag.ApiDescription.Clientversion 13.05, and the included (but obsolete)Microsoft.Extensions.ApiDescription.Client 3.0.3I get the autogenerated code:This throws an ApiException:
However upgrading
Microsoft.Extensions.ApiDescription.Clientto the latest 6.0.10 andNSwag.ApiDescription.Clientto version 13.17.0 gives me slightly different code:And this works 😁 😁 😁
It’s hard to isolate just one or the other package, as downgrading isn’t so simple, but I think it is
NSwag.ApiDescription.Clientthat needs the latest 13.17 version.Various other combinations of content type, or no content (see the attributes above) caused the generated code:
So I’ve got it working, but there are many parts in the chain where it can fail.
thanks for all the suggestions from this thread!
I’m getting this issue in 13.15.10 also. It is setting the
acceptheader totext/plainthen trying to parse the result as if it had setapplication/json.Perhaps all this is a result of an apparent lack of dynamism on the generated code’s behalf, and it should be saying “accept a or b” then examining what the response header says is in the message, a vs b, and acting based on that rather than a “swagger says a or b is available, ask for a, expect a” - this latter approach is less “be strict in what you send and liberal in what you receive” than the former
I tried with 13.9.3. I have
"produces": ["text/plain"]in my swagger.json 2.0 I still got generated code like this:await ReadObjectResponseAsync<string>(....)will cause the problem.I can confirm that the nswag.msbuild 13.20 package still has this issue:
relevant excerpt of my openapi spec
Generated code excerpt:
im using the following attributes on my controller action method:
And the return result is an
ActionResult<string>.When i leave out the explicit content type parameters of the
ProducesResponseTypeattribute the client generator interprets everything as json. And tries to deserialise the string content as json, which is wrong.Why it now generates a VOID response is unknown to me.
Im working around this by returning a wrapper object instead of a string. But its not ideal.
I used NSwag to generate a client from an API which resulted in the following code:
And since the generated ReadObjectResponseAsync<T>() method tries to do the following:
It also threw an error everytime the API returned a 200, since deserializing a string into a string doesnt work. While waiting for this to be solved I created the following class in my project as a fix since I couldnt use an earlier version of NSwag:
Not the best solution but it works for now (while i wait for the fix) and its simple, plus it allows me to (as seen in the last code snippet) “modify” the generated code while also allowing for easy regeneration of the client if the api changes without losing my changes.
I’ve just tested it with 13.16.1 and it works flawless for me. visual studio has installed 13.0.5 automatical, an update solved the problem
@shawty Please post text, not screenshots - we can’t search nor copy+paste code and data from screenshots: https://meta.stackoverflow.com/questions/303812/discourage-screenshots-of-code-and-or-errors
As for your problem:
If you’re returning plain-text (as in
text/plain) in your 404 responses then your[ProducesResponseType]attributes are wrong becausetypeof(string)combined withContent-Typeset toapplication/jsonmeans that your action will return JSON string for 404 - not that it will return atext/plainresponse. Rephrased: TheStringtype does not correspond to any particular HTTP responseContent-Typeheader value.Also,
application/jsonis also inappropriate and incorrect forFileStreamResult- but that didn’t cause any problems so far becauseFileStreamResultsets its own responseContent-Typeheader anyway). You’ll notice that the OpenAPI JSON does not listapplication/octet-streamfor200responses, even though it should.Unfortunately (and annoyingly) the
[ProducesResponseType]does not support specifying an explicitContent-Typevalue for per-status-code responses. The workaround you’ll need to customize the generated OpenAPI to change theContent-Typefor those error responses:(The below code is just an example, I haven’t compiled nor tested it).
That might be a bit of a problem 😃
I generate the client code direct into my project using NSwag, I don’t save or make a copy of the open API spec code.
Scrap that comment 😃
I screen shotted NSwag.
Hi @RicoSuter , yea sure… here you go
Had to reduce the font a little to make it fit on the screen…
Last bottom little bit is just the dispose calls
Please test with the latest version of NSwag, this has been changed a bit and might solve your problem.