Add health checks routing extensions (#5127)

This commit is contained in:
James Newton-King 2018-12-21 11:18:44 +13:00 committed by GitHub
parent 28cf059a3d
commit 5ab3c89be3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 158 additions and 0 deletions

View File

@ -0,0 +1,71 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Diagnostics.HealthChecks;
using Microsoft.Extensions.Options;
using Microsoft.AspNetCore.Routing;
namespace Microsoft.AspNetCore.Builder
{
/// <summary>
/// Provides extension methods for <see cref="IEndpointRouteBuilder"/> to add health checks.
/// </summary>
public static class HealthCheckEndpointRouteBuilderExtensions
{
/// <summary>
/// Adds a health checks endpoint to the <see cref="IEndpointRouteBuilder"/> with the specified template.
/// </summary>
/// <param name="builder">The <see cref="IEndpointRouteBuilder"/> to add the health checks endpoint to.</param>
/// <param name="pattern">The URL pattern of the health checks endpoint.</param>
/// <returns>A convention builder for the health checks endpoint.</returns>
public static IEndpointConventionBuilder MapHealthChecks(
this IEndpointRouteBuilder builder,
string pattern)
{
if (builder == null)
{
throw new ArgumentNullException(nameof(builder));
}
return MapHealthChecksCore(builder, pattern, null);
}
/// <summary>
/// Adds a health checks endpoint to the <see cref="IEndpointRouteBuilder"/> with the specified template and options.
/// </summary>
/// <param name="builder">The <see cref="IEndpointRouteBuilder"/> to add the health checks endpoint to.</param>
/// <param name="pattern">The URL pattern of the health checks endpoint.</param>
/// <param name="options">A <see cref="HealthCheckOptions"/> used to configure the health checks.</param>
/// <returns>A convention builder for the health checks endpoint.</returns>
public static IEndpointConventionBuilder MapHealthChecks(
this IEndpointRouteBuilder builder,
string pattern,
HealthCheckOptions options)
{
if (builder == null)
{
throw new ArgumentNullException(nameof(builder));
}
if (options == null)
{
throw new ArgumentNullException(nameof(options));
}
return MapHealthChecksCore(builder, pattern, options);
}
private static IEndpointConventionBuilder MapHealthChecksCore(IEndpointRouteBuilder builder, string pattern, HealthCheckOptions options)
{
var args = options != null ? new[] { Options.Create(options) } : Array.Empty<object>();
var pipeline = builder.CreateApplicationBuilder()
.UseMiddleware<HealthCheckMiddleware>(args)
.Build();
return builder.Map(pattern, "Health checks", pipeline);
}
}
}

View File

@ -17,6 +17,7 @@
<ItemGroup>
<Reference Include="Microsoft.AspNetCore.Http.Abstractions" />
<Reference Include="Microsoft.AspNetCore.Routing" />
<Reference Include="Microsoft.Extensions.Diagnostics.HealthChecks" />
<Reference Include="Microsoft.Extensions.Options" />
<Reference Include="Microsoft.Net.Http.Headers" />

View File

@ -0,0 +1,86 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Net;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Routing;
using Microsoft.AspNetCore.TestHost;
using Moq;
using Xunit;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.AspNetCore.Http;
namespace Microsoft.AspNetCore.Diagnostics.HealthChecks
{
public class HealthCheckEndpointRouteBuilderExtensionsTest
{
[Fact]
public async Task MapHealthChecks_ReturnsOk()
{
// Arrange
var builder = new WebHostBuilder()
.Configure(app =>
{
app.UseRouting(routes =>
{
routes.MapHealthChecks("/healthz");
});
})
.ConfigureServices(services =>
{
services.AddRouting();
services.AddHealthChecks();
});
var server = new TestServer(builder);
var client = server.CreateClient();
// Act
var response = await client.GetAsync("/healthz");
// Assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.Equal("text/plain", response.Content.Headers.ContentType.ToString());
Assert.Equal("Healthy", await response.Content.ReadAsStringAsync());
}
[Fact]
public async Task MapHealthChecks_WithOptions_ReturnsOk()
{
// Arrange
var builder = new WebHostBuilder()
.Configure(app =>
{
app.UseRouting(routes =>
{
routes.MapHealthChecks("/healthz", new HealthCheckOptions
{
ResponseWriter = async (context, report) =>
{
context.Response.ContentType = "text/plain";
await context.Response.WriteAsync("Custom!");
}
});
});
})
.ConfigureServices(services =>
{
services.AddRouting();
services.AddHealthChecks();
});
var server = new TestServer(builder);
var client = server.CreateClient();
// Act
var response = await client.GetAsync("/healthz");
// Assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.Equal("text/plain", response.Content.Headers.ContentType.ToString());
Assert.Equal("Custom!", await response.Content.ReadAsStringAsync());
}
}
}