ASP.NET Core – API versioning by convention

1. Introduction

If you were looking for information about API versioning support for ASP.NET Core you’ve probably come across Microsoft.AspNetCore.Mvc.Versioning library. The library itself allows you to set up versioning in a couple of different ways, for instance, via attributes or via manual convention setup. All of this options are really nice but unfortunately, they have one significant drawback, namely, you have to set them up manually. As I tend to forget about this kind of things I wanted to automate that process as much as possible. Thankfully ASP.NET Core has a very nice feature called ApplicationModelConventions which allows you to add some metadata(like routing information, API versioning ) to your controller, actions etc.

2. Convention

I’ve decided to implement versioning by routing which means the API will be accessible via this template

The template itself doesn’t give you much, as you also have to add information to the controllers which version of API they support. In my case, I decided to go with a version by namespace convention, which means that supported version will be deduced from namespace in which given controller resides. So, in fact, there will be two conventions, one for applying routing and a second one for applying versioning

3. Creating conventions.

In order to write an ASP.NET Core convention, we have to implement IApplicationModelConvention interface. This interface has a single method Apply which takes ApplicationModel class as an argument. This class gives us access to all of our controllers, actions and other parts of the application. So if we want to apply a routing with versioning for all of the controllers, we can do it in following way

As you can see we iterate through all of the Selectors and then apply new route model to them. If selector already had a route attribute applied we combine two attributes together. Once our convention is applied our actions will be accessible with following routing prefix

or via

Having our routing ready now it is time to add versioning information to our controllers. Once again it will be done via application model convention. The version of the controller will be deduced from the namespace given controller is located in.

As you can see I iterate through all of the controller models of our application, then check the version of controller based on its namespace and finally with

I am able to inform the framework which version of API given controller supports.

4. Adding convention to application

Having all of our conventions prepared now we can enable versioning support

And of course, we have to add newly created conventions to list of application conventions

Note that I removed ApiVersionConvention and ImplicitControllerVersionConvention with simple extension method Remove<T>

to make sure that only my convention is responsible for API versioning.

Source code for this post can be found here

ASP.NET Core – API versioning by convention

ASP.NET Core – default API version with url path versioning

1. Introduction.

When you start versioning your API sometimes you want to have access to your endpoints without specifying version explicitly. Thanks to Microsoft.AspNetCore.Mvc.Versioning library this can be easily achieved with proper setup of configuration action. However, it turns out that in order to enable default API version for url path versioning, there are a couple additional steps to do.

2. Default API version without url path versioning

Let’s start with the initial setup of API versioning which will work for every type of versioning apart from url path versioning. All you have to do is to assign an ApiVersionSelector and set the AssumeDefaultVersionWhenUnspecified property to true.

Now when the user will try to access the endpoint without specifying version explicitly the ApiVersionSelector will select proper version – in this case highest available version.

3. Default Api version with URL path versioning

Running the same configuration against controllers which are versioned via url path (not query string)

will result with 404 status code, as routing is not able to match the url.
Fortunately, unlike the ASP.NET Web API, ASP.NET Core allows us to have multiple route attributes applied to given controller, so in order to fix the issue we just have to add

attribute to versioned controllers. From now on we can access our API without specifying version as well as with version specified.

4. Adding default route with convention

If you don’t want to specify default route manually for every controller, you can do it via application model convention. The interesting thing about it is the fact that apart from changing existing values of application model we can also add new items to it. This means that we can add additional SelectorModel with our default route to Selectors’ collection

Now we can get rid of [Route(“[controller]”)] attribute from our versioned controllers and just rely on convention which can be added as follows

Source code for this post can be found here

ASP.NET Core – default API version with url path versioning

VS Code – forcing partial IntelliSense support for Cake scripts

1. Introduction

I’ve been using Cake for quite some time now, and I really like this tool, however the more complex my build scripts are, the more painful lack of IntelliSense is. Inspired a bit by this post, I decided to see what it takes to enable at least partial IntelliSense for Cake scripts in Visual Studio Code.

2. Investigation

The proper way of providing the code completion for Cake scripts would probably be a plugin to Omnisharp-Roslyn, as Cake script is basically a valid c# snippet. Unfortunately, at this moment Omnisharp-Roslyn doesn’t have plugin infrastructure ready, that is why I decided to go with a bit different path. As you might or might not be aware, VS Code already supports csx files, so if you add an empty project.json file (by empty I mean file with empty JSON object) to your build directory and change extension of your scripts to csx, you will immediately get a C# syntax highlighting and some IntelliSense support. Sadly this will not provide code completion for Cake method aliases. The reason why it fails on that is the fact that the Cake alias is ICakeContext extension method

but you use it as it was written as

The Cake engine generates additional alias overloads during script compilation, and as these overloads exist only on runtime, VS Code just can’t “see” them.

3. My approach

Having in mind the way Cake works I decided to write an application which would be able to take any Cake or Cake add-in and produce a library containing proper alias overloads. For instance, if original Cake method looks as follows

the application will rewrite it into

The algorithm looks more or less like that

  • Retrieve Cake or Cake add-in via NuGet
  • Scan an assembly and find all classes containing alias methods
  • Use CSharpCodeGenerationService to generate metadata for Cake alias methods
  • Parse generated code with Roslyn and produce SyntaxTree
  • Append Metadata suffix to classes containing alias method
  • Remove ICakeContext parameter from alias method
  • Generate dummy body for methods which require that (methods which have return type or which have out parameters)
  • Update xml documentation
  • Compile generated code and produce dll

There is no point of doing more detailed description in here so if you want to take a closer look here is source code.

4. Generating metadata libraries

Before we start “hacking” VS Code to have IntelliSense, we have to prepare metadata libraries which will contain all necessary Cake alias overloads. In order to do that grab the application from NuGet and generate Cake.Common and Cake.Core metadata libraries. The simplest way of doing it is to run these commands

As a result, the application will produce following files:

  • Cake.CommonMetadata.dll
  • Cake.CommonMetadata.xml
  • Cake.CoreMetadata.dll
  • Cake.CoreMetadata.xml

5. Enabling IntelliSense in VS Code

Having our metadata libraries prepared now we can adjust our build scripts to have code completion in VS Code. Here are the steps:

  • Add project.json file with empty JSON object into your build directory.
  • Change extension of all your build scripts to csx.
  • Copy metadata libraries into your Build directory.
  • Create imports.csx file. This is the file which contains all original namespace imports. It may look as follows
  • Create metadataimports.csx file. This is the file which contains metadata namespaces imports and loads Cake and metadata references.Each original Cake alias class has corresponding metadata class with Metadata suffix, for instance
    Cake.Common.ArgumentAliases -> Cake.Common.ArgumentAliasesMetadata
    Cake.Common.EnvironmentAliases -> Cake.Common.EnvironmentAliasesMetadata
  • Load imports.csx to your build.csx file via
  • Run VS Code install ms-vscode.csharp 1.7.0, open Build directory and write your build script with IntelliSense support
  • Before running the script remember to comment outfrom imports.csx file
  • Run the build

I do realize this is quite convoluted explanation so in case of any troubles take a look at my build

6. Known issues

  • Cake.Intellisense can only generate metadata libraries for a standard .NET frameworks, it will fail if you try to create metadata targeting .NETStandard or .NET Core framework
  • Due to some breaking changes in Omnisharp-Roslyn scripting support, IntelliSense will only work with Omnisharp 1.7.0

7. Summary

This approach is just a temporary solution. As you can see, it requires significant amount of work to have a code completion in VS Code. I believe that once Omnisharp-Roslyn has proper plugin support it should be possible to write some kind of custom IntelliSense provider for Cake scripts. There are already people who forked Omnisharp-Roslyn and play around with that, so we just have to wait for something better than this solution.

VS Code – forcing partial IntelliSense support for Cake scripts

Downgrading Visual Studio Code extension

1. Introduction

For time to time when you update Visual Studio Code’s extension you realize that there were some breaking changes you don’t like or the extension has a bug which prevents you from using it. Usually, in this kind of situations, you would like to just go back to the version you were using previously rather than stop using the extension at all. Unfortunately, VSCode doesn’t give us an option to install a specific version of the extension for now. Luckily there is an easy way of doing that manually.

2. Installation

Let’s assume that I would like to downgrade C# plugin from newest version (1.8.1 at the moment) to 1.7.0. First of all, we have to uninstall current extension. As there as some issues of doing that via command line, just do it from VSCode by clicking on uninstall button in extension screen.
In the next step we have to download proper extension’s version using vsassets api. The url pattern looks as follows

In my case, the variables looks as follow

  • ${publisher} – ms-vscode
  • ${extension_name} – csharp
  • ${version} – 1.7.0

and entire url can be rewritten as

Having the link prepared we can paste it into browser address bar and download the extension. Once the file is downloaded, run VSCode, hit CTRL+SHIFT+P, type vsix in command line and choose

Select the file you’ve just downloaded and restart editor after installation. From now on you can use older version of your favorite extension.

Downgrading Visual Studio Code extension

Asp.NET Core – populating IOptions<T> from external data source

1. Introduction

In ASP.NET Core web.config is no longer a proper place for storing application settings. New framework introduces the concept of a json based configuration and the default file which stores the settings now is appsettings.json. Here is a quick tutorial how to use new features.

2. Reading configuration

Let’s assume that our appsettings.json file looks as follows.

Thanks to ConfigurationBuilder we can parse this config and later on materialize sections or entire file into strongly typed configuration classes. Let’s say we want to parse AvailabilitySearchOptions node to following class

We can achieve that with following steps. First of all, we need to read entire configuration

And in the next step we have to register IOptions<AvailabilitySearchOptions> in the container using services.Configure<TOptions>(IConfiguration section) method

Note Configuration.GetSection(“AvailabilitySearchOptions”) passed as argument to services.Configure method.
From now on we can access AvailabilitySearchOptions settings via IOptions<AvailabilitySearchOptions> interface, which you can easily inject into your classes.

3. Populating IOptions<T> from external data source

From time to time, reading configuration just from JSON file might not be enough and for instance you would like to add additional configuration read from some external data source. Fortunately you don’t have to resign from the IOptions<T> class as it is possible to read additional data for literally any other source thanks to IConfigureOptions<T> class. All we have to do is to create a setup class which implements IConfigureOptions<T> interface

And then registering this class in our container

From now on, when value of IOptions<AvailabilitySearchOptions> is accessed for very first time, Configure method from AvailabilitySearchOptionsSetupService will be called and you will be able to set additional values for your settings. Note that values from appsettings.json will already be there.
In addition, it is possible to have multiple implementations of IConfigureOptions<T> so if you want your setup to be split into multiple classes you are good to go.
Source code for this post can be found here

Asp.NET Core – populating IOptions<T> from external data source