Skip to content

Commit

Permalink
Make hosted service generic (#157)
Browse files Browse the repository at this point in the history
* Make hosted service generic

* inject hosted service and generic application
  • Loading branch information
marcwittke authored Dec 27, 2023
1 parent 2a289a6 commit 83cb4cd
Show file tree
Hide file tree
Showing 6 changed files with 72 additions and 69 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,27 @@
using System.Threading.Tasks;
using Backend.Fx.Logging;
using Backend.Fx.Patterns.DependencyInjection;
using JetBrains.Annotations;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using ILogger = Microsoft.Extensions.Logging.ILogger;

namespace Backend.Fx.AspNetCore
{
public interface IBackendFxApplicationHostedService : IHostedService
[PublicAPI]
public interface IBackendFxApplicationHostedService<out TApplication> : IHostedService
where TApplication : IBackendFxApplication
{
IBackendFxApplication Application { get; }
TApplication Application { get; }
}

public abstract class BackendFxApplicationHostedService : IBackendFxApplicationHostedService

public abstract class BackendFxApplicationHostedService<TApplication> : IBackendFxApplicationHostedService<TApplication>
where TApplication : IBackendFxApplication
{
private static readonly ILogger Logger = Log.Create<BackendFxApplicationHostedService>();
private static readonly ILogger Logger = Log.Create<BackendFxApplicationHostedService<TApplication>>();

public abstract IBackendFxApplication Application { get; }
public abstract TApplication Application { get; }

public virtual async Task StartAsync(CancellationToken ct)
{
Expand All @@ -45,4 +50,20 @@ public virtual Task StopAsync(CancellationToken cancellationToken)
}
}
}

public static class BackendFxApplicationHostedServiceExtensions
{
public static void AddBackendFxApplication<THostedService, TApplication>(this IServiceCollection services)
where THostedService : class, IBackendFxApplicationHostedService<TApplication>
where TApplication : class, IBackendFxApplication
{
services.AddSingleton<THostedService>();

// this registration ensures starting of the hosted service
services.AddSingleton<IHostedService>(provider => provider.GetRequiredService<THostedService>());

// this registration makes the application instance available as singleton
services.AddSingleton(provider => provider.GetRequiredService<THostedService>().Application);
}
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,22 +1,18 @@
using Backend.Fx.AspNetCore.Tests.SampleApp.Runtime;
using Backend.Fx.Environment.MultiTenancy;
using Backend.Fx.InMemoryPersistence;
using Backend.Fx.Logging;
using Backend.Fx.Patterns.DependencyInjection;
using Backend.Fx.Patterns.EventAggregation.Integration;
using JetBrains.Annotations;

namespace Backend.Fx.AspNetCore.Tests.SampleApp
{
public class SampleApplicationHostedService : BackendFxApplicationHostedService
[UsedImplicitly]
public class SampleApplicationHostedService : BackendFxApplicationHostedService<SampleApplication>
{
public ITenantService TenantService { get; }
public override IBackendFxApplication Application { get; }
public override SampleApplication Application { get; }

public SampleApplicationHostedService(IExceptionLogger exceptionLogger)
public SampleApplicationHostedService(IExceptionLogger exceptionLogger, ITenantService tenantService)
{
IMessageBus messageBus = new InMemoryMessageBus();
TenantService = new TenantService(messageBus, new InMemoryTenantRepository());
Application = new SampleApplication(TenantService.TenantIdProvider, exceptionLogger);
Application = new SampleApplication(tenantService.TenantIdProvider, exceptionLogger);
}
}
}
38 changes: 35 additions & 3 deletions tests/Backend.Fx.AspNetCore.Tests/SampleApp/Startup.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,18 @@
using System.Security.Principal;
using Backend.Fx.AspNetCore.MultiTenancy;
using Backend.Fx.AspNetCore.Mvc;
using Backend.Fx.AspNetCore.Mvc.Activators;
using Backend.Fx.AspNetCore.Tests.SampleApp.Domain;
using Backend.Fx.AspNetCore.Tests.SampleApp.Runtime;
using Backend.Fx.Environment.MultiTenancy;
using Backend.Fx.InMemoryPersistence;
using Backend.Fx.Logging;
using Backend.Fx.Patterns.DependencyInjection;
using Backend.Fx.Patterns.EventAggregation.Integration;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.Extensions.DependencyInjection;

namespace Backend.Fx.AspNetCore.Tests.SampleApp
Expand All @@ -27,15 +37,20 @@ public void ConfigureServices(IServiceCollection services)

// enabling MVC
services.AddMvc();
services.AddSingleton<IControllerActivator, BackendFxApplicationControllerActivator>();

// integrate backend fx application as hosted service
services.AddBackendFxApplication<SampleApplicationHostedService>();
services.AddBackendFxApplication<SampleApplicationHostedService, SampleApplication>();

services.AddSingleton<IMessageBus, InMemoryMessageBus>();
services.AddSingleton<ITenantRepository, InMemoryTenantRepository>();
services.AddSingleton<ITenantService, TenantService>();
}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
// log exceptions to file
_exceptionLoggers.Add(new ExceptionLogger(Log.Create("Mep.WebHost")));
_exceptionLoggers.Add(new ExceptionLogger(Log.Create("Sample.WebHost")));

// use the ASP.Net Core routing middleware that decides the endpoint to be hit later
app.UseRouting();
Expand All @@ -48,7 +63,24 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env)

app.UseMiddleware<TenantAdminMiddleware>();

app.UseBackendFxApplication<SampleApplicationHostedService, MultiTenantMiddleware>();
app.UseMiddleware<MultiTenantMiddleware>();

app.Use(async (context, requestDelegate) =>
{
IBackendFxApplication application = app.ApplicationServices.GetRequiredService<SampleApplication>();
application.WaitForBoot();
// set the instance provider for the controller activator
context.SetCurrentInstanceProvider(application.CompositionRoot.InstanceProvider);
// the ambient tenant id has been set before by a TenantMiddleware
var tenantId = context.GetTenantId();
// the invoking identity has been set before by an AuthenticationMiddleware
IIdentity actingIdentity = context.User.Identity;
await application.AsyncInvoker.InvokeAsync(_ => requestDelegate.Invoke(), actingIdentity, tenantId);
});

app.UseEndpoints(endpointRouteBuilder =>
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
using Backend.Fx.AspNetCore.MultiTenancy;
using Backend.Fx.Environment.MultiTenancy;
using Microsoft.AspNetCore.Http;

namespace Backend.Fx.AspNetCore.Tests.SampleApp
{
public class TenantAdminMiddleware : TenantAdminMiddlewareBase
{
public TenantAdminMiddleware(RequestDelegate next, SampleApplicationHostedService hostedService)
: base(next, hostedService.TenantService)
public TenantAdminMiddleware(RequestDelegate next, ITenantService tenantService)
: base(next, tenantService)
{
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ protected override TestServer CreateServer(IWebHostBuilder builder)
{
TestServer server = base.CreateServer(builder);

ITenantService tenantService = server.Services.GetRequiredService<SampleApplicationHostedService>().TenantService;
ITenantService tenantService = server.Services.GetRequiredService<ITenantService>();
for (int i = 0; i < 100; i++)
{
var x = tenantService.CreateTenant($"t{i:000}", $"Tenant {i:000}", false);
Expand Down

0 comments on commit 83cb4cd

Please sign in to comment.