2

I am trying to implement health checks in my blazor application. To do so, I have used the Microsoft.AspNetCore.Diagnostics.HealthChecks package among others. Below you can see sql and url health checks.

startup.cs

//using AjuaBlazorServerApp.Data;
using HealthChecks.UI.Client;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Diagnostics.HealthChecks;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Diagnostics.HealthChecks;
using Microsoft.Extensions.Hosting;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace AjuaBlazorServerApp
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddRazorPages();
            services.AddServerSideBlazor();
            services.AddHostedService<PeriodicExecutor>();
            services.AddHealthChecks().AddUrlGroup(new Uri("https://api.example.com/post"),
                name: "Example Endpoint",
                failureStatus: HealthStatus.Degraded)
            .AddSqlServer(Configuration["sqlString"],
                healthQuery: "select 1",
                failureStatus: HealthStatus.Degraded,
                name: "SQL Server");
            services.AddHealthChecksUI(opt =>
            {
                opt.SetEvaluationTimeInSeconds(5); //time in seconds between check    
                opt.MaximumHistoryEntriesPerEndpoint(60); //maximum history of checks    
                opt.SetApiMaxActiveRequests(1); //api requests concurrency    
                opt.AddHealthCheckEndpoint("Ajua API", "/api/health"); //map health check api    
            }).AddInMemoryStorage();
        }

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Error");
            }

            app.UseStaticFiles();

            app.UseRouting();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapBlazorHub();
                endpoints.MapFallbackToPage("/_Host");
                endpoints.MapHealthChecks("/api/health", new HealthCheckOptions()
                {
                    Predicate = _ => true,
                    ResponseWriter = UIResponseWriter.
                    WriteHealthCheckUIResponse
                });
                endpoints.MapHealthChecksUI();
            });
        }
    }
}

The sql one works perfectly. However the url health check returns the following error:

Discover endpoint #0 is not responding with code in 200...299 range, the current status is MethodNotAllowed.

What i would like to know is if there is a way to maybe set the method type and if need be send some test details to the endpoint so that we can actually get a valid response.

TriedAtLeast
  • 181
  • 1
  • 10

2 Answers2

3

AddUrlGroup has an overload that allows you to specify the method through the httpMethod parameter. Try using :

.AddUrlGroup(new Uri("https://api.example.com/post"),
            httpMethod: HttpMethod.Post,
            name: "Example Endpoint",
            failureStatus: HealthStatus.Degraded)

Another overload allows configuring the HttpClient and HttpMessageHandler explicitly, to add specific default headers for example, enable compression or redirection.

.AddUrlGroup(new Uri("https://api.example.com/post"),
            httpMethod: HttpMethod.Post,
            name: "Example Endpoint",
            configureClient: client => {
                client.DefaultRequest.Headers.IfModifiedSince=
                                DateTimeOffset.Now.AddMinutes(-10);
            },
            failureStatus: HealthStatus.Degraded)

Yet another overload allows explicitly configuring the UriHealthCheckOptions class generated by other AddUrlGroup overloads:

.AddUrlGroup(uriOptions=>{
    uriOptions
        .UsePost()
        .AddUri(someUrl,setup=>{
            setup.AddCustomHeader("...","...");
    });
});

There's no way to specify content headers because the health check code doesn't send a body.

Panagiotis Kanavos
  • 120,703
  • 13
  • 188
  • 236
  • Is there a way to set the content type? e.g application/json Btw your answer worked and now my problem is with content type so I will just accept your solution – TriedAtLeast Mar 16 '22 at 14:02
1

I accepted the answer above because it technically answered my question. However, this is the implementation I ended up using. Basically you will have to create your own custom healthcheck.

  1. Add a new folder under you projects main directory and name it accordingly enter image description here

2. Create a new class in that folder and add code similar to what I have below

EndpointHealth.cs

using Microsoft.Extensions.Diagnostics.HealthChecks;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using System.Net;
using System.IO;
using Microsoft.Extensions.Configuration;

namespace BlazorServerApp.HealthChecks
{
    public class EndpointHealth : IHealthCheck
    {
        public Task<HealthCheckResult> CheckHealthAsync(HealthCheckContext context, CancellationToken cancellationToken =
         default)
        {
            
                //create a json string of parameters and send it to the endpoint
                var data = new
                {
                    test = "Example",
                };
                string jsonString = JsonSerializer.Serialize(data);
                var httpWebRequest = (HttpWebRequest)WebRequest.Create("https://api.example.com/post");
                httpWebRequest.ContentType = Configuration["application/json"];
                httpWebRequest.Method = Configuration["POST"];
                using (var streamWriter = new StreamWriter(httpWebRequest.GetRequestStream()))
                {
                    streamWriter.Write(jsonString);
                }
                //Get the endpoint result and use it to return the appropriate health check result
                var httpResponse = (HttpWebResponse)httpWebRequest.GetResponse();
                if (((int)httpResponse.StatusCode) >= 200 && ((int)httpResponse.StatusCode) < 300)
                return Task.FromResult(HealthCheckResult.Healthy());
                else
                return Task.FromResult(HealthCheckResult.Unhealthy());
        }
    }
}

Then add the following code to the top of your startup.cs file using BlazorServerApp.HealthChecks;

and finally the below code:

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddRazorPages();
            services.AddServerSideBlazor();
            services.AddHealthChecks()
            .AddCheck<EndpointHealth>("Endpoint",null);

        }
TriedAtLeast
  • 181
  • 1
  • 10