Performance Tests / Benchmarking for ASP.NET Core 2.2 Endpoints

Written by Ken Dale

As you’re building out an API it’s important to keep response times in check. In many cases slowness is due to database calls, web requests, and other network operations. But, elevated response times can also be due to in-memory operations as part of the ASP.NET Core pipeline.

Using BenchmarkDotNet we can benchmark integration tests for an ASP.NET Core 2.2 application to keep a watch on these items.

<!-- Benchmarks.csproj -->

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

  <PropertyGroup>
    <TargetFramework>netcoreapp2.2</TargetFramework>
    <OutputType>Exe</OutputType>
    <ServerGarbageCollection>true</ServerGarbageCollection>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="BenchmarkDotNet" Version="0.11.3" />
    <PackageReference Include="Microsoft.AspNetCore.App" />
    <PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="2.2.0" />
  </ItemGroup>

  <ItemGroup>
    <ProjectReference Include="<< TODO >>" />
  </ItemGroup>

</Project>
// ResponseBenchmarks.cs

using BenchmarkDotNet.Attributes;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc.Testing;
using Microsoft.Extensions.Logging;
using SampleApi; // TODO: Change this to your API to benchmark
using System.Net.Http;
using System.Threading.Tasks;

namespace Benchmarks
{
    [InProcess]
    [MemoryDiagnoser]
    public class ResponseBenchmarks
    {
        private HttpClient client;

        [GlobalSetup]
        public void GlobalSetup()
        {
            var factory = new WebApplicationFactory<Startup>()
                .WithWebHostBuilder(configuration =>
                {
                    configuration.ConfigureLogging(logging =>
                    {
                        logging.ClearProviders();
                    });
                });

            client = factory.CreateClient();
        }

        [Benchmark]
        public Task GetResponseTime()
        {
            return client.GetAsync("/");
        }

        // More benchmarks as needed
    }
}
// Program.cs

using BenchmarkDotNet.Running;

namespace Benchmarks
{
    public class Program
    {
        public static void Main()
        {
            BenchmarkRunner.Run<ResponseBenchmarks>();
        }
    }
}

Running this via dotnet run -c Release will produce something like:

                             Method |       Mean |     Error |    StdDev | Gen 0/1k Op | Gen 1/1k Op | Gen 2/1k Op | Allocated Memory/Op |
----------------------------------- |-----------:|----------:|----------:|------------:|------------:|------------:|--------------------:|
                    GetResponseTime |   186.3 us |  2.586 us |  2.419 us |           - |           - |           - |             6.09 KB |

Happy benchmarking!

Published December 26, 2018 by

undefined avatar
Ken Dale Senior Application Developer (Former)

Suggested Reading