Show Swagger documentation on Azure Service Fabric

Another blog post in what seems to be becoming a series of posts on Swagger.

Swashbuckle allows you to include XML comments on your API’s Swagger page. To do this you need to set your Build to output an XML file, which Swashbuckle reads the XML comments from.
Don’t forget to add that XML file to the “Release” build configuration too, otherwise you won’t have XML comments when your application is actually deployed to an environment.

Here’s a handy code snippet for your .NET Core .csproj file:

  <!-- Begin Swagger documentation file-->
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
    <DocumentationFile>bin\Debug\net46\win10-x64\swagger.xml</DocumentationFile>
    <NoWarn>1701;1702;1705;1591</NoWarn>
  </PropertyGroup>

  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
    <DocumentationFile>bin\Debug\net46\win10-x64\swagger.xml</DocumentationFile>
    <NoWarn>1701;1702;1705;1591</NoWarn>
  </PropertyGroup>

  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
    <DocumentationFile>bin\Release\net46\win10-x64\swagger.xml</DocumentationFile>
    <NoWarn>1701;1702;1705;1591</NoWarn>
  </PropertyGroup>

  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
    <DocumentationFile>bin\Release\net46\win10-x64\swagger.xml</DocumentationFile>
    <NoWarn>1701;1702;1705;1591</NoWarn>
  </PropertyGroup>
  <!-- End Swagger documentation file-->

Additionally, if your application is deployed on Azure Service Fabric, you will also need to copy the XML file to your PublishDir, with the following snippet in your .csproj:

  <Target Name="PrepublishScript" BeforeTargets="PrepareForPublish">
    <ItemGroup>
      <DocFile Include="bin\x64\$(Configuration)\$(TargetFramework)\win10-x64\*.xml" />
    </ItemGroup>
    <Copy SourceFiles="@(DocFile)" DestinationFolder="$(PublishDir)" SkipUnchangedFiles="false" />
  </Target>

And of course you need to tell Swashbuckle to use that XML file via the .IncludeXmlComments() method mentioned above.

Advertisement

Fix slow NCrunch build

NCrunch is a great unit test runner and has been part of my developer toolbox for many years.

Recently I was having an issue on a medium-sized project where the NCrunch’s Build step was taking almost 2 minutes to complete. That spinning “B” was taking forever!

NCrunch progress

The tests themselves would run in under one minute.

The problem was we use a custom Autofixture [AutoData] attribute on every test.

Our attribute’s constructor creates a TestServer for running the web tests against.
We then inject the test server into each test, i.e.

[Scenario]
[WebHostAutoData]
public void CreateJob_ShouldCreateSuccessfully(
    WebApiClientFixture apiFixture

As it turns out, NCrunch enumerates all test attributes during Analysis, so you should not have any expensive code in your attribute’s constructor.

In my case, I fixed this by introducing a base class for all of my tests, which creates the TestServer (during test run). I then dropped our custom [AutoData] attribute.

Add an upload button to your swagger page

The swagger adventures continue…

In .NET Core the current recommended way to upload a file in ASP.NET is with an IFormFile.

If you’re using an IFormFile in your ASP.NET Web Api like so:

[HttpPost("upload")]
public IActionResult UploadFile(IFormFile file)
{

N.B. Update December 2018. As of Swashbuckle 4.0, IFormFile is supported out of the box, so the filter below is no longer needed.

If you do this, the Swagger page as rendered by Swashbuckle won’t look correct:

However, if you install version 2.5.0 or later of my Swashbuckle.AspNetCore.Examples NuGet package, then you can add the [AddSwaggerFileUploadButton] attribute to your controller action, like so:

[HttpPost("upload")]
[AddSwaggerFileUploadButton]
public IActionResult UploadFile(IFormFile file)
{

and then enable my filter in your Startup.cs:

services.AddSwaggerGen(c =>
{
    c.OperationFilter<AddFileParamTypesOperationFilter>();

Then you’ll get a nice upload button:

N.B. Update December 2018. As of Swashbuckle 4.0, IFormFile is supported out of the box, so the filter above is no longer needed.

Speed up development in a NuGet package-centric solution

As microservices architectures become more popular, so increases usage of NuGet as a way of sharing code amongst separate services. The last few projects I’ve worked on have typically contained a number of “Core” NuGet packages with shared code and interfaces that are consumed by one or more services in the solution. Our build pipeline will publish these NuGet packages to an in-house NuGet server.

This can cause a lot of developer friction when you’re working in one of the services and you decide you need to change one of the Core projects. Typically you’ll

  1. make the change to Core
  2. commit it
  3. (Perhaps raise a PR and wait for approval)
  4. wait for the build to publish new versions of the package
  5. and finally updated the package in your service.

Probably at least 20 min wait for all that to happen. And then you realise that your change didn’t quite work, so you have to go through the cycle again with another change.

Well, here’s a shortcut to that cycle and it’s pretty darn simple. Note that this only works if you’re using the newer .NET Core style .csproj containing <PackageReference>. Simply

  1. make the change in Core and compile it locally
  2. Copy the resulting dll(s) to your local NuGet packages feed folder. NOT the bin folder of your service, or the packages folder of your service. On my machine the local NuGet packages feed folder is C:\Users\matt\.nuget\packages\.

As soon as the dll is copied, Visual Studio detects the change – you don’t need to tell it to update the NuGet packages or even compile!

Another surprise bonus of this – while debugging you can step into the Core code! You don’t need to mess around copying PDBs around or anything. I don’t know how it works, but Visual Studio seems to somehow know that the DLL you’ve copied into the NuGet folder came from your local machine and thus it knows where the source code for it is.

Obviously once you’re happy that your changes to Core are working correctly, then you can can commit them and consume an updated version of the package in your service as usual.

Anyway, hopefully this will speed up your local development as much as it has mine.

Run a Service Fabric solution locally without deploying to Service Fabric

This is a similar piece to another post of mine from a few years ago Run a Windows Azure cloud service locally without the Azure compute emulator

So you’re working on a Service Fabric application which has an ASP.NET Web api host project. I find the debugging experience painful, for two reasons:

  1. Time to start debugging the project is a minimum of 45 seconds, every time, because the app gets deployed to a local service fabric cluster which takes forever.
  2. You need to remember to run Visual Studio as administrator in order for the above local deployment to succeed.

If either of these things bug you, then here’s a possible solution. Once we’re done you’ll be able to set the Web project in your solution as the StartUp project instead of the Service Fabric application, for much faster debugging, and you’ll no longer need to run VS as admin.

First, change the Program.cs in the Web project:

private static void Main()
{
	if (UseServiceFabric())
	{
		StartServiceFabric();
	}
	else
	{
		StartWebHost();
	}
}

private static bool UseServiceFabric()
{
	var webHostBuilder = new WebHostBuilder();
	var environment = webHostBuilder.GetSetting("environment");

	return environment != "Development";
}

private static void StartWebHost()
{
	var builder = new WebHostBuilder()
		.UseKestrel()
		.UseContentRoot(Directory.GetCurrentDirectory())
		.UseStartup<Startup>();

	var host = builder.Build();
	host.Run();
}

private static void StartServiceFabric()
{
	try
	{
		// The ServiceManifest.XML file defines one or more service type names.
		// Registering a service maps a service type name to a .NET type.
		// When Service Fabric creates an instance of this service type,
		// an instance of the class is created in this host process.

		ServiceRuntime.RegisterServiceAsync("Web1Type",
			context => new WebHost(context)).GetAwaiter().GetResult();

		ServiceEventSource.Current.ServiceTypeRegistered(Process.GetCurrentProcess().Id, typeof(Web1).Name);

		// Prevents this host process from terminating so services keeps running. 
		Thread.Sleep(Timeout.Infinite);
	}
	catch (Exception e)
	{
		ServiceEventSource.Current.ServiceHostInitializationFailed(e.ToString());
		throw;
	}
}

If the ASPNETCORE_ENVIRONMENT setting is Development, then it won’t use Service Fabric at all and will just use a plain ol’ ASP.NET Core WebHostBuilder to start the web host.

You’ll also need to change your Debug target to be the Web project, instead of IISExpress, via the VS Standard toolbar.

And just like that the app startup time has shrunk from around 40 seconds to around 5 seconds. Or from an unbearable 100 seconds for the application the team I just joined is working on.

Add an authorization header to your swagger-ui with Swashbuckle

Edit July 2018: I’ve blogged a better way to do this. Add an authorization header to your swagger-ui with Swashbuckle (revisited).

Out of the box there’s no way to add an Authorization header to your API requests from swagger-ui. Fortunately (if you’re using ASP.NET), Swashbuckle 5.0 is extendable, so it’s very easy to add a new IOperationFilter to do it for us:

public class AddAuthorizationHeaderParameterOperationFilter : IOperationFilter
{
    public void Apply(Operation operation, SchemaRegistry schemaRegistry, ApiDescription apiDescription)
    {
        if (operation.parameters != null)
        {
            operation.parameters.Add(new Parameter
            {
                name = "Authorization",
                @in = "header",
                description = "access token",
                required = false,
                type = "string"
            });
        }
    }
}

Now all you need to do is register it in your EnableSwagger call:

configuration
    .EnableSwagger(c =>
    {
        c.SingleApiVersion("v1", "Commerce Services - Discounts");

        foreach (var commentFile in xmlCommentFiles)
        {
            c.IncludeXmlComments(commentFile);
        }

        c.OperationFilter<ExamplesOperationFilter>();
        c.OperationFilter<AddAuthorizationHeaderParameterOperationFilter>();
    })
    .EnableSwaggerUi(config => config.DocExpansion(DocExpansion.List));

Once that’s done it’ll give you an input field where you can paste your Authorization header. Don’t forget to add the word “bearer” if you’re using a JWT token:

Edit July 2018: I’ve blogged a better way to do this. Add an authorization header to your swagger-ui with Swashbuckle (revisited).

Generating Swagger example requests with Swashbuckle

This is a follow on from my post from last year about Generating example Swagger responses.

Update April 2020: You probably don’t need to do it this way any more. Swashbuckle.AspNetCore supports request examples via XML comments. See my blog post.

Update May 4th 2017: I have created a new NuGet package called Swashbuckle.Examples which contains the functionality I previously described in this blog post. The code lives on GitHub.

I have also created a .NET Standard version of the NuGet package at Swashbuckle.AspNetCore.Filters, which is also on GitHub.

It can also be useful to generate example requests, and in this post I will show you how.

First, install my Swashbuckle.Examples NuGet package, or the .NET Core version Swashbuckle.AspNetCore.Filters

Now decorate your controller methods with the included SwaggerRequestExample attribute:

[Route(RouteTemplates.DeliveryOptionsSearchByAddress)]
[SwaggerRequestExample(typeof(DeliveryOptionsSearchModel), typeof(DeliveryOptionsSearchModelExample))]
[SwaggerResponse(HttpStatusCode.OK, Type = typeof(DeliveryOptionsModel), Description = "Delivery options for the country found and returned successfully")]
[SwaggerResponseExample(tHttpStatusCode.OK, typeof(DeliveryOptionsModelExample))]
[SwaggerResponse(HttpStatusCode.BadRequest, Type = typeof(ErrorsModel), Description = "An invalid or missing input parameter will result in a bad request")]
[SwaggerResponse(HttpStatusCode.InternalServerError, Type = typeof(ErrorsModel), Description = "An unexpected error occurred, should not return sensitive information")]
public async Task<IHttpActionResult> DeliveryOptionsForAddress(DeliveryOptionsSearchModel search)
{

Now implement it, in this case via a DeliveryOptionsSearchModelExample (which should implement IExamplesProvider), which will generate the example data. It should return the type you specified when you specified the [SwaggerRequestExample].

public class DeliveryOptionsSearchModelExample : IExamplesProvider
{
    public object GetExamples()
    {
        return new DeliveryOptionsSearchModel
        {
            Lang = "en-GB",
            Currency = "GBP",
            Address = new AddressModel
            {
                Address1 = "1 Gwalior Road",
                Locality = "London",
                Country = "GB",
                PostalCode = "SW15 1NP"
            },
            Items = new[]
            {
                new ItemModel
                {
                    ItemId = "ABCD",
                    ItemType = ItemType.Product,
                    Price = 20,
                    Quantity = 1,
                    RestrictedCountries = new[] { "US" }
                }
            }
        };
    }

Don’t forget to enable the ExamplesOperationFilter when you enable Swagger, as before:

configuration
    .EnableSwagger(c =>
    {
        c.OperationFilter<ExamplesOperationFilter>();
    })
    .EnableSwaggerUi();

Or if you’re using .NET Core

services.AddSwaggerGen(c =>
   {
        c.SwaggerDoc("v1", new Info { Title = "My API", Version = "v1" });
        c.OperationFilter<ExamplesOperationFilter>();

Now that we’ve done all that, we should see the examples output in our swagger.json file, which you can get to by starting your solution and navigating to /swagger/docs/v1.

Capture

And the best part is, when you’re using swagger-ui (at /swagger/ui/index), now when you click the example request in order to populate the form, instead of getting an autogenerated request like this:

Untitled

You’ll get your desired example, like this:

Capture2

I find that having a valid request on hand is useful for smoke testing your API endpoints are working correctly.

Azure Emulator not working with SQL server alias

I just spent a few hours trying to figure out something that had me stumped.

In my local dev environment I’m building a web api which has a SQL database. The connection string for the database is an alias with a named pipe. If I set the web api as StartUp project in Visual Studio it works fine. (See this post for some tips on how to do that). But when I’d instead start the Azure emulator as the StartUp project it wouldn’t connect to the sql server, with the good ol’:

A network-related or instance-specific error occurred while establishing a connection to SQL Server. The server was not found or was not accessible. Verify that the instance name is correct and that SQL Server is configured to allow remote connections. (provider: SQL Network Interfaces, error: 26 – Error Locating Server/Instance Specified)

Eventually I figured it out. The alias was the problem, because if I changed the connectionstring to .\sqlexpress it worked fine.

Digging deeper, the problem was I had set up the alias on the “SQL Native Client 11.0 Configuration (32bit)” node, but I hadn’t added an alias on the “SQL Native Client 11.0 Configuration” node. So the fix was to create an additional Alias on the “SQL Native Client 11.0 Configuration” node.

sql

So it seems that debugging a web api locally may be a 32 bit process but debugging with the Azure emulator is a 64 bit process. Maybe?

Anyway, hope this helps someone.

Generating Swagger example responses with Swashbuckle

Update April 2020: You probably don’t need to do it this way any more. Swashbuckle.AspNetCore supports request examples via XML comments. See my blog post.

Update May 4th 2017: I have created a new NuGet package called Swashbuckle.Examples which contains the functionality I previously described in this blog post. The code lives on GitHub.

I have also created a .NET Standard version of the NuGet package at Swashbuckle.AspNetCore.Filters, which is also on GitHub.

Swashbuckle is a tool for generating Swagger, the API description language, from your ASP.NET Web Api solution.
Using Swashbuckle, which provides Swagger-UI, you can create pretty living documentation of your web api, like this:
swagger

Documenting the Response

In this post I am going to show you how to document the Response, and a new way to generate some response examples.

You can specify the type of response for Swashbuckle a number of ways. Consider a simple API endpoint which returns a list of Countries:

public class CountriesController : DefaultController
{
    [HttpGet]
    public async Task<HttpResponseMessage> Get()
    {
        var resource = new List<Country>
        {
            new Country {Code = "AR", Name = "Argentina"},
            new Country {Code = "BR", Name = "Brazil"},
            // etc etc omitted for brevity
        };

        return Request.CreateResponse(HttpStatusCode.OK, resource);
    }
}

One way of describing the response code and content for Swashbuckle is using a combination of XML comments, and the ResponseType attribute, like so:

/// <response code="200">Countries returned OK</response>
[HttpGet]
[ResponseType(typeof(IEnumerable<Country>))]
public async Task<HttpResponseMessage> Get()
{

However, this only allows for one type of response.

If your API method can return multiple types, i.e. in the case of an error, then you can use the new SwaggerResponse attribute:

[HttpGet]
[SwaggerResponse(HttpStatusCode.OK, Type=typeof(IEnumerable<Country>))]
[SwaggerResponse(HttpStatusCode.BadRequest, Type = typeof(IEnumerable<ErrorResource>))]
public async Task<HttpResponseMessage> Get(string lang)
{

The Swagger 2.0 spec allows for examples to be added to the Response. However, at time of writing Swashbuckle doesn’t support this. Fortunately Swashbuckle is extendible so here is a way of doing it.

Install my Swashbuckle.Examples NuGet package.

Decorate your methods with the new SwaggerResponseExample attribute:

[SwaggerResponse(HttpStatusCode.OK, Type=typeof(IEnumerable<Country>))]
[SwaggerResponseExample(HttpStatusCode.OK, typeof(CountryExamples))]
[SwaggerResponse(HttpStatusCode.BadRequest, Type = typeof(IEnumerable<ErrorResource>))]
public async Task<HttpResponseMessage> Get(string lang)

Now you’ll need to add an Examples class, which will implement IExamplesProvider to generate the example data

public class CountryExamples : IExamplesProvider
{
    public object GetExamples()
    {
        return new List<Country>
        {
            new Country { Code = "AA", Name = "Test Country" },
            new Country { Code = "BB", Name = "And another" }
        };
    }
}

And finally enable the ExamplesOperationFilter when you configure Swashbuckle’s startup.

configuration
    .EnableSwagger(c =>
    {
        c.OperationFilter<ExamplesOperationFilter>();
    })
    .EnableSwaggerUi();

Now that we’ve done all that, we should see the examples output in our swagger.json file, which you can get to by starting your solution and navigating to /swagger/docs/v1.

response

And then, when you browse the swagger-ui at /swagger/ui/index, instead of an autogenerated example like this:
response old

You’ll see your desired example, like this:
response new

Be sure to check out Part 2, where we again use Swashbuckle to generate example requests.

Run a Windows Azure cloud service locally without the Azure compute emulator

A big bugbear when developing Azure cloud services is the Azure emulator. You make a code change and the write – compile – debug process is slowed down big time because you have to wait for the Azure emulator to start up every time.

One project I worked on had a Web API running in an Azure cloud service and an ASP.NET MVC website running in another cloud service. So in order to develop it locally we had to run 2 instances of Visual Studio 2013 and each of them would fire up an emulator. Needless to say this was quite the resource hog and we’d every now and then see unexpected issues with Visual Studio or the emulators. Oh and the emulators would fight over which ports they would run on so we had to ensure we started debugging the API first so that it would get port 443 and then start the website which would default to 445.

So why can’t we just install our Web API and ASP.NET MVC website into IIS and not use the emulators? Well there are two blockers:

  1. The Azure diagnostics config will throw exceptions if we’re not running in Azure
  2. Settings are read from cloud config values in ServiceConfiguration.cscfg via RoleEnvironment.GetConfigurationSettingValue which needs Azure

My colleague Dylan came up with a solution. Basically, in the Global.asax.cs of both our website and our web api, we need to check if we’re running in Azure or not.

If we are in Azure, then use 1. configure Azure diagnostics config, and 2. read cloud config values using the default RoleEnvironment.GetConfigurationSettingValue.

If we are not in Azure, then 1. don’t configure Azure diagnostics, and 2. read cloud config values from ServiceConfiguration.cscfg manually via XML. parsing.


if (RoleEnvironment.IsAvailable) // we are in Azure
{
    Trace.Listeners.Add(new DiagnosticMonitorTraceListener());
    Trace.AutoFlush = true;
}
else
{
    var di = new DirectoryInfo(HttpContext.Current.Server.MapPath("~"));
    var solutionRoot = di.Parent;

    var xdoc = XDocument.Load(solutionRoot.FullName + @"\Identity.Web.Azure\ServiceConfiguration.cscfg");
    ConfigurationSettingsProvider.Current = new NotInRoleEnvirovmentConfigurationProvider(xdoc, "Identity.Web");
}

Our ConfigurationSettingsProvider.Current is by default a DefaultConfigurationSettingsProvider which uses RoleEnvironment.GetConfigurationSettingValue(key) to read the cloud config – we use one of these when we’re in Azure.

Our NotInRoleEnvirovmentConfigurationProvider reads the .cscfg file using XDocument.

So now I can install our website and web api into IIS locally – and code changes are visible after a compile. No need to run 2 Visual Studios and wait for the memory hungry emulator to startup every time. If I need to debug I can Debug -> Attach to process. Much more productive :-)