NSwag icon indicating copy to clipboard operation
NSwag copied to clipboard

Bad code generation for application/zip

Open SlimRG opened this issue 7 months ago • 0 comments

I have controller:

/// <summary>
/// Получение контента документа.
/// </summary>
[HttpPost]
[Route("/v2/documents/content")]
[Produces(MediaTypeNames.Application.Zip)]
[ProducesResponseType(typeof(byte[]), 200)]
public async Task<IActionResult> DocumentsContent(
    [FromBody] JsonDocument json,
    [FromServices] IDocumentsContentLogic documentsContentLogic)
{
    var result = await documentsContentLogic.RunAsync(json);
    if (result.IsError == false)
    {
        var fileResult = result.SuccessResult;
        Response.ContentType = fileResult.ContentType;
        Response.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
        {
            FileName = fileResult.FileDownloadName
        }.ToString();
        await Response.Body.WriteAsync(fileResult.FileContents, 0, fileResult.FileContents.Length);
    }
    return new EmptyResult();
}

In swagger all ok, in swagger.json is strange magic, because of byte[] not base64 - it's binary

But! In generated client I see error:

public async System.Threading.Tasks.Task<byte[]> DocumentsContentAsync(object? body = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken))
{
    var urlBuilder_ = new System.Text.StringBuilder();
    urlBuilder_.Append("v2/documents/content");
    
    var client_ = await CreateHttpClientAsync(cancellationToken).ConfigureAwait(false);
    var disposeClient_ = false;
    try
    {
        using (var request_ = new System.Net.Http.HttpRequestMessage())
        {
            var content_ = new System.Net.Http.StringContent(System.Text.Json.JsonSerializer.Serialize(body, _settings.Value));
            content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json");
            request_.Content = content_;
            request_.Method = new System.Net.Http.HttpMethod("POST");
            request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/zip"));
    
            PrepareRequest(client_, request_, urlBuilder_);
    
            var url_ = urlBuilder_.ToString();
            request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute);
    
            PrepareRequest(client_, request_, url_);
    
            var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false);
            var disposeResponse_ = true;
            try
            {
                var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value);
                if (response_.Content != null && response_.Content.Headers != null)
                {
                    foreach (var item_ in response_.Content.Headers)
                        headers_[item_.Key] = item_.Value;
                }
    
                ProcessResponse(client_, response_);
    
                var status_ = (int)response_.StatusCode;
                if (status_ == 200)
                {
                    var objectResponse_ = await ReadObjectResponseAsync<byte[]>(response_, headers_, cancellationToken).ConfigureAwait(false);
                    if (objectResponse_.Object == null)
                    {
                        throw new KFAPIClientException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null);
                    }
                    return objectResponse_.Object;
                }
                else
                if (status_ == 400)
                {
                    var objectResponse_ = await ReadObjectResponseAsync<ErrorResponse>(response_, headers_, cancellationToken).ConfigureAwait(false);
                    if (objectResponse_.Object == null)
                    {
                        throw new KFAPIClientException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null);
                    }
                    throw new KFAPIClientException<ErrorResponse>("\u0417\u0430\u043f\u0440\u043e\u0441 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u043d\u0435\u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null);
                }
                else
                if (status_ == 500)
                {
                    var objectResponse_ = await ReadObjectResponseAsync<ErrorResponse>(response_, headers_, cancellationToken).ConfigureAwait(false);
                    if (objectResponse_.Object == null)
                    {
                        throw new KFAPIClientException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null);
                    }
                    throw new KFAPIClientException<ErrorResponse>("\u041f\u0440\u043e\u0438\u0437\u043e\u0448\u043b\u0430 \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u044f\u044f \u043e\u0448\u0438\u0431\u043a\u0430 \u0441\u0435\u0440\u0432\u0438\u0441\u0430, \u043e \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u043d\u0443\u0436\u043d\u043e \u0441\u043e\u043e\u0431\u0449\u0438\u0442\u044c \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430\u043c.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null);
                }
                else
                {
                    var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
                    throw new KFAPIClientException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null);
                }
            }
            finally
            {
                if (disposeResponse_)
                    response_.Dispose();
            }
        }
    }
    finally
    {
        if (disposeClient_)
            client_.Dispose();
    }
}

As you can see - ReadObjectResponseAsync, which incudes json deserialization, but response is NOT IN JSON!!!

So, you client will always crash on SerializationException.

How can I fix this problem?

NSwag", "13.14.5.0 (NJsonSchema v10.5.2.0 (Newtonsoft.Json v13.0.0.0))

SlimRG avatar Jul 17 '24 15:07 SlimRG