diff --git a/aspnetcore/host-and-deploy/health-checks.md b/aspnetcore/host-and-deploy/health-checks.md index 9964aed80f43..e96a4e7e6b30 100644 --- a/aspnetcore/host-and-deploy/health-checks.md +++ b/aspnetcore/host-and-deploy/health-checks.md @@ -5,7 +5,7 @@ description: Learn how to set up health checks for ASP.NET Core infrastructure, monikerRange: '>= aspnetcore-2.2' ms.author: riande ms.custom: mvc -ms.date: 11/13/2019 +ms.date: 12/15/2019 uid: host-and-deploy/health-checks --- # Health checks in ASP.NET Core @@ -294,9 +294,7 @@ app.UseEndpoints(endpoints => ### Customize output -The option gets or sets a delegate used to write the response. - -In `Startup.Configure`: +In `Startup.Configure`, set the [HealthCheckOptions.ResponseWriter](xref:Microsoft.AspNetCore.Diagnostics.HealthChecks.HealthCheckOptions.ResponseWriter) option to a delegate for writing the response: ```csharp app.UseEndpoints(endpoints => @@ -308,27 +306,19 @@ app.UseEndpoints(endpoints => }); ``` -The default delegate writes a minimal plaintext response with the string value of [HealthReport.Status](xref:Microsoft.Extensions.Diagnostics.HealthChecks.HealthReport.Status). The following custom delegate, `WriteResponse`, outputs a custom JSON response: +The default delegate writes a minimal plaintext response with the string value of [HealthReport.Status](xref:Microsoft.Extensions.Diagnostics.HealthChecks.HealthReport.Status). The following custom delegates output a custom JSON response. -```csharp -private static Task WriteResponse(HttpContext httpContext, HealthReport result) -{ - httpContext.Response.ContentType = "application/json"; +The first example from the sample app demonstrates how to use : - var json = new JObject( - new JProperty("status", result.Status.ToString()), - new JProperty("results", new JObject(result.Entries.Select(pair => - new JProperty(pair.Key, new JObject( - new JProperty("status", pair.Value.Status.ToString()), - new JProperty("description", pair.Value.Description), - new JProperty("data", new JObject(pair.Value.Data.Select( - p => new JProperty(p.Key, p.Value)))))))))); - return httpContext.Response.WriteAsync( - json.ToString(Formatting.Indented)); -} -``` +[!code-csharp[](health-checks/samples/3.x/HealthChecksSample/CustomWriterStartup.cs?name=snippet_WriteResponse_SystemTextJson)] -The health checks system doesn't provide built-in support for complex JSON return formats because the format is specific to your choice of monitoring system. Feel free to customize the `JObject` in the preceding example as necessary to meet your needs. +The second example demonstrates how to use [Newtonsoft.Json](https://www.nuget.org/packages/Newtonsoft.Json/): + +[!code-csharp[](health-checks/samples/3.x/HealthChecksSample/CustomWriterStartup.cs?name=snippet_WriteResponse_NewtonSoftJson)] + +In the sample app, comment out the `SYSTEM_TEXT_JSON` [preprocessor directive](xref:index#preprocessor-directives-in-sample-code) in *CustomWriterStartup.cs* to enable the `Newtonsoft.Json` version of `WriteResponse`. + +The health checks API doesn't provide built-in support for complex JSON return formats because the format is specific to your choice of monitoring system. Customize the response in the preceding examples as needed. For more information on JSON serialization with `System.Text.Json`, see [How to serialize and deserialize JSON in .NET](/dotnet/standard/serialization/system-text-json-how-to). ## Database probe @@ -525,11 +515,11 @@ The sample app demonstrates a memory health check with a custom response writer. Register health check services with in `Startup.ConfigureServices`. Instead of enabling the health check by passing it to , the `MemoryHealthCheck` is registered as a service. All registered services are available to the health check services and middleware. We recommend registering health check services as Singleton services. -In the sample app (*CustomWriterStartup.cs*): +In *CustomWriterStartup.cs* of the sample app: [!code-csharp[](health-checks/samples/3.x/HealthChecksSample/CustomWriterStartup.cs?name=snippet_ConfigureServices&highlight=4)] -A health check endpoint is created by calling `MapHealthChecks` in `Startup.Configure`. A `WriteResponse` delegate is provided to the `ResponseWriter` property to output a custom JSON response when the health check executes: +A health check endpoint is created by calling `MapHealthChecks` in `Startup.Configure`. A `WriteResponse` delegate is provided to the property to output a custom JSON response when the health check executes: ```csharp app.UseEndpoints(endpoints => @@ -541,9 +531,7 @@ app.UseEndpoints(endpoints => } ``` -The `WriteResponse` method formats the `CompositeHealthCheckResult` into a JSON object and yields JSON output for the health check response: - -[!code-csharp[](health-checks/samples/3.x/HealthChecksSample/CustomWriterStartup.cs?name=snippet_WriteResponse)] +The `WriteResponse` delegate formats the `CompositeHealthCheckResult` into a JSON object and yields JSON output for the health check response. For more information, see the [Customize output](#customize-output) section. To run the metric-based probe with custom response writer output using the sample app, execute the following command from the project's folder in a command shell: diff --git a/aspnetcore/host-and-deploy/health-checks/samples/2.x/HealthChecksSample/CustomWriterStartup.cs b/aspnetcore/host-and-deploy/health-checks/samples/2.x/HealthChecksSample/CustomWriterStartup.cs index 79e082321685..8da835a797f2 100644 --- a/aspnetcore/host-and-deploy/health-checks/samples/2.x/HealthChecksSample/CustomWriterStartup.cs +++ b/aspnetcore/host-and-deploy/health-checks/samples/2.x/HealthChecksSample/CustomWriterStartup.cs @@ -48,7 +48,7 @@ await context.Response.WriteAsync( private static Task WriteResponse(HttpContext httpContext, HealthReport result) { - httpContext.Response.ContentType = "application/json"; + httpContext.Response.ContentType = "application/json; charset=utf-8"; var json = new JObject( new JProperty("status", result.Status.ToString()), diff --git a/aspnetcore/host-and-deploy/health-checks/samples/3.x/HealthChecksSample/BasicStartup.cs b/aspnetcore/host-and-deploy/health-checks/samples/3.x/HealthChecksSample/BasicStartup.cs index 4881165caaab..43c35f6cbb86 100644 --- a/aspnetcore/host-and-deploy/health-checks/samples/3.x/HealthChecksSample/BasicStartup.cs +++ b/aspnetcore/host-and-deploy/health-checks/samples/3.x/HealthChecksSample/BasicStartup.cs @@ -1,5 +1,4 @@ using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.DependencyInjection; diff --git a/aspnetcore/host-and-deploy/health-checks/samples/3.x/HealthChecksSample/CustomWriterStartup.cs b/aspnetcore/host-and-deploy/health-checks/samples/3.x/HealthChecksSample/CustomWriterStartup.cs index 86dcc5963142..dd529aa29a9c 100644 --- a/aspnetcore/host-and-deploy/health-checks/samples/3.x/HealthChecksSample/CustomWriterStartup.cs +++ b/aspnetcore/host-and-deploy/health-checks/samples/3.x/HealthChecksSample/CustomWriterStartup.cs @@ -1,13 +1,22 @@ -using System.Linq; +#define SYSTEM_TEXT_JSON + +using System; +using System.IO; +using System.Linq; +#if SYSTEM_TEXT_JSON +using System.Text; +using System.Text.Json; +#endif using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Diagnostics.HealthChecks; -using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Diagnostics.HealthChecks; +#if !SYSTEM_TEXT_JSON using Newtonsoft.Json; using Newtonsoft.Json.Linq; +#endif namespace SampleApp { @@ -49,11 +58,55 @@ await context.Response.WriteAsync( }); } - #region snippet_WriteResponse - private static Task WriteResponse(HttpContext httpContext, - HealthReport result) +#if SYSTEM_TEXT_JSON + #region snippet_WriteResponse_SystemTextJson + private static Task WriteResponse(HttpContext context, HealthReport result) + { + context.Response.ContentType = "application/json; charset=utf-8"; + + var options = new JsonWriterOptions + { + Indented = true + }; + + using (var stream = new MemoryStream()) + { + using (var writer = new Utf8JsonWriter(stream, options)) + { + writer.WriteStartObject(); + writer.WriteString("status", result.Status.ToString()); + writer.WriteStartObject("results"); + foreach (var entry in result.Entries) + { + writer.WriteStartObject(entry.Key); + writer.WriteString("status", entry.Value.Status.ToString()); + writer.WriteString("description", entry.Value.Description); + writer.WriteStartObject("data"); + foreach (var item in entry.Value.Data) + { + writer.WritePropertyName(item.Key); + JsonSerializer.Serialize( + writer, item.Value, item.Value?.GetType() ?? + typeof(object)); + } + writer.WriteEndObject(); + writer.WriteEndObject(); + } + writer.WriteEndObject(); + writer.WriteEndObject(); + } + + var json = Encoding.UTF8.GetString(stream.ToArray()); + + return context.Response.WriteAsync(json); + } + } + #endregion +#else + #region snippet_WriteResponse_NewtonSoftJson + private static Task WriteResponse(HttpContext context, HealthReport result) { - httpContext.Response.ContentType = "application/json"; + context.Response.ContentType = "application/json"; var json = new JObject( new JProperty("status", result.Status.ToString()), @@ -63,9 +116,11 @@ private static Task WriteResponse(HttpContext httpContext, new JProperty("description", pair.Value.Description), new JProperty("data", new JObject(pair.Value.Data.Select( p => new JProperty(p.Key, p.Value)))))))))); - return httpContext.Response.WriteAsync( + + return context.Response.WriteAsync( json.ToString(Formatting.Indented)); } #endregion +#endif } } diff --git a/aspnetcore/host-and-deploy/health-checks/samples/3.x/HealthChecksSample/DBHealthStartup.cs b/aspnetcore/host-and-deploy/health-checks/samples/3.x/HealthChecksSample/DBHealthStartup.cs index e0fec2cc0693..f2abdb686f21 100644 --- a/aspnetcore/host-and-deploy/health-checks/samples/3.x/HealthChecksSample/DBHealthStartup.cs +++ b/aspnetcore/host-and-deploy/health-checks/samples/3.x/HealthChecksSample/DBHealthStartup.cs @@ -1,5 +1,4 @@ using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; diff --git a/aspnetcore/host-and-deploy/health-checks/samples/3.x/HealthChecksSample/DbContextHealthStartup.cs b/aspnetcore/host-and-deploy/health-checks/samples/3.x/HealthChecksSample/DbContextHealthStartup.cs index c5880b5d6c15..edb23b9ec57e 100644 --- a/aspnetcore/host-and-deploy/health-checks/samples/3.x/HealthChecksSample/DbContextHealthStartup.cs +++ b/aspnetcore/host-and-deploy/health-checks/samples/3.x/HealthChecksSample/DbContextHealthStartup.cs @@ -1,6 +1,5 @@ using System; using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; diff --git a/aspnetcore/host-and-deploy/health-checks/samples/3.x/HealthChecksSample/LivenessProbeStartup.cs b/aspnetcore/host-and-deploy/health-checks/samples/3.x/HealthChecksSample/LivenessProbeStartup.cs index cc7f99678f79..e44d14cb1c1d 100644 --- a/aspnetcore/host-and-deploy/health-checks/samples/3.x/HealthChecksSample/LivenessProbeStartup.cs +++ b/aspnetcore/host-and-deploy/health-checks/samples/3.x/HealthChecksSample/LivenessProbeStartup.cs @@ -3,9 +3,7 @@ using Microsoft.AspNetCore.Diagnostics.HealthChecks; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.Diagnostics.HealthChecks; -using Microsoft.Extensions.Hosting; using SampleApp.Services; namespace SampleApp diff --git a/aspnetcore/host-and-deploy/health-checks/samples/3.x/HealthChecksSample/ManagementPortStartup.cs b/aspnetcore/host-and-deploy/health-checks/samples/3.x/HealthChecksSample/ManagementPortStartup.cs index fc66a0366f73..56f01f4f150d 100644 --- a/aspnetcore/host-and-deploy/health-checks/samples/3.x/HealthChecksSample/ManagementPortStartup.cs +++ b/aspnetcore/host-and-deploy/health-checks/samples/3.x/HealthChecksSample/ManagementPortStartup.cs @@ -1,5 +1,4 @@ using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; diff --git a/aspnetcore/host-and-deploy/health-checks/samples/3.x/HealthChecksSample/SampleApp.csproj b/aspnetcore/host-and-deploy/health-checks/samples/3.x/HealthChecksSample/SampleApp.csproj index 2e54e4e19ea2..117c1d993eea 100644 --- a/aspnetcore/host-and-deploy/health-checks/samples/3.x/HealthChecksSample/SampleApp.csproj +++ b/aspnetcore/host-and-deploy/health-checks/samples/3.x/HealthChecksSample/SampleApp.csproj @@ -1,15 +1,14 @@ - netcoreapp3.0 + netcoreapp3.1 - - - - - + + + +