1

I'm using the java Swagger-Codegen class to generate the c# client for a Swagger Web Api exposing a firmware publishing service.

The public Byte[] LelFile property of the PackagePublishRequestInfoAndLel dto class required as parameter of the public async Task<IHttpActionResult> PublishPackageAsync(...) ApiController method is missing in the generated client DataContract class.

Did I make something wrong ? Is there something special to do to handle Byte[] properties ? Or is this an issue to report in the Swagger-Codegen Github project ?

Note that the PackagePublishRequestInfo PackagePublishRequestInfoAndLel.PackagePublishRequestInfo member property is correctly exposed in the client, only the Byte[] PackagePublishRequestInfoAndLel.LelFile member property is missing in the DataContract class.

Thank you for any help.

Here are some code extracts:

The LelController (ApiController) class exposing the public async Task<IHttpActionResult> PublishPackageAsync() method: (for info)

/// <summary>
/// The lel ApiController handling lel file publication.
/// </summary>
[System.Web.Http.RoutePrefix("api/Lels")]
[GenerateFactory(typeof(ILelControllerFactory))]
public class LelController : ApiController,
                             ILelController
{
    #region Fields

    private readonly ILelRepository lelRepository; // Repository to access the Datasets in the RED Database

    #endregion

    #region Constructors and Destructors

    /// <summary>
    /// Initializes a new instance of the <see cref="LelController"/> class.
    /// </summary>
    /// <param name="lelRepository">
    /// The lel repository.
    /// </param>
    public LelController(ILelRepository lelRepository)
    {
        this.lelRepository = lelRepository;
    }

    #endregion

    #region Public Methods and Operators

    /// <summary>
    /// Publishes a new firmware package.
    /// </summary>
    /// <param name="packagePublishRequestInfoAndLel">
    /// The package publish info and the lel file content.
    /// </param>
    /// <returns>
    /// The returned IHttpActionResult
    /// </returns>
    [System.Web.Http.Route("")]
    [SwaggerResponse(HttpStatusCode.Created, "Package succesfully published.")]
    [SwaggerResponse(HttpStatusCode.NotFound, "Unable to publish posted package data. (Detailed error message available in the response body).")]
    [SwaggerResponse(HttpStatusCode.InternalServerError, "Internal server error. Package not published. An HttpException is returned with the original inner exception thrown. (Detailed error message available in the returned exception).", typeof(HttpException))]
    public async Task<IHttpActionResult> PublishPackageAsync(PackagePublishRequestInfoAndLel packagePublishRequestInfoAndLel)
    {
        // Try to publish the package:
        await this.lelRepository.PublishPackageAsync(packagePublishRequestInfoAndLel);
        return this.Content(HttpStatusCode.Created, "Package successfully published.");
    }

    #endregion
}

The PackagePublishRequestInfoAndLel dto class including a byte[] LelFile property:

public class PackagePublishRequestInfoAndLel : IPackagePublishRequestInfoAndLel
{
    #region Constructors and Destructors

    /// <summary>
    /// Initializes a new instance of the <see cref="PackagePublishRequestInfoAndLel"/> class.
    /// </summary>
    public PackagePublishRequestInfoAndLel()
    {
    }

    /// <summary>
    /// Initializes a new instance of the <see cref="PackagePublishRequestInfoAndLel"/> class.
    /// </summary>
    /// <param name="packagePublishRequestInfo">
    /// The package Publish Request Info.
    /// </param>
    /// <param name="lelFile">
    /// The lel file.
    /// </param>
    public PackagePublishRequestInfoAndLel(PackagePublishRequestInfo packagePublishRequestInfo,
                                           byte[] lelFile)
    {
        this.LelFile = lelFile;
        this.PackagePublishRequestInfo = packagePublishRequestInfo;
    }

    #endregion

    #region Public Properties

    /// <summary>
    /// Gets or sets the lel file
    /// </summary>
    [Required(AllowEmptyStrings = false, ErrorMessage = ValidationConstants.LelFileIsRequired)]
    public byte[] LelFile { get; set; } // The LelFile property missing in the Swagger-Codegen generated client DataContract.

    /// <summary>
    /// Gets or sets the package publish request info
    /// </summary>
    public PackagePublishRequestInfo PackagePublishRequestInfo { get; set; }

    #endregion
}

The PackagePublishRequestInfoAndLel definition in the Swagger JSon: (Correctly including the LelFile property of type "Byte[]" and formatted as a "string")

"PackagePublishRequestInfoAndLel": {
  "required": [
    "LelFile"
  ],
  "type": "object",
  "properties": {
    "LelFile": {
      "format": "string",
      "type": "byte[]"
    },
    "PackagePublishRequestInfo": {
      "$ref": "#/definitions/PackagePublishRequestInfo"
    }
  }
},
"PackagePublishRequestInfo": {
  "required": [
    "UserIdent"
  ],
  "type": "object",
  "properties": {
    "Override": {
      "type": "boolean"
    },
    "BootManagerVersion": {
      "type": "string"
    },
    "BootloaderVersion": {
      "type": "string"
    },
    "EcuIdent": {
      "type": "string"
    },
    "HardwareVersion": {
      "format": "int32",
      "type": "integer"
    },
    "LelFileName": {
      "pattern": "^[0-9]{8}_[0-9]{3}\\.lel$",
      "type": "string"
    },
    "SoftwareVersion": {
      "type": "string"
    },
    "SpfVersion": {
      "type": "string"
    },
    "Status": {
      "type": "string"
    },
    "UserIdent": {
      "format": "int32",
      "type": "integer"
    },
    "DatasetIdent": {
      "type": "string"
    },
    "DatasetRevision": {
      "format": "int32",
      "type": "integer"
    }
  }
},

And finally, the incomplete Swagger-Codegen generated client DataContract:

namespace IO.Swagger.Model
{
  [DataContract]
  public class PackagePublishRequestInfoAndLel : IEquatable<PackagePublishRequestInfoAndLel>
  {
    [DataMember(EmitDefaultValue = false, Name = "PackagePublishRequestInfo")]
    public PackagePublishRequestInfo PackagePublishRequestInfo { get; set; }

    // Here, missing public Byte[] LelFile DataMember !!!


    public override string ToString()
    {
      StringBuilder stringBuilder = new StringBuilder();
      stringBuilder.Append("class PackagePublishRequestInfoAndLel {\n");
      stringBuilder.Append("  PackagePublishRequestInfo: ").Append((object) this.PackagePublishRequestInfo).Append("\n");
      stringBuilder.Append("}\n");
      return ((object) stringBuilder).ToString();
    }

    public string ToJson()
    {
      return JsonConvert.SerializeObject((object) this, Formatting.Indented);
    }

    public override bool Equals(object obj)
    {
      return this.Equals(obj as PackagePublishRequestInfoAndLel);
    }

    public bool Equals(PackagePublishRequestInfoAndLel other)
    {
      if (other == null)
        return false;
      if (this.PackagePublishRequestInfo == other.PackagePublishRequestInfo)
        return true;
      if (this.PackagePublishRequestInfo != null)
        return this.PackagePublishRequestInfo.Equals(other.PackagePublishRequestInfo);
      else
        return false;
    }

    public override int GetHashCode()
    {
      int num = 41;
      if (this.PackagePublishRequestInfo != null)
        num = num * 57 + this.PackagePublishRequestInfo.GetHashCode();
      return num;
    }
  }
}

Addendum:

I guess the problem might be in the Swashbuckle/Swagger mapping of the byte[] type. So here is my SwaggerConfig class code: (the mapping of the byte[] type might be wrong...)

public class SwaggerConfig
{
    #region Public Methods and Operators

    /// <summary>
    /// Register the configuration for Swashbuckle (Swagger .Net)
    /// </summary>
    /// <param name="config">
    ///     The global configuration
    /// </param>
    public static void Register(HttpConfiguration config)
    {
        config.EnableSwagger(c =>
                                 {
                                     c.SingleApiVersion("v1", "RedFull.Api")
                                      .Description(@"An API for accessing the Firmware Database services."
                                                   + "(lel file publishing and firmware package retrieval)"
                                                   + "<br /><br />Service events viewer is available on : <a href='/elmah.axd'>ELMAH</a> page")
                                      .TermsOfService("Terms of service: Reserved for internal usage.")
                                      .Contact(cc => cc
                                                         .Name("Firmware Services"
                                                         .Url("https://xxxxx.com/yyyy/Home.aspx")
                                                         .Email("xxx.yyy@gmail.com"))
                                      .License(lc => lc
                                                         .Name("Usage License")
                                                         .Url("http://xxxxx.com/license"));

                                     c.MapType<byte[]>(() => new Schema
                                                                 {
                                                                     type = "byte[]",
                                                                     format = "string"
                                                                 });
...

I also tried to declare the mapping this way:

                                 c.MapType<byte[]>(() => new Schema
                                 {
                                     type = "array",
                                     format = "string",
                                     items = new Schema()
                                                 {
                                                     type = "byte",
                                                     format = "int32"
                                                 }
                                 });

But this code leaded to an exception when lauching the swagger-codegen generator:

Exception in thread "main" java.lang.RuntimeException: Could not generate model
'PackagePublishRequestInfoAndLel'
        at io.swagger.codegen.DefaultGenerator.generate(DefaultGenerator.java:21
5)
        at io.swagger.codegen.cmd.Generate.run(Generate.java:188)
        at io.swagger.codegen.SwaggerCodegen.main(SwaggerCodegen.java:35)
Caused by: java.lang.NullPointerException
        at io.swagger.codegen.languages.CSharpClientCodegen.getSwaggerType(CShar
pClientCodegen.java:246)
        at io.swagger.codegen.DefaultCodegen.getTypeDeclaration(DefaultCodegen.j
ava:714)
        at io.swagger.codegen.languages.CSharpClientCodegen.getTypeDeclaration(C
SharpClientCodegen.java:239)
        at io.swagger.codegen.languages.CSharpClientCodegen.getTypeDeclaration(C
SharpClientCodegen.java:232)
        at io.swagger.codegen.DefaultCodegen.fromProperty(DefaultCodegen.java:10
32)
        at io.swagger.codegen.DefaultCodegen.addVars(DefaultCodegen.java:1868)
        at io.swagger.codegen.DefaultCodegen.fromModel(DefaultCodegen.java:845)
        at io.swagger.codegen.DefaultGenerator.processModels(DefaultGenerator.ja
va:695)
        at io.swagger.codegen.DefaultGenerator.generate(DefaultGenerator.java:18
9)
        ... 2 more
Bug Raptor
  • 261
  • 6
  • 15

1 Answers1

4

binary format (mapped to byte[] in C# API client) is supported in the latest master of Swagger-Codegen and it will be included in the upcoming stable release 2.1.6.

Please pull the latest master for the time being to get the support of byte[] in the C# API client.

William Cheng
  • 10,137
  • 5
  • 54
  • 79