Skip to main content

NSwag - Auto generating code

The logic in GlobalDcc.Api.Client is largely created by NSwag. From the controller in GlobalDcc.Api.Server NSwag generates a swagger.json file and from this file it creates Autogenerated\NSwagGenerated.cs in GlobalDcc.Api.Client. Which contains (most) of the logic for calling Global DCC's API.

NSwag is also used to set up OpenAPI (formerly known as Swagger) for GlobalDcc.Api.Server (using the NSwag.AspNetCore NuGet package). But this page is concerned with the auto generation aspect of NSwag.

The build process

NSwag runs as a post build event for GlobalDcc.Api.Server. It only runs when building in debug, because NSwag assumes the output path is bin\Debug (this might no longer be the case, we have now specified output path for GlobalDcc.Api.Server, and now it should also work in Release in theory).

To use NSwag for auto generating code, we use the NuGet package NSwag.MSBuild. Since we only run NSwag for Debug, this package is only included for Debug.

The post build event looks as follows:

<Exec EnvironmentVariables="ASPNETCORE_ENVIRONMENT=Development" Command="$(NSwagExe_Net60) aspnetcore2openapi /project:$(ProjectPath) /noBuild:true /output:swagger.json" />
<Exec Command="$(NSwagExe_Net60) openapi2csclient /input:swagger.json /namespace:GlobalDcc.Api.Client /output:../GlobalDcc.Api.Client/AutoGenerated/NSwagGenerated.cs /ClientBaseClass:&quot;Client, IClient&quot; /UseHttpClientCreationMethod:true /InjectHttpClient:false /GenerateBaseUrlProperty:false /ClientClassAccessModifier:&quot;public abstract&quot; /ClassName:{controller}BaseClient /GenerateSyncMethods:true /GenerateDtoTypes:false /AdditionalNamespaceUsages:DccModel.Message /HttpClientType:GlobalDcc.Api.Client.HttpClientWrapper /DisposeHttpClient:false" />

The first Exec creates swagger.json. To do this it first sets an environment variable, because NSwag will only generate code if in Development. It then calls the NSwag dll for .NET 7.0 with the following arguments:

ArgumentWhat does it do?
aspnetcore2openapiTells NSwag to create an Open API file from an ASP.NET core app.
/project:$(ProjectPath)Tells NSwag that it is the current project (GlobalDcc.Api.Server) that should be converted.
/noBuild:trueDo not build. I think this often gets ignored.
/output:swagger.jsonSets the output file to swagger.json.

The second Exec tells NSwag to create an auto generated client from the just created Open API file.

ArgumentWhat does it do?
openapi2csclientTells NSwag that the job is to generate a C# client from an Open API file.
/input:swagger.jsonThe input file is swagger.json.
/namespace:GlobalDcc.Api.ClientThe code gets generated in the namespace GlobalDcc.Api.Client.
/output:../GlobalDcc.Api.Client/AutoGenerated/NSwagGenerated.csThe auto generated code is placed in the file ../GlobalDcc.Api.Client/AutoGenerated/NSwagGenerated.cs. The path is relative to GlobalDcc.Api.Server.csproj.
/ClientBaseClass:\&quot;Client, IClient\&quot;Adds : Client, IClient to the generated clients class, so it extends Client and implements IClient.
/UseHttpClientCreationMethod:trueUse the CreateHttpClientAsync method to get the client that sends the actual HTTP requests. This method is not auto generated.
/InjectHttpClient:falseTells NSwag not to inject an HttpClient into the auto generated client.
/GenerateBaseUrlProperty:falseTells NSwag not to generate the BaseUrl property (it is instead created in Client).
/ClientClassAccessModifier:&quot;public abstract\&quot;Makes the auto generated client public abstract. It is set to abstract because we do not want the consumer to use the constructor created by NSwag, so instead we create an extension with a constructor we like.
/ClassName:{controller}BaseClientThe name of the auto generated client should be the name of the controller from GlobalDcc.Api.Server minus "Controller" plus "BaseClient". E.g. Version0Controller becomes Version0BaseClient.
/GenerateSyncMethods:trueAuto generate synchronous methods, instead of only generating async methods.
/GenerateDtoTypes:falseDo not generate Data Transfer Objects. This is because we use the objects in DccModel.
/AdditionalNamespaceUsages:DccModel.MessageAdds a using DccModel.Message; line to the auto generated client.
/HttpClientType:GlobalDcc.Api.Client.HttpClientWrapperTells NSwag to use GlobalDcc.Api.Client.HttpClientWrapper as the type for the client sending the HTTP requests.
/DisposeHttpClient:falseThe auto generated client should not dispose the HttpClientWrapper (because we reuse it).

What is not auto generated

Apart from the code generated by NSwag, there are the following classes in GlobalDcc.Api.Client:

  • Client: A base class for implementing some things we want to use in the auto generated client.
  • IClient: An interface for the methods we want the auto generated client and any future auto generated clients to contain. I.e. if we make a Version1Controller in GlobalDcc.Api.Server, the auto generated client for this controller should also implement these methods. Please add methods to this, if adding a new endpoint to the controller(s) in GlobalDcc.Api.Server.
  • HttpClientWrapper: Wrapper for HttpClient to make sure we handle DNS changes.
  • Version0Client: Extension of the auto generated client Version0BaseClient which has the constructor we want.
  • ProblemDetails: This is actually originally auto generated and then copied. It is the only DTO we wanted NSwag to generate.

References