RicoSuter / NSwag

The Swagger/OpenAPI toolchain for .NET, ASP.NET Core and TypeScript.
http://NSwag.org
MIT License
6.78k stars 1.29k forks source link

FileResponse compile-time error #1875

Open novakmarkov opened 5 years ago

novakmarkov commented 5 years ago

Hi,

I'I have one issue with NSWAG (i'm using the latest 12.0.10.0).

When i have in openapi 3.0 definition , response for api which downloads a file, like this:

responses: '200': description: The content of the file content: application/octet-stream: schema: type: string format: binary

In my C# Web Api controller generated code , i have compile-time error in:

HttpResponseMessage response = Request.CreateResponse(status, result.Result);

where Result doesn't exists in FileResponse class:

  public partial class FileResponse : System.IDisposable
  {
    private System.IDisposable _client;
    private System.IDisposable _response;

    public int StatusCode { get; private set; }

    public System.Collections.Generic.Dictionary<string, System.Collections.Generic.IEnumerable<string>> Headers { get; private set; }

    public System.IO.Stream Stream { get; private set; }

    public bool IsPartial
    {
      get { return StatusCode == 206; }
    }

    public FileResponse(int statusCode, System.Collections.Generic.Dictionary<string, System.Collections.Generic.IEnumerable<string>> headers, System.IO.Stream stream, System.IDisposable client, System.IDisposable response)
    {
      StatusCode = statusCode;
      Headers = headers;
      Stream = stream;
      _client = client;
      _response = response;
    }

    public void Dispose()
    {
      if (Stream != null)
        Stream.Dispose();
      if (_response != null)
        _response.Dispose();
      if (_client != null)
        _client.Dispose();
    }
  }

So either this is a compile-time error with generated code or i should use some other type of response ?

Thank you.

RicoSuter commented 5 years ago

Canyou post a sample spec?

RicoSuter commented 5 years ago

Is this a problem with c# controller code generation?

novakmarkov commented 5 years ago

Yes this is the problem with Web Api C# controller code generation.

novakmarkov commented 5 years ago

Hi,

This is the simple yaml for download:

x-generator: NSwag v11.20.1.0 (NJsonSchema v9.11.0.0 (Newtonsoft.Json v11.0.0.0))
openapi: 3.0.0
info:
  title: Download 
  description: Download
  contact:
    name: Download
  version: 1.0.0-e
servers:
  - url: /api
paths:
  '/download':
    get:
      tags:
        - Download
      summary: Download
      description: Download
      responses:
        '200':
          description: The content of the file
          content:
            application/octet-stream:
              schema:
                type: string
                format: binary

Please if you can advise me if i should change response type or if this is a bug. Thank you.

RicoSuter commented 5 years ago

I currently dont use the controller generators in any projects thats why some features are still missing and there might be some bugs - also asp.net core is not yet fully supported

novakmarkov commented 5 years ago

Ok thanks for the answer. Just to be sure, you will check to see if it's a bug and then put it in some of the future release ?

RicoSuter commented 5 years ago

So the output is

//----------------------
// <auto-generated>
//     Generated using the NSwag toolchain v12.0.11.0 (NJsonSchema v9.13.13.0 (Newtonsoft.Json v11.0.0.0)) (http://NSwag.org)
// </auto-generated>
//----------------------

namespace MyNamespace
{
    #pragma warning disable

    [System.CodeDom.Compiler.GeneratedCode("NSwag", "12.0.11.0 (NJsonSchema v9.13.13.0 (Newtonsoft.Json v11.0.0.0))")]
    public interface IController
    {
        /// <summary>Download</summary>
        /// <returns>The content of the file</returns>
        System.Threading.Tasks.Task<FileResponse> DownloadAsync();

    }

    [System.CodeDom.Compiler.GeneratedCode("NSwag", "12.0.11.0 (NJsonSchema v9.13.13.0 (Newtonsoft.Json v11.0.0.0))")]
    [System.Web.Http.RoutePrefix("api")]
    public partial class Controller : System.Web.Http.ApiController
    {
        private IController _implementation;

        public Controller(IController implementation)
        {
            _implementation = implementation;
        }

        /// <summary>Download</summary>
        /// <returns>The content of the file</returns>
        [System.Web.Http.HttpGet, System.Web.Http.Route("download")]
        public System.Threading.Tasks.Task<FileResponse> Download()
        {
            return _implementation.DownloadAsync();
        }
    }

    public partial class FileResponse : System.IDisposable
    {
        private System.IDisposable _client; 
        private System.IDisposable _response; 

        public int StatusCode { get; private set; }

        public System.Collections.Generic.Dictionary<string, System.Collections.Generic.IEnumerable<string>> Headers { get; private set; }

        public System.IO.Stream Stream { get; private set; }

        public bool IsPartial
        {
            get { return StatusCode == 206; }
        }

        public FileResponse(int statusCode, System.Collections.Generic.Dictionary<string, System.Collections.Generic.IEnumerable<string>> headers, System.IO.Stream stream, System.IDisposable client, System.IDisposable response)
        {
            StatusCode = statusCode; 
            Headers = headers; 
            Stream = stream; 
            _client = client; 
            _response = response;
        }

        public void Dispose() 
        {
            if (Stream != null)
                Stream.Dispose();
            if (_response != null)
                _response.Dispose();
            if (_client != null)
                _client.Dispose();
        }
    }

    #pragma warning restore
}

I think for controllers it should not generate FileResponse at all but just return a Stream - or is this not working in ASP.NET (Core)?

Alamaster99 commented 5 years ago

Hi, is there any progress on this? I believe that in .net core controller it should generate FileResult or just ActionResult.

Alamaster99 commented 5 years ago

Hi @RicoSuter , I have created a pull request for this issue. It seems to fix my problem. https://github.com/RicoSuter/NSwag/pull/2376

RobinHerbots commented 4 years ago

@novakmarkov, @RicoSuter, @Alamaster99,

Is there any update on this?

I temporaly solved it by adding the following in the generated c# client

using FileResponse=Microsoft.AspNetCore.Mvc.IActionResult;
RicoSuter commented 4 years ago

The pr above is merged and released, doesnt that fix your problem

RobinHerbots commented 4 years ago

@RicoSuter,

I used the openApiToCSharpClient that's why. The PR only applies to generating c# controllers.

ud09 commented 4 years ago

@Alamaster99 @RicoSuter When useActionResultType setting is true it creates: public abstract System.Threading.Tasks.Task<Microsoft.AspNetCore.Mvc.ActionResult<FileResult>> which is not correct. It should not wrap with ActionResult. Below part still doesn't check for FileResult.

public string SyncResultType
{
    get
    {
        if (_settings != null && WrapResponse && UnwrappedResultType != "FileResponse")
        {
            return UnwrappedResultType == "void"
                ? _settings.ResponseClass.Replace("{controller}", ControllerName)
                : _settings.ResponseClass.Replace("{controller}", ControllerName) + "<" + UnwrappedResultType + ">";
        }

        return UnwrappedResultType;
    }
}

Also FileResult namespace should be included to prevent compile error, like below. I couldn't find how to fix this in nswag code. public abstract System.Threading.Tasks.Task<Microsoft.AspNetCore.Mvc.FileResult>

LubosKato commented 4 years ago

got the same issue as above please fix

skorunka commented 4 years ago

Same problem here :(

gastonmuijtjens commented 4 years ago

@Alamaster99 @RicoSuter When useActionResultType setting is true it creates: public abstract System.Threading.Tasks.Task<Microsoft.AspNetCore.Mvc.ActionResult<FileResult>>

@RicoSuter I have the same problem here. Any indication on when this could be fixed? Thank you in advance!

davicbaba commented 4 years ago

Same problem here :(

yves1982 commented 4 years ago

my current workaround for this problem using a string replacement task in msbuild:

Add this to the csproj file after the NSwag Code generation task:

<Target Name="NSwag" BeforeTargets="PrepareForBuild">
  <!-- openApi2cscontroller code generate here -->
</Target>

<UsingTask TaskName="TokenReplace" TaskFactory="CodeTaskFactory" 
   AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.Core.dll">
    <ParameterGroup>
      <Path ParameterType="System.String" Required="true" />
      <Token ParameterType="System.String" Required="true" />
      <Replacement ParameterType="System.String" Required="true" />
    </ParameterGroup>
    <Task>
      <Code Type="Fragment" Language="cs">
        <![CDATA[
string content = File.ReadAllText(Path);
content = content.Replace(Token, Replacement);
File.WriteAllText(Path, content);

]]>
      </Code>
    </Task>
</UsingTask>

<Target Name="FixNamespace" AfterTargets="NSwag" >
    <TokenReplace Path="Boundary\Generated\MyGeneratedControllerBase.cs"
                  Token="&lt;Microsoft.AspNetCore.Mvc.ActionResult&lt;FileResult&gt;&gt;"
                  Replacement="&lt;Microsoft.AspNetCore.Mvc.ActionResult&lt;Microsoft.AspNetCore.Mvc.FileResult&gt;&gt;" />
</Target>
kbilsted commented 2 years ago

Seems like there is a missing using Microsoft.AspNetCore.Mvc; in the code generation or type out the fully qualified name where ever FileResult is used.

simonbor commented 1 year ago

Locally the fix (using FileResponse = Microsoft.AspNetCore.Mvc.IActionResult;) is working well, but during CI/CD it will be a real issue.

Is there any update about it?