2

I'm trying to use Healthchecks UI in my asp.net core application with SqlServer.Storage for history purposes. It works with InMemoryStorage (without history part, of course).

So, Startup.cs code is like this:

services.AddHealthChecks()
    .AddHangfire(...)
    .AddDbContextCheck<...>("Database")
    .AddAzureBlobStorage(...)
    .AddProcessAllocatedMemoryHealthCheck(...)
    .AddCheck(...);

services
    .AddHealthChecksUI(settings =>
    {
        settings.SetEvaluationTimeInSeconds(...);
        settings.SetMinimumSecondsBetweenFailureNotifications(...);
        settings.MaximumHistoryEntriesPerEndpoint(...);
    })
    .AddSqlServerStorage(Configuration.GetConnectionString("..."));

later, additional configuration is in Configure method

Everything works when AddInMemoryStorage is used instead of AddSqlServerStorage. When AddSqlServerStorage is used, app crashes on startup, with

SqlException: Invalid object name 'Configurations'.

Sure, SQL tables are missing, but I cannot force [migration from nuget package to be applied to database.

Of course, I could copy/paste migration or create tables in database but I would like to skip that because of future changes and keeping code clean.

Can someone point me in right direction to solve this? Thanks

Nino
  • 6,931
  • 2
  • 27
  • 42
  • Maybe you are shutting down sql server for the healthcheck and the UI is not able to write as well?. That would explain why in memory is working. Can it go into the table normally using `UseSqlServerStorage`? – Chen Oct 24 '22 at 08:03
  • I succeeded in building services later and triggering Migrate(), but that is not [recommended](https://learn.microsoft.com/en-us/aspnet/core/diagnostics/asp0000?view=aspnetcore-6.0), so I'm guessing server works fine – Nino Oct 24 '22 at 08:17

2 Answers2

2

In Configure:

using IServiceScope scope = app.ApplicationServices.GetService<IServiceScopeFactory>().CreateScope();

using HealthChecksDb healthChecksDb = scope.ServiceProvider.GetRequiredService<HealthChecksDb>();

healthChecksDb.Database.Migrate();

In ConfigureServices:

// build an intermediate service provider
ServiceProvider serviceProvider = services.BuildServiceProvider();            
try
{
    using HealthChecksDb healthChecksDb = serviceProvider.GetRequiredService<HealthChecksDb>();
    healthChecksDb.Database.Migrate();
        
}
finally
{ 
    serviceProvider.Dispose(); 
}
Nino
  • 6,931
  • 2
  • 27
  • 42
Danut Radoaica
  • 1,860
  • 13
  • 17
  • Running that code in `Configure(IApplicationBuilder app, IWebHostEnvironment env)` was already too late, i got exception before app reached that code. :( – Nino Oct 24 '22 at 08:57
  • You can use it in ConfigureServices also, see the modified answer – Danut Radoaica Oct 24 '22 at 09:34
  • 1
    thanks, I got to that thanks to your answer, but decided for another approach because of `BuildServiceProvider` is not recommended. Anyhow, I managed to solve this. Your answer helper me so the bounty is yours (in 9 hours :)) – Nino Oct 24 '22 at 10:12
2

I've managed to solve it. Since migrations weren't applied to database, I ran them in Main like this.

var app = CreateHostBuilder(args).Build();
//run heaalthchecksui migrations
using (var scope = app.Services.CreateScope())
{
    var healthChecksDb = scope.ServiceProvider.GetRequiredService<HealthChecksDb>();
    healthChecksDb.Database.Migrate();
}

app.Run();

So, maybe that workouround could help someone with similar problem.

Nino
  • 6,931
  • 2
  • 27
  • 42