DEV Community

Cover image for Dotnet, Angular, Typescript + NSWAG = <3
Travis Marble
Travis Marble

Posted on

Dotnet, Angular, Typescript + NSWAG = <3

One of my previous co-workers, who I consider to be one of the smartest developers I know (Darrel Brown), created a tool called Typescripter.

Typescripter was probably one of the most magical libraries I know of, so what did it do?

Typescripter would generate typescript files for objects exposed in the dotnet API and it would generate a set of functions for calling API end points.

Typescripter used assembly reflection to generate the typescript code. This worked most of the time, however when the dotnet version of the source code was greater than the library reflection would break. Dotnet core brought other issues with dependencies missing and issues with cross platform development.

I wanted to fix this, in talking with the package owner, he suggested I check out how Swagger worked.

Which brought me to

NSWAG

NSWAG, which is a dotnet implementation of swagger (hence the N), it has two ways of doing API discovery.

  • Assembly Reflection, which it turns out has similar/same issues as typescripter.
  • Function call during startup

That second one, the function call during startup, works beautifully since it always runs with the right dependencies/versions. It is technically meant to be used when someone else consumes your API. In this instance the site is running when the API needs to be discovered.

A suggested workaround from the NSWAG team is to "run" your application post build, generate the API json file and stop the application.

This worked! However, it was a little slow. Here's how I did it:

Update Project File

  <Target Name="PostBuild" AfterTargets="PostBuildEvent">
    <Exec EnvironmentVariables="ASPNETCORE_ENVIRONMENT=Development;NSWAG=Build" Command="$(NSwagExe_Core31) run nswag.json /variables:Configuration=$(Configuration),TargetFramework=$(TargetFrameworkVersion),Runtime=$(Runtime)" />
  </Target>

Needs to be added to your project file (the project hosting your API), more on the NSWAG environment variable later.

Update startup.cs

public void ConfigureServices(IServiceCollection services)
        {
...
                services.AddSwaggerDocument();
...
}

In order for the NSWAG portion to work, you don't need to do everything in your startup.cs. To speed things up, we set an environment variable in the tag (see above) then use that in startup.cs to exit early.

Our startup.cs becomes

public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc().AddJsonOptions(options =>
            {
                options.JsonSerializerOptions.PropertyNameCaseInsensitive = true;
                options.JsonSerializerOptions.PropertyNamingPolicy = null;
            });

            if (!string.IsNullOrWhiteSpace(Environment.GetEnvironmentVariable("NSWAG")))
            {
                services.AddSwaggerDocument();
                return;
            }
...
}

In our instance, this reduced the amount NSWAG added to our build time by approx 1 second.

NSWAG + Typescript

Technically at this point, all you have is a nice .json file that tells you about your API.

With Typescripter, we had always dreamed of doing this, generating an in between .json descriptor and then generating the typescript files separately. This would make generating other code easier.

NSWAG generates typescript files for you, and overall it does a great job and is fairly configurable.

Future

I am still tempted to take the knowledge from my time collaborating on Typescripter and implement a pipeline tool that runs on the client (typescript) build using a templating engine to make customization of typescript output easier. I will keep you posted if it ever happens.

Top comments (0)