Displaying Azure DevOps build number in Swagger UI for ASP.NET Core
Image from Pexels

Displaying Azure DevOps build number in Swagger UI for ASP.NET Core

How to add and show Azure DevOps build number in ASP.NET Core project and Swagger UI

Swagger is a great way to document you REST API endpoints and reduce the need for communication, item spent and the cost for supporting the consumers of you APIs. Apart from providing the info about the endpoints, models, validation it can also display the data of the product. This data can be either stored outside of your application, but most of the time good old AppInfo is just good enough for storing the information about product name, product description or product version.

Note

Unlike in .NET Freamwork where you had AppInfo.cs class right out of the box once you create your project, in .NET Core you do not get AppInfo.cs generated in the project. Instead you can set Assembly attributes in your project *.csproj file and they will be translated into AppInfo.cs class and compiled into an Assembly during you project compilation time.

All the assembly attribute values you set in your project *.csproj file will be generated in the AppInfo class on the compile time and you can access them through reflection by accessing the Assembly class instance.

Before we start integrating with Azure DevOps Build pipeline, let's make a small test for fetching Assembly information. For start let's add some Assembly related information to our project file.

<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>netcoreapp2.2</TargetFramework>
<DocumentationFile>bin\$(Configuration)\$(TargetFramework)\$(MSBuildThisFileName).xml</DocumentationFile>
    <AspNetCoreHostingModel>OutOfProcess</AspNetCoreHostingModel>
    <Product>Sample REST Service</Product>
    <Description>Sample ASP.NET Core WebApi REST Service</Description>
  </PropertyGroup>
  
</Project>
    

Since we have stored our data let's try to retrieve it first in the Startup class constructor first before we dive into the Swagger and add these things to its configuration. I simply added debug output lines in the Startup constructor and the output I got matched the values we declared in the .csproj file

Assemblyinfo Debug

We figured out how to add and retrieve values from the Assembly, now let's display the in the Swagger auto-generated API documentation. If you are not that familiar with Swagger and you are not sure how to do the setup, I suggest you to check few articles I wrote previously for using Swagger in ASP.NET Core DTO comments from external assembly in Swagger documentation in ASP.NET Core and Setting up Swagger to support versioned API endpoints in ASP.NET Core

            services.AddSwaggerGen(
                options =>
                {
                    // Resolve the temprary IApiVersionDescriptionProvider service
                    var provider = services.BuildServiceProvider().GetRequiredService<IApiVersionDescriptionProvider>();
                    // Add a swagger document for each discovered API version
                    foreach (var description in provider.ApiVersionDescriptions)
                    {

                        options.SwaggerDoc(description.GroupName, new Swashbuckle.AspNetCore.Swagger.Info()
                        {
                            Title = $"{this.GetType().Assembly.GetCustomAttribute<AssemblyProductAttribute>().Product} {description.ApiVersion}",
                            Version = description.ApiVersion.ToString(),
                            Description = this.GetType().Assembly.GetCustomAttribute<AssemblyDescriptionAttribute>().Description
                        });
                    }
                });
    
Note

This sample code snippet considers that your API supports versioning. To read more about API versioning and Swagger, consider visiting this page http://bit.ly/2OnbQTF

Let's run our ASP.NET project and see what is the output in Swagger UI.

Swagger Assembyinfo

You can see that we have our Assembly info display as the part of Swagger UI.

Since we want to incorporate our Azure DevOps Build number into our Swagger, from the previous example we saw that Assembly info is the great place to store this value as it will be part of the built artifact itself and we do not need to store it anywhere externally. It is related to the build and that is where it should be stored as well.

We only used AssemblyProductAttribute and AssemblyDescriptioAttribute, we can try to use pretty much any other Assembly info attribute for keeping our Build number and as this is sort of a version of the build artifact, it is somehow logical to use attribute which is related to Assembly version. What first come to mind is AssemblyVersionAttribute, but beware, not all the attributes have loose value format. To demonstrate that, let's try to set AssemblyVersionAttribute in the .csproj file and try to run the project. To have it close as possible to the real scenario, I used one of my Azure Build numbers 20190412.8

Devops Build

Our project file will now look something like this

<Project Sdk="Microsoft.NET.Sdk.Web">

  <PropertyGroup>
    <TargetFramework>netcoreapp2.2</TargetFramework>
    <DocumentationFile>bin\$(Configuration)\$(TargetFramework)\$(MSBuildThisFileName).xml</DocumentationFile>
    <AspNetCoreHostingModel>OutOfProcess</AspNetCoreHostingModel>
    <Product>Sample REST Service</Product>
    <Description>Sample ASP.NET Core WebApi REST Service</Description>
    <AssemblyVersion>20190412.8</AssemblyVersion>
  </PropertyGroup>
</Project>
    

Right upon the debug start, you will get the compilation error. If we check the source of an error, you will see that it comes from auto-generated AppInfo class which was assembled from our project .csproj file.

 Version Build Err

As the compilation error shows, AssemblyVersionAttribute value, although it is a string, it has to follow specific format. You can find more details about assembly version format from official Microsoft documentation page related to AssemblyVersionAttribute Class. To cut the story short, we simply cannot use AssemblyVersionAttribute, so we need to pick some other assembly info attribute.

Assembly version is fortunately not the only version attribute we have to choose for storing free-form version values. One of them is AssemblyInformationalVersionAttribute which unlike AssemblyVersionAttribute can use free form text which makes it perfect for storing our build artifact version (build number).

<Project Sdk="Microsoft.NET.Sdk.Web">

  <PropertyGroup>
    <TargetFramework>netcoreapp2.2</TargetFramework>
    <DocumentationFile>bin\$(Configuration)\$(TargetFramework)\$(MSBuildThisFileName).xml</DocumentationFile>
    <AspNetCoreHostingModel>OutOfProcess</AspNetCoreHostingModel>
    <Product>Sample REST Service</Product>
    <Description>Sample ASP.NET Core WebApi REST Service</Description>
    <InformationalVersion>20190412.8</InformationalVersion>
  </PropertyGroup>

</Project>
    

We do not have the compilation error anymore, so we can now add this value to our Swagger configuration and make the test run to see how our Build number will be displayed in the Swagger UI.

            services.AddSwaggerGen(
                options =>
                {
                    // Resolve the temprary IApiVersionDescriptionProvider service
                    var provider = services.BuildServiceProvider().GetRequiredService<IApiVersionDescriptionProvider>();
                    // Add a swagger document for each discovered API version
                    foreach (var description in provider.ApiVersionDescriptions)
                    {

                        options.SwaggerDoc(description.GroupName, new Swashbuckle.AspNetCore.Swagger.Info()
                        {
                            Title = $"{this.GetType().Assembly.GetCustomAttribute<AssemblyProductAttribute>().Product} {description.ApiVersion}",
                            Version = description.ApiVersion.ToString(),
                            Description = this.GetType().Assembly.GetCustomAttribute<AssemblyDescriptionAttribute>().Description +
                            $"<p><strong>Build: </strong>{this.GetType().Assembly.GetCustomAttribute<AssemblyInformationalVersionAttribute>().InformationalVersion}</p>"
                        });
                    }
                });
    

 Swagger Buildno

We are ready now to jump to Azure DevOps Build pipeline to setup AssemblyInfo update step. Assembly information update task does not come out of the box with Azure DevOps Build pipeline and you have to add it from the Visual Studio Marketplace as an extension to your VisualStudio online account. The extension I used and which works quite well is called Assembly Info, works fine with both .NET Framework, .NET Standard and .NET Core and it is free.

This task needs to be added to the pipeline before any other build task as it will basically make changes to the source before it restores packages and performs the actual code builds.

Azure Pipeline Assembly Info

 Build number is acquired from the build variables with $(Build.BuildNumber) macro and replaced when build pipeline is initiated.

Having your build number in your Swagger documentation, might be quite useful especially when you are facing issues with your latest build/release and you need to roll back to the previous stable build/release. Unfortunately, you cannot incorporate release number into your project since it is using already compiled and prepared deployment package, but still you can use build number to track down the release using it.

References

Disclaimer

Purpose of the code contained in snippets or available for download in this article is solely for learning and demo purposes. Author will not be held responsible for any failure or damages caused due to any other usage.


About the author

DEJAN STOJANOVIC

Dejan is a passionate Software Architect/Developer. He is highly experienced in .NET programming platform including ASP.NET MVC and WebApi. He likes working on new technologies and exciting challenging projects

CONNECT WITH DEJAN  Loginlinkedin Logintwitter Logingoogleplus Logingoogleplus

JavaScript

read more

SQL/T-SQL

read more

Umbraco CMS

read more

PowerShell

read more

Comments for this article