NSwag Studio
A quick way to add API connectivity to an application is by using NSwagStudio to automatically generate the basic scaffolding.
This is a Windows application that can generates API client code from an OpenAPI specification such as those generated by Swagger.
Creating the Client Code
Start the API as NSwagStudio will need to read the Swagger information. Then, (assuming the API is running on the port 7256) we need to do the following:
- With the API running, paste the URL (
https://localhost:7256/swagger/v1/swagger.json) into the Specification URL field and click the Create local Copy button.
Configure the generated output
Below are all items that should be checked, and a couple that are checked by default but should be un-cheked. Other values that are not checkboxes are listed with the required setting:
- In the "Output" section, select "CSharp Client" as the output type.
- Configure any additional settings as needed, such as namespace and class name, for this example
JobSearch.MVC.Services.Baseand:- Generate exception classes
- Generate Client classes
- Operation Generation Mode = Multiple Operation IDs (comma separated)
- Class Name = {controller}client
- Client class access modifier = public
- Use base URL for the request = unticked
- Inject HttpClient via constructor (lifecycle managed by the caller)
- Generate interfaces for Client classes
- Http Client Type = System.Net.Http.HttpClient
- DateTime format for method parameters = s
- Date format for method parameters = yyyy-MM-dd
- Wrap DTO exceptions in a SwaggerException instance
- Generic Array Type (Parameter Types and Response Types) = System.Collections.Generic.IEnumerable
- Generic Dictionary Type (Parameter Types and Response Types) = System.Collections.Generic.IDictionary
- Generate DTO Types (e.g. Request and Response Classes)
- DTO class/emun modifier = public
- Generate default values for properties
- Generate data annotation attributes
- Inline named tuples
- Class Style = poco
- JSON Library = System.TextJson
- JSON Library Version = 10.0 (for .Net 10)
- Required properties must be defined in JSON
- JSON Polymorphic Serialisation Style = System.TextJson
- Required properties must be defined in JSON
- Read Accessor of properties (set | init) = set
- Primitive Types
- Any Type = object
- Date Type = System.DateTimeOffset
- Date Time Type = System.DateTimeOffset
- Time Type = System.TimeSpan
- Time Span Type = System.TimeSpan
- Generic Array Type = System.Collections.Generic.ICollection
- Generic Array Instance Type (empty = ArrayType) = System.Collections.ObjectModel.Collection
- Generic Dictionary Type = System.Collections.Generic.IDictionary
- Generic Dictionary Instance Type (empty = DictionaryType) = System.Collections.Generic.Dictionary
- Generic Array Base Type = System.Collections.ObjectModel.Collection
- Generic Dictionary Base Type = System.Collections.Generic.Dictionary
- New Line Behaviour = Auto
- Set
Output file path (empty = no file output)(at the bottom of the tab) to a sub folder of your project calledServices\Basewith the nameServiceClient.cs, e.g.[Path]\JobSearch.MVC\Services\Base\ServiceClient.cs.1. - Optionally save this configuration to the project root (or a resources folder)
- Optional: Click "Generate Outputs" to generate the client code. Inspect this if required
- Click the "Generate Files" button to create the file.
The generated API wrapper client file should now appear in the solution explorer and is ready to add to the project. We can now add a few extensions:
Extend the output
Here we can now add a new file IClient to hold a partial interface to extend the one that has just been generated.
Add this to the Services\Base folder alongside the ServiceClient.cs class. This will hold our HttpClient instance
public partial interface IClient
{
public HttpClient HttpClient { get; }
}
And alongside this add a new file Client to hold a partial class to extend the generated ServiceClient class:
public partial class Client
{
public HttpClient HttpClient
{
get
{
return _httpClient;
}
}
}
This will allow us to inject an HttpClient instance when we register the client in the DI container. We can add the code Program.cs to register these services now:
Firstly add a scoped instance of HttpClient to allow this client code to locate the backend API. The second registration is IClient to Client, so anywhere I need to access the API we inject IClient. We previously modified Client to contain a reference to HttpClient:
// Add services to the container.
builder.Services.AddScoped(sp => new HttpClient
{
BaseAddress = new Uri(builder.Configuration["ApiBaseAddress"]
?? throw new InvalidOperationException("ApiBaseAddress configuration is missing."))
});
builder.Services.AddScoped<IClient, Client>();
We can add the base address for the API in the appsettings.Development.json file:
{
...
"ApiBaseAddress": "https://localhost:7256/",
"AllowedHosts": "*"
}
Thoughts
NSwagStudio is a great way of getting something up and running quickly, including creation of DTOs, etc. but will need to be re-run every time the API is modified.
Also, as with any tool, you will need to verify the generated code is suitable and correct.
It feels to me like this should be used when crating quick PoC projects or personal tools, but for production level code possibly only used initially when creating the codebase, then refactored into properly structured SOLID classes according to a better project structure.