();
20 | context.Services.AddScoped(_ => new HttpClient
21 | {
22 | BaseAddress = new Uri(hostEnvironment.BaseAddress)
23 | });
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/samples/BlazorApp2/BlazorApp2.Client/Layout/MainLayout.razor:
--------------------------------------------------------------------------------
1 | @inherits LayoutComponentBase
2 |
3 |
4 |
7 |
8 |
9 |
12 |
13 |
14 | @Body
15 |
16 |
17 |
18 |
19 |
20 | An unhandled error has occurred.
21 |
Reload
22 |
🗙
23 |
24 |
--------------------------------------------------------------------------------
/samples/BlazorApp2/BlazorApp2.Client/Layout/MainLayout.razor.css:
--------------------------------------------------------------------------------
1 | .page {
2 | position: relative;
3 | display: flex;
4 | flex-direction: column;
5 | }
6 |
7 | main {
8 | flex: 1;
9 | }
10 |
11 | .sidebar {
12 | background-image: linear-gradient(180deg, rgb(5, 39, 103) 0%, #3a0647 70%);
13 | }
14 |
15 | .top-row {
16 | background-color: #f7f7f7;
17 | border-bottom: 1px solid #d6d5d5;
18 | justify-content: flex-end;
19 | height: 3.5rem;
20 | display: flex;
21 | align-items: center;
22 | }
23 |
24 | .top-row ::deep a, .top-row ::deep .btn-link {
25 | white-space: nowrap;
26 | margin-left: 1.5rem;
27 | text-decoration: none;
28 | }
29 |
30 | .top-row ::deep a:hover, .top-row ::deep .btn-link:hover {
31 | text-decoration: underline;
32 | }
33 |
34 | .top-row ::deep a:first-child {
35 | overflow: hidden;
36 | text-overflow: ellipsis;
37 | }
38 |
39 | @media (max-width: 640.98px) {
40 | .top-row {
41 | justify-content: space-between;
42 | }
43 |
44 | .top-row ::deep a, .top-row ::deep .btn-link {
45 | margin-left: 0;
46 | }
47 | }
48 |
49 | @media (min-width: 641px) {
50 | .page {
51 | flex-direction: row;
52 | }
53 |
54 | .sidebar {
55 | width: 250px;
56 | height: 100vh;
57 | position: sticky;
58 | top: 0;
59 | }
60 |
61 | .top-row {
62 | position: sticky;
63 | top: 0;
64 | z-index: 1;
65 | }
66 |
67 | .top-row.auth ::deep a:first-child {
68 | flex: 1;
69 | text-align: right;
70 | width: 0;
71 | }
72 |
73 | .top-row, article {
74 | padding-left: 2rem !important;
75 | padding-right: 1.5rem !important;
76 | }
77 | }
78 |
79 | #blazor-error-ui {
80 | background: lightyellow;
81 | bottom: 0;
82 | box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2);
83 | display: none;
84 | left: 0;
85 | padding: 0.6rem 1.25rem 0.7rem 1.25rem;
86 | position: fixed;
87 | width: 100%;
88 | z-index: 1000;
89 | }
90 |
91 | #blazor-error-ui .dismiss {
92 | cursor: pointer;
93 | position: absolute;
94 | right: 0.75rem;
95 | top: 0.5rem;
96 | }
97 |
--------------------------------------------------------------------------------
/samples/BlazorApp2/BlazorApp2.Client/Layout/NavMenu.razor:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
9 |
30 |
31 |
--------------------------------------------------------------------------------
/samples/BlazorApp2/BlazorApp2.Client/Pages/Counter.razor:
--------------------------------------------------------------------------------
1 | @page "/counter"
2 |
3 | Counter
4 |
5 | Counter
6 |
7 | Current count: @currentCount
8 |
9 | Click me
10 |
11 | @code {
12 | private int currentCount = 0;
13 |
14 | private void IncrementCount()
15 | {
16 | currentCount++;
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/samples/BlazorApp2/BlazorApp2.Client/Pages/Home.razor:
--------------------------------------------------------------------------------
1 | @page "/"
2 |
3 | Home
4 |
5 | Hello, world!
6 |
7 | Welcome to your new app.
8 |
--------------------------------------------------------------------------------
/samples/BlazorApp2/BlazorApp2.Client/Pages/Weather.razor:
--------------------------------------------------------------------------------
1 | @page "/weather"
2 |
3 | Weather
4 |
5 | Weather
6 |
7 | This component demonstrates showing data.
8 |
9 | @if (forecasts == null)
10 | {
11 | Loading...
12 | }
13 | else
14 | {
15 |
16 |
17 |
18 | Date
19 | Temp. (C)
20 | Temp. (F)
21 | Summary
22 |
23 |
24 |
25 | @foreach (var forecast in forecasts)
26 | {
27 |
28 | @forecast.Date.ToShortDateString()
29 | @forecast.TemperatureC
30 | @forecast.TemperatureF
31 | @forecast.Summary
32 |
33 | }
34 |
35 |
36 | }
37 |
38 | @code {
39 | private WeatherForecast[]? forecasts;
40 |
41 | protected override async Task OnInitializedAsync()
42 | {
43 | // Simulate asynchronous loading to demonstrate a loading indicator
44 | await Task.Delay(500);
45 |
46 | var startDate = DateOnly.FromDateTime(DateTime.Now);
47 | var summaries = new[] { "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" };
48 | forecasts = Enumerable.Range(1, 5).Select(index => new WeatherForecast
49 | {
50 | Date = startDate.AddDays(index),
51 | TemperatureC = Random.Shared.Next(-20, 55),
52 | Summary = summaries[Random.Shared.Next(summaries.Length)]
53 | }).ToArray();
54 | }
55 |
56 | private class WeatherForecast
57 | {
58 | public DateOnly Date { get; set; }
59 | public int TemperatureC { get; set; }
60 | public string? Summary { get; set; }
61 | public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/samples/BlazorApp2/BlazorApp2.Client/Program.cs:
--------------------------------------------------------------------------------
1 | namespace BlazorApp2.Client
2 | {
3 | using System.Threading.Tasks;
4 | using Fluxera.Extensions.Hosting;
5 |
6 | public static class Program
7 | {
8 | public static async Task Main(string[] args)
9 | {
10 | await ApplicationHost.RunAsync(args);
11 | }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/samples/BlazorApp2/BlazorApp2.Client/Routes.razor:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/samples/BlazorApp2/BlazorApp2.Client/_Imports.razor:
--------------------------------------------------------------------------------
1 | @using System.Net.Http
2 | @using System.Net.Http.Json
3 | @using Microsoft.AspNetCore.Components.Forms
4 | @using Microsoft.AspNetCore.Components.Routing
5 | @using Microsoft.AspNetCore.Components.Web
6 | @using static Microsoft.AspNetCore.Components.Web.RenderMode
7 | @using Microsoft.AspNetCore.Components.Web.Virtualization
8 | @using Microsoft.JSInterop
9 | @using BlazorApp2.Client
10 |
--------------------------------------------------------------------------------
/samples/BlazorApp2/BlazorApp2.Client/wwwroot/appsettings.Development.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft.AspNetCore": "Warning"
6 | }
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/samples/BlazorApp2/BlazorApp2.Client/wwwroot/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft.AspNetCore": "Warning"
6 | }
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/samples/BlazorApp2/BlazorApp2/BlazorApp2.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net9.0
5 | false
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/samples/BlazorApp2/BlazorApp2/Components/App.razor:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/samples/BlazorApp2/BlazorApp2/Components/Pages/Error.razor:
--------------------------------------------------------------------------------
1 | @page "/Error"
2 | @using System.Diagnostics
3 | @using Microsoft.AspNetCore.Http
4 |
5 | Error
6 |
7 | Error.
8 | An error occurred while processing your request.
9 |
10 | @if (ShowRequestId)
11 | {
12 |
13 | Request ID: @RequestId
14 |
15 | }
16 |
17 | Development Mode
18 |
19 | Swapping to Development environment will display more detailed information about the error that occurred.
20 |
21 |
22 | The Development environment shouldn't be enabled for deployed applications.
23 | It can result in displaying sensitive information from exceptions to end users.
24 | For local debugging, enable the Development environment by setting the ASPNETCORE_ENVIRONMENT environment variable to Development
25 | and restarting the app.
26 |
27 |
28 | @code{
29 | [CascadingParameter]
30 | private HttpContext? HttpContext { get; set; }
31 |
32 | private string? RequestId { get; set; }
33 | private bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
34 |
35 | protected override void OnInitialized() =>
36 | RequestId = Activity.Current?.Id ?? HttpContext?.TraceIdentifier;
37 | }
38 |
--------------------------------------------------------------------------------
/samples/BlazorApp2/BlazorApp2/Components/_Imports.razor:
--------------------------------------------------------------------------------
1 | @using System.Net.Http
2 | @using System.Net.Http.Json
3 | @using Microsoft.AspNetCore.Components.Forms
4 | @using Microsoft.AspNetCore.Components.Routing
5 | @using Microsoft.AspNetCore.Components.Web
6 | @using static Microsoft.AspNetCore.Components.Web.RenderMode
7 | @using Microsoft.AspNetCore.Components.Web.Virtualization
8 | @using Microsoft.JSInterop
9 | @using BlazorApp2
10 | @using BlazorApp2.Client
11 | @using BlazorApp2.Components
12 |
--------------------------------------------------------------------------------
/samples/BlazorApp2/BlazorApp2/Program.cs:
--------------------------------------------------------------------------------
1 | namespace BlazorApp2
2 | {
3 | using BlazorApp2.Client.Pages;
4 | using BlazorApp2.Components;
5 | using Microsoft.AspNetCore.Builder;
6 | using Microsoft.Extensions.DependencyInjection;
7 | using Microsoft.Extensions.Hosting;
8 |
9 | public static class Program
10 | {
11 | public static void Main(string[] args)
12 | {
13 | WebApplicationBuilder builder = WebApplication.CreateBuilder(args);
14 |
15 | // Add services to the container.
16 | builder.Services
17 | .AddRazorComponents()
18 | .AddInteractiveWebAssemblyComponents();
19 |
20 | WebApplication app = builder.Build();
21 |
22 | // Configure the HTTP request pipeline.
23 | if(app.Environment.IsDevelopment())
24 | {
25 | app.UseWebAssemblyDebugging();
26 | }
27 | else
28 | {
29 | app.UseExceptionHandler("/Error");
30 | // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
31 | app.UseHsts();
32 | }
33 |
34 | app.UseHttpsRedirection();
35 |
36 | app.UseStaticFiles();
37 | app.UseAntiforgery();
38 |
39 | app.MapRazorComponents()
40 | .AddInteractiveWebAssemblyRenderMode()
41 | .AddAdditionalAssemblies(typeof(Counter).Assembly);
42 |
43 | app.Run();
44 | }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/samples/BlazorApp2/BlazorApp2/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "http://json.schemastore.org/launchsettings.json",
3 | "iisSettings": {
4 | "windowsAuthentication": false,
5 | "anonymousAuthentication": true,
6 | "iisExpress": {
7 | "applicationUrl": "http://localhost:44051",
8 | "sslPort": 44326
9 | }
10 | },
11 | "profiles": {
12 | "http": {
13 | "commandName": "Project",
14 | "dotnetRunMessages": true,
15 | "launchBrowser": true,
16 | "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}",
17 | "applicationUrl": "http://localhost:5130",
18 | "environmentVariables": {
19 | "ASPNETCORE_ENVIRONMENT": "Development"
20 | }
21 | },
22 | "https": {
23 | "commandName": "Project",
24 | "dotnetRunMessages": true,
25 | "launchBrowser": true,
26 | "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}",
27 | "applicationUrl": "https://localhost:7243;http://localhost:5130",
28 | "environmentVariables": {
29 | "ASPNETCORE_ENVIRONMENT": "Development"
30 | }
31 | },
32 | "IIS Express": {
33 | "commandName": "IISExpress",
34 | "launchBrowser": true,
35 | "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}",
36 | "environmentVariables": {
37 | "ASPNETCORE_ENVIRONMENT": "Development"
38 | }
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/samples/BlazorApp2/BlazorApp2/appsettings.Development.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft.AspNetCore": "Warning"
6 | }
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/samples/BlazorApp2/BlazorApp2/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft.AspNetCore": "Warning"
6 | }
7 | },
8 | "AllowedHosts": "*"
9 | }
10 |
--------------------------------------------------------------------------------
/samples/BlazorApp2/BlazorApp2/wwwroot/app.css:
--------------------------------------------------------------------------------
1 | html, body {
2 | font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
3 | }
4 |
5 | a, .btn-link {
6 | color: #006bb7;
7 | }
8 |
9 | .btn-primary {
10 | color: #fff;
11 | background-color: #1b6ec2;
12 | border-color: #1861ac;
13 | }
14 |
15 | .btn:focus, .btn:active:focus, .btn-link.nav-link:focus, .form-control:focus, .form-check-input:focus {
16 | box-shadow: 0 0 0 0.1rem white, 0 0 0 0.25rem #258cfb;
17 | }
18 |
19 | .content {
20 | padding-top: 1.1rem;
21 | }
22 |
23 | h1:focus {
24 | outline: none;
25 | }
26 |
27 | .valid.modified:not([type=checkbox]) {
28 | outline: 1px solid #26b050;
29 | }
30 |
31 | .invalid {
32 | outline: 1px solid #e50000;
33 | }
34 |
35 | .validation-message {
36 | color: #e50000;
37 | }
38 |
39 | .blazor-error-boundary {
40 | background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTYiIGhlaWdodD0iNDkiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIG92ZXJmbG93PSJoaWRkZW4iPjxkZWZzPjxjbGlwUGF0aCBpZD0iY2xpcDAiPjxyZWN0IHg9IjIzNSIgeT0iNTEiIHdpZHRoPSI1NiIgaGVpZ2h0PSI0OSIvPjwvY2xpcFBhdGg+PC9kZWZzPjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMCkiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yMzUgLTUxKSI+PHBhdGggZD0iTTI2My41MDYgNTFDMjY0LjcxNyA1MSAyNjUuODEzIDUxLjQ4MzcgMjY2LjYwNiA1Mi4yNjU4TDI2Ny4wNTIgNTIuNzk4NyAyNjcuNTM5IDUzLjYyODMgMjkwLjE4NSA5Mi4xODMxIDI5MC41NDUgOTIuNzk1IDI5MC42NTYgOTIuOTk2QzI5MC44NzcgOTMuNTEzIDI5MSA5NC4wODE1IDI5MSA5NC42NzgyIDI5MSA5Ny4wNjUxIDI4OS4wMzggOTkgMjg2LjYxNyA5OUwyNDAuMzgzIDk5QzIzNy45NjMgOTkgMjM2IDk3LjA2NTEgMjM2IDk0LjY3ODIgMjM2IDk0LjM3OTkgMjM2LjAzMSA5NC4wODg2IDIzNi4wODkgOTMuODA3MkwyMzYuMzM4IDkzLjAxNjIgMjM2Ljg1OCA5Mi4xMzE0IDI1OS40NzMgNTMuNjI5NCAyNTkuOTYxIDUyLjc5ODUgMjYwLjQwNyA1Mi4yNjU4QzI2MS4yIDUxLjQ4MzcgMjYyLjI5NiA1MSAyNjMuNTA2IDUxWk0yNjMuNTg2IDY2LjAxODNDMjYwLjczNyA2Ni4wMTgzIDI1OS4zMTMgNjcuMTI0NSAyNTkuMzEzIDY5LjMzNyAyNTkuMzEzIDY5LjYxMDIgMjU5LjMzMiA2OS44NjA4IDI1OS4zNzEgNzAuMDg4N0wyNjEuNzk1IDg0LjAxNjEgMjY1LjM4IDg0LjAxNjEgMjY3LjgyMSA2OS43NDc1QzI2Ny44NiA2OS43MzA5IDI2Ny44NzkgNjkuNTg3NyAyNjcuODc5IDY5LjMxNzkgMjY3Ljg3OSA2Ny4xMTgyIDI2Ni40NDggNjYuMDE4MyAyNjMuNTg2IDY2LjAxODNaTTI2My41NzYgODYuMDU0N0MyNjEuMDQ5IDg2LjA1NDcgMjU5Ljc4NiA4Ny4zMDA1IDI1OS43ODYgODkuNzkyMSAyNTkuNzg2IDkyLjI4MzcgMjYxLjA0OSA5My41Mjk1IDI2My41NzYgOTMuNTI5NSAyNjYuMTE2IDkzLjUyOTUgMjY3LjM4NyA5Mi4yODM3IDI2Ny4zODcgODkuNzkyMSAyNjcuMzg3IDg3LjMwMDUgMjY2LjExNiA4Ni4wNTQ3IDI2My41NzYgODYuMDU0N1oiIGZpbGw9IiNGRkU1MDAiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvZz48L3N2Zz4=) no-repeat 1rem/1.8rem, #b32121;
41 | padding: 1rem 1rem 1rem 3.7rem;
42 | color: white;
43 | }
44 |
45 | .blazor-error-boundary::after {
46 | content: "An error has occurred."
47 | }
48 |
49 | .darker-border-checkbox.form-check-input {
50 | border-color: #929292;
51 | }
52 |
--------------------------------------------------------------------------------
/samples/BlazorApp2/BlazorApp2/wwwroot/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fluxera/Fluxera.Extensions.Hosting/edb8d919e2a09af1c398dc8a2576790a3e9c689c/samples/BlazorApp2/BlazorApp2/wwwroot/favicon.png
--------------------------------------------------------------------------------
/samples/ConsoleApp1/ConsoleApp1.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net9.0
5 | Exe
6 | false
7 |
8 |
9 |
10 |
11 | PreserveNewest
12 | true
13 | PreserveNewest
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/samples/ConsoleApp1/ConsoleApp1Host.cs:
--------------------------------------------------------------------------------
1 | namespace ConsoleApp1
2 | {
3 | using Autofac.Extensions.DependencyInjection;
4 | using Fluxera.Extensions.Hosting;
5 | using Fluxera.Extensions.Hosting.Plugins;
6 | using JetBrains.Annotations;
7 | using Microsoft.Extensions.Configuration;
8 | using Microsoft.Extensions.Hosting;
9 | using Microsoft.Extensions.Logging;
10 | using Serilog;
11 | using Serilog.Extensions.Hosting;
12 | using Serilog.Extensions.Logging;
13 |
14 | [PublicAPI]
15 | [UsedImplicitly]
16 | internal sealed class ConsoleApp1Host : ConsoleApplicationHost // WindowsServiceApplicationHost
17 | {
18 | ///
19 | protected override void ConfigureApplicationPlugins(IPluginConfigurationContext context)
20 | {
21 | base.ConfigureApplicationPlugins(context);
22 | }
23 |
24 | ///
25 | protected override void ConfigureHostBuilder(IHostBuilder builder)
26 | {
27 | base.ConfigureHostBuilder(builder);
28 |
29 | // Use Autofac as default container.
30 | builder.UseServiceProviderFactory(new AutofacServiceProviderFactory());
31 |
32 | // Use Serilog as default logger.
33 | builder.UseSerilog((context, services, configuration) => configuration
34 | .Enrich.FromLogContext()
35 | .WriteTo.Console()
36 | .WriteTo.OpenTelemetry() // https://github.com/serilog/serilog-sinks-opentelemetry
37 | .ReadFrom.Configuration(context.Configuration)
38 | .ReadFrom.Services(services));
39 | }
40 |
41 | ///
42 | protected override ILoggerFactory CreateBootstrapperLoggerFactory(IConfiguration configuration)
43 | {
44 | ReloadableLogger bootstrapLogger = new LoggerConfiguration()
45 | .Enrich.FromLogContext()
46 | .WriteTo.Console()
47 | .WriteTo.OpenTelemetry() // https://github.com/serilog/serilog-sinks-opentelemetry
48 | .ReadFrom.Configuration(configuration)
49 | .CreateBootstrapLogger();
50 |
51 | ILoggerFactory loggerFactory = new SerilogLoggerFactory(bootstrapLogger);
52 | return loggerFactory;
53 | }
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/samples/ConsoleApp1/ConsoleApp1Module.cs:
--------------------------------------------------------------------------------
1 | namespace ConsoleApp1
2 | {
3 | using System.Globalization;
4 | using Fluxera.Extensions.Hosting;
5 | using Fluxera.Extensions.Hosting.Modules;
6 | using JetBrains.Annotations;
7 | using Microsoft.Extensions.DependencyInjection;
8 |
9 | [PublicAPI]
10 | [UsedImplicitly]
11 | internal sealed class ConsoleApp1Module : ConfigureApplicationModule
12 | {
13 | ///
14 | public override void ConfigureServices(IServiceConfigurationContext context)
15 | {
16 | CultureInfo.DefaultThreadCurrentCulture = CultureInfo.GetCultureInfo("de-DE");
17 | CultureInfo.DefaultThreadCurrentUICulture = CultureInfo.GetCultureInfo("de-DE");
18 |
19 | context.Services.AddHostedService();
20 | context.Services.AddSingleton();
21 | context.Services.AddOptions().Bind(context.Configuration.GetSection("Weather"));
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/samples/ConsoleApp1/ConsoleHostedService.cs:
--------------------------------------------------------------------------------
1 | namespace ConsoleApp1
2 | {
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Threading;
6 | using System.Threading.Tasks;
7 | using Microsoft.Extensions.Hosting;
8 | using Microsoft.Extensions.Logging;
9 |
10 | internal sealed class ConsoleHostedService : IHostedService
11 | {
12 | private readonly IHostApplicationLifetime appLifetime;
13 | private readonly ILogger logger;
14 | private readonly IWeatherService weatherService;
15 |
16 | private int? exitCode;
17 |
18 | public ConsoleHostedService(
19 | ILogger logger,
20 | IHostApplicationLifetime appLifetime,
21 | IWeatherService weatherService)
22 | {
23 | this.logger = logger;
24 | this.appLifetime = appLifetime;
25 | this.weatherService = weatherService;
26 | }
27 |
28 | public Task StartAsync(CancellationToken cancellationToken)
29 | {
30 | this.logger.LogDebug($"Starting with arguments: {string.Join(" ", Environment.GetCommandLineArgs())}");
31 |
32 | this.appLifetime.ApplicationStarted.Register(() =>
33 | {
34 | Task.Run(async () =>
35 | {
36 | try
37 | {
38 | IReadOnlyList temperatures = await this.weatherService.GetFiveDayTemperaturesAsync();
39 | for(int i = 0; i < temperatures.Count; i++)
40 | {
41 | this.logger.LogInformation($"{DateTime.Today.AddDays(i).DayOfWeek}: {temperatures[i]}");
42 | }
43 |
44 | this.exitCode = 0;
45 | }
46 | catch(Exception ex)
47 | {
48 | this.logger.LogError(ex, "Unhandled exception!");
49 | this.exitCode = 1;
50 | }
51 | finally
52 | {
53 | // Stop the application once the work is done
54 | this.appLifetime.StopApplication();
55 | }
56 | }, cancellationToken);
57 | });
58 |
59 | return Task.CompletedTask;
60 | }
61 |
62 | public Task StopAsync(CancellationToken cancellationToken)
63 | {
64 | this.logger.LogDebug($"Exiting with return code: {this.exitCode}");
65 |
66 | // Exit code may be null if the user cancelled via Ctrl+C/SIGTERM
67 | Environment.ExitCode = this.exitCode.GetValueOrDefault(-1);
68 | return Task.CompletedTask;
69 | }
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/samples/ConsoleApp1/IWeatherService.cs:
--------------------------------------------------------------------------------
1 | namespace ConsoleApp1
2 | {
3 | using System.Collections.Generic;
4 | using System.Threading.Tasks;
5 |
6 | internal interface IWeatherService
7 | {
8 | Task> GetFiveDayTemperaturesAsync();
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/samples/ConsoleApp1/Program.cs:
--------------------------------------------------------------------------------
1 | namespace ConsoleApp1
2 | {
3 | using System;
4 | using System.Threading.Tasks;
5 | using Fluxera.Extensions.Hosting;
6 |
7 | public static class Program
8 | {
9 | public static async Task Main(string[] args)
10 | {
11 | await ApplicationHost.RunAsync(args);
12 |
13 | Console.WriteLine();
14 | Console.WriteLine("Press any key to quit...");
15 | Console.ReadKey(true);
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/samples/ConsoleApp1/WeatherService.cs:
--------------------------------------------------------------------------------
1 | namespace ConsoleApp1
2 | {
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Threading.Tasks;
6 | using Microsoft.Extensions.Options;
7 |
8 | internal sealed class WeatherService : IWeatherService
9 | {
10 | private readonly IOptions weatherSettings;
11 |
12 | public WeatherService(IOptions weatherSettings)
13 | {
14 | this.weatherSettings = weatherSettings;
15 | }
16 |
17 | public Task> GetFiveDayTemperaturesAsync()
18 | {
19 | int[] temperatures = { 76, 76, 77, 79, 78 };
20 | if(this.weatherSettings.Value.Unit.Equals("C", StringComparison.OrdinalIgnoreCase))
21 | {
22 | for(int i = 0; i < temperatures.Length; i++)
23 | {
24 | temperatures[i] = (int)Math.Round((temperatures[i] - 32) / 1.8);
25 | }
26 | }
27 |
28 | return Task.FromResult>(temperatures);
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/samples/ConsoleApp1/WeatherSettings.cs:
--------------------------------------------------------------------------------
1 | namespace ConsoleApp1
2 | {
3 | internal sealed class WeatherSettings
4 | {
5 | public string Unit { get; set; }
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/samples/ConsoleApp1/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Trace",
5 | "Fluxera.Extensions.Hosting.ApplicationHost": "Trace",
6 | "Microsoft.Hosting.Lifetime": "Information"
7 | }
8 | },
9 | "Serilog": {
10 | "MinimumLevel": {
11 | "Default": "Verbose",
12 | "Fluxera.Extensions.Hosting.ApplicationHost": "Verbose",
13 | "Override": {
14 | "Microsoft": "Information",
15 | "System": "Warning",
16 | "Microsoft.Hosting.Lifetime": "Information"
17 | }
18 | }
19 | },
20 | "Weather": {
21 | "Unit": "C"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/samples/Directory.Build.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | latest
5 | disable
6 | disable
7 | false
8 | false
9 |
10 |
11 |
12 | Fluxera Software Development GmbH
13 | Fluxera Software Foundation
14 | Copyright © 2014-2024 Fluxera Software Development GmbH. All rights reserved.
15 |
16 |
17 |
--------------------------------------------------------------------------------
/samples/MauiApp1/App.xaml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/samples/MauiApp1/App.xaml.cs:
--------------------------------------------------------------------------------
1 | namespace MauiApp1
2 | {
3 | public partial class App : Application
4 | {
5 | public App()
6 | {
7 | this.InitializeComponent();
8 |
9 | this.MainPage = new AppShell();
10 | }
11 | }
12 | }
--------------------------------------------------------------------------------
/samples/MauiApp1/AppShell.xaml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
14 |
15 |
--------------------------------------------------------------------------------
/samples/MauiApp1/AppShell.xaml.cs:
--------------------------------------------------------------------------------
1 | namespace MauiApp1
2 | {
3 | public partial class AppShell : Shell
4 | {
5 | public AppShell()
6 | {
7 | this.InitializeComponent();
8 | }
9 | }
10 | }
--------------------------------------------------------------------------------
/samples/MauiApp1/MainPage.xaml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
10 |
15 |
16 |
20 |
21 |
26 |
27 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/samples/MauiApp1/MainPage.xaml.cs:
--------------------------------------------------------------------------------
1 | namespace MauiApp1
2 | {
3 | public partial class MainPage : ContentPage
4 | {
5 | private int count;
6 |
7 | public MainPage()
8 | {
9 | this.InitializeComponent();
10 | }
11 |
12 | private void OnCounterClicked(object sender, EventArgs e)
13 | {
14 | this.count++;
15 |
16 | this.CounterBtn.Text = this.count == 1
17 | ? $"Clicked {this.count} time"
18 | : $"Clicked {this.count} times";
19 |
20 | SemanticScreenReader.Announce(this.CounterBtn.Text);
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/samples/MauiApp1/MauiApp1Host.cs:
--------------------------------------------------------------------------------
1 | namespace MauiApp1
2 | {
3 | using CommunityToolkit.Maui;
4 | using Fluxera.Extensions.Hosting;
5 | using Microsoft.Extensions.Logging;
6 |
7 | public class MauiApp1Host : MauiApplicationHost
8 | {
9 | ///
10 | protected override void ConfigureHostBuilder(MauiAppBuilder builder)
11 | {
12 | base.ConfigureHostBuilder(builder);
13 |
14 | builder.ConfigureFonts(fonts =>
15 | {
16 | fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
17 | fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
18 | });
19 |
20 | // Register the MAUI community toolkit.
21 | builder.UseMauiCommunityToolkit();
22 | //builder.UseMauiCommunityToolkitMarkup();
23 | //builder.UseMauiCommunityToolkitMaps("key");
24 | //builder.UseMauiCommunityToolkitMediaElement();
25 |
26 | #if DEBUG
27 | builder.Logging.AddDebug();
28 | #endif
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/samples/MauiApp1/MauiApp1Module.cs:
--------------------------------------------------------------------------------
1 | namespace MauiApp1
2 | {
3 | using Fluxera.Extensions.Hosting;
4 | using Fluxera.Extensions.Hosting.Modules;
5 |
6 | public class MauiApp1Module : ConfigureApplicationModule
7 | {
8 | ///
9 | public override void ConfigureServices(IServiceConfigurationContext context)
10 | {
11 | context.Services.AddSingleton(Connectivity.Current);
12 | context.Services.AddSingleton();
13 | }
14 |
15 | ///
16 | public override void OnApplicationShutdown(IApplicationShutdownContext context)
17 | {
18 | base.OnApplicationShutdown(context);
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/samples/MauiApp1/MauiProgram.cs:
--------------------------------------------------------------------------------
1 | namespace MauiApp1
2 | {
3 | using Fluxera.Extensions.Hosting;
4 |
5 | public static class MauiProgram
6 | {
7 | public static MauiApp CreateMauiApp()
8 | {
9 | return MauiApplicationHost.BuildApplication();
10 | }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/samples/MauiApp1/Platforms/Android/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/samples/MauiApp1/Platforms/Android/MainActivity.cs:
--------------------------------------------------------------------------------
1 | namespace MauiApp1
2 | {
3 | using Android.App;
4 | using Android.Content.PM;
5 | using Android.OS;
6 |
7 | [Activity(Theme = "@style/Maui.SplashTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation | ConfigChanges.UiMode | ConfigChanges.ScreenLayout | ConfigChanges.SmallestScreenSize | ConfigChanges.Density)]
8 | public class MainActivity : MauiAppCompatActivity
9 | {
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/samples/MauiApp1/Platforms/Android/MainApplication.cs:
--------------------------------------------------------------------------------
1 | namespace MauiApp1
2 | {
3 | using Android.App;
4 | using Android.Runtime;
5 |
6 | [Application]
7 | public class MainApplication : MauiApplication
8 | {
9 | public MainApplication(IntPtr handle, JniHandleOwnership ownership)
10 | : base(handle, ownership)
11 | {
12 | }
13 |
14 | protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/samples/MauiApp1/Platforms/Android/Resources/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #512BD4
4 | #2B0B98
5 | #2B0B98
6 |
--------------------------------------------------------------------------------
/samples/MauiApp1/Platforms/MacCatalyst/AppDelegate.cs:
--------------------------------------------------------------------------------
1 | namespace MauiApp1
2 | {
3 | using Foundation;
4 |
5 | [Register("AppDelegate")]
6 | public class AppDelegate : MauiUIApplicationDelegate
7 | {
8 | protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/samples/MauiApp1/Platforms/MacCatalyst/Entitlements.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | com.apple.security.app-sandbox
8 |
9 |
10 | com.apple.security.network.client
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/samples/MauiApp1/Platforms/MacCatalyst/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | UIDeviceFamily
15 |
16 | 2
17 |
18 | UIRequiredDeviceCapabilities
19 |
20 | arm64
21 |
22 | UISupportedInterfaceOrientations
23 |
24 | UIInterfaceOrientationPortrait
25 | UIInterfaceOrientationLandscapeLeft
26 | UIInterfaceOrientationLandscapeRight
27 |
28 | UISupportedInterfaceOrientations~ipad
29 |
30 | UIInterfaceOrientationPortrait
31 | UIInterfaceOrientationPortraitUpsideDown
32 | UIInterfaceOrientationLandscapeLeft
33 | UIInterfaceOrientationLandscapeRight
34 |
35 | XSAppIconAssets
36 | Assets.xcassets/appicon.appiconset
37 |
38 |
39 |
--------------------------------------------------------------------------------
/samples/MauiApp1/Platforms/MacCatalyst/Program.cs:
--------------------------------------------------------------------------------
1 | namespace MauiApp1
2 | {
3 | using ObjCRuntime;
4 | using UIKit;
5 |
6 | public class Program
7 | {
8 | // This is the main entry point of the application.
9 | static void Main(string[] args)
10 | {
11 | // if you want to use a different Application Delegate class from "AppDelegate"
12 | // you can specify it here.
13 | UIApplication.Main(args, null, typeof(AppDelegate));
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/samples/MauiApp1/Platforms/Tizen/Main.cs:
--------------------------------------------------------------------------------
1 | namespace MauiApp1
2 | {
3 | using Microsoft.Maui;
4 | using Microsoft.Maui.Hosting;
5 | using System;
6 |
7 | internal class Program : MauiApplication
8 | {
9 | protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
10 |
11 | static void Main(string[] args)
12 | {
13 | var app = new Program();
14 | app.Run(args);
15 | }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/samples/MauiApp1/Platforms/Tizen/tizen-manifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | maui-application-title-placeholder
6 | maui-appicon-placeholder
7 |
8 |
9 |
10 |
11 | http://tizen.org/privilege/internet
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/samples/MauiApp1/Platforms/Windows/App.xaml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/samples/MauiApp1/Platforms/Windows/App.xaml.cs:
--------------------------------------------------------------------------------
1 | // To learn more about WinUI, the WinUI project structure,
2 | // and more about our project templates, see: http://aka.ms/winui-project-info.
3 |
4 | namespace MauiApp1.WinUI
5 | {
6 | using Microsoft.UI.Xaml;
7 |
8 | ///
9 | /// Provides application-specific behavior to supplement the default Application class.
10 | ///
11 | public partial class App : MauiWinUIApplication
12 | {
13 | ///
14 | /// Initializes the singleton application object. This is the first line of authored code
15 | /// executed, and as such is the logical equivalent of main() or WinMain().
16 | ///
17 | public App()
18 | {
19 | this.InitializeComponent();
20 | }
21 |
22 | protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
23 | }
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/samples/MauiApp1/Platforms/Windows/Package.appxmanifest:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | $placeholder$
15 | User Name
16 | $placeholder$.png
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/samples/MauiApp1/Platforms/Windows/app.manifest:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
11 | true/PM
12 | PerMonitorV2, PerMonitor
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/samples/MauiApp1/Platforms/iOS/AppDelegate.cs:
--------------------------------------------------------------------------------
1 | namespace MauiApp1
2 | {
3 | using Foundation;
4 |
5 | [Register("AppDelegate")]
6 | public class AppDelegate : MauiUIApplicationDelegate
7 | {
8 | protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/samples/MauiApp1/Platforms/iOS/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | LSRequiresIPhoneOS
6 |
7 | UIDeviceFamily
8 |
9 | 1
10 | 2
11 |
12 | UIRequiredDeviceCapabilities
13 |
14 | arm64
15 |
16 | UISupportedInterfaceOrientations
17 |
18 | UIInterfaceOrientationPortrait
19 | UIInterfaceOrientationLandscapeLeft
20 | UIInterfaceOrientationLandscapeRight
21 |
22 | UISupportedInterfaceOrientations~ipad
23 |
24 | UIInterfaceOrientationPortrait
25 | UIInterfaceOrientationPortraitUpsideDown
26 | UIInterfaceOrientationLandscapeLeft
27 | UIInterfaceOrientationLandscapeRight
28 |
29 | XSAppIconAssets
30 | Assets.xcassets/appicon.appiconset
31 |
32 |
33 |
--------------------------------------------------------------------------------
/samples/MauiApp1/Platforms/iOS/Program.cs:
--------------------------------------------------------------------------------
1 | namespace MauiApp1
2 | {
3 | using ObjCRuntime;
4 | using UIKit;
5 |
6 | public class Program
7 | {
8 | // This is the main entry point of the application.
9 | static void Main(string[] args)
10 | {
11 | // if you want to use a different Application Delegate class from "AppDelegate"
12 | // you can specify it here.
13 | UIApplication.Main(args, null, typeof(AppDelegate));
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/samples/MauiApp1/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "profiles": {
3 | "Windows Machine": {
4 | "commandName": "MsixPackage",
5 | "nativeDebugging": false
6 | }
7 | }
8 | }
--------------------------------------------------------------------------------
/samples/MauiApp1/Resources/AppIcon/appicon.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/samples/MauiApp1/Resources/AppIcon/appiconfg.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/samples/MauiApp1/Resources/Fonts/OpenSans-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fluxera/Fluxera.Extensions.Hosting/edb8d919e2a09af1c398dc8a2576790a3e9c689c/samples/MauiApp1/Resources/Fonts/OpenSans-Regular.ttf
--------------------------------------------------------------------------------
/samples/MauiApp1/Resources/Fonts/OpenSans-Semibold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fluxera/Fluxera.Extensions.Hosting/edb8d919e2a09af1c398dc8a2576790a3e9c689c/samples/MauiApp1/Resources/Fonts/OpenSans-Semibold.ttf
--------------------------------------------------------------------------------
/samples/MauiApp1/Resources/Images/dotnet_bot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fluxera/Fluxera.Extensions.Hosting/edb8d919e2a09af1c398dc8a2576790a3e9c689c/samples/MauiApp1/Resources/Images/dotnet_bot.png
--------------------------------------------------------------------------------
/samples/MauiApp1/Resources/Raw/AboutAssets.txt:
--------------------------------------------------------------------------------
1 | Any raw assets you want to be deployed with your application can be placed in
2 | this directory (and child directories). Deployment of the asset to your application
3 | is automatically handled by the following `MauiAsset` Build Action within your `.csproj`.
4 |
5 |
6 |
7 | These files will be deployed with you package and will be accessible using Essentials:
8 |
9 | async Task LoadMauiAsset()
10 | {
11 | using var stream = await FileSystem.OpenAppPackageFileAsync("AboutAssets.txt");
12 | using var reader = new StreamReader(stream);
13 |
14 | var contents = reader.ReadToEnd();
15 | }
16 |
--------------------------------------------------------------------------------
/samples/MauiApp1/Resources/Splash/splash.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/samples/MauiApp1/Resources/Styles/Colors.xaml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
8 |
9 | #512BD4
10 | #ac99ea
11 | #242424
12 | #DFD8F7
13 | #9880e5
14 | #2B0B98
15 |
16 | White
17 | Black
18 | #D600AA
19 | #190649
20 | #1f1f1f
21 |
22 | #E1E1E1
23 | #C8C8C8
24 | #ACACAC
25 | #919191
26 | #6E6E6E
27 | #404040
28 | #212121
29 | #141414
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/samples/TestProject1/TestApplication1Host.cs:
--------------------------------------------------------------------------------
1 | namespace TestProject1
2 | {
3 | using Fluxera.Extensions.Hosting;
4 | using WebApplication1;
5 |
6 | public class TestApplication1Host : TestApplicationHost
7 | {
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/samples/TestProject1/TestProject1.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net9.0
5 | false
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | all
16 | runtime; build; native; contentfiles; analyzers; buildtransitive
17 |
18 |
19 | all
20 | runtime; build; native; contentfiles; analyzers; buildtransitive
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/samples/TestProject1/Tests.cs:
--------------------------------------------------------------------------------
1 | namespace TestProject1
2 | {
3 | using System.Net;
4 | using System.Net.Http;
5 | using System.Threading.Tasks;
6 | using FluentAssertions;
7 | using Fluxera.Extensions.Hosting;
8 | using Microsoft.AspNetCore.TestHost;
9 | using Microsoft.Extensions.DependencyInjection;
10 | using NUnit.Framework;
11 |
12 | [TestFixture]
13 | public class Tests
14 | {
15 | private TestServer server;
16 |
17 | [SetUp]
18 | public async Task Setup()
19 | {
20 | this.server = await TestApplicationHost.RunAsync();
21 | }
22 |
23 | [TearDown]
24 | public void TearDown()
25 | {
26 | this.server?.Dispose();
27 | this.server = null;
28 | }
29 |
30 | [Test]
31 | public async Task ShouldExecuteController()
32 | {
33 | HttpClient httpClient = this.server.CreateClient();
34 | HttpResponseMessage response = await httpClient.GetAsync("/weatherforecast");
35 |
36 | response.StatusCode.Should().Be(HttpStatusCode.OK);
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/samples/WebApplication1/Controllers/WeatherForecastController.cs:
--------------------------------------------------------------------------------
1 | namespace WebApplication1.Controllers
2 | {
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using Microsoft.AspNetCore.Mvc;
7 | using Microsoft.Extensions.Logging;
8 |
9 | [ApiController]
10 | [Route("[controller]")]
11 | public class WeatherForecastController : ControllerBase
12 | {
13 | private static readonly string[] Summaries =
14 | {
15 | "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
16 | };
17 |
18 | private readonly ILogger _logger;
19 |
20 | public WeatherForecastController(ILogger logger)
21 | {
22 | this._logger = logger;
23 | }
24 |
25 | [HttpGet(Name = "GetWeatherForecast")]
26 | public IEnumerable Get()
27 | {
28 | return Enumerable.Range(1, 5).Select(index => new WeatherForecast
29 | {
30 | Date = DateTime.Now.AddDays(index),
31 | TemperatureC = Random.Shared.Next(-20, 55),
32 | Summary = Summaries[Random.Shared.Next(Summaries.Length)]
33 | })
34 | .ToArray();
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/samples/WebApplication1/Program.cs:
--------------------------------------------------------------------------------
1 | namespace WebApplication1
2 | {
3 | using System.Threading.Tasks;
4 | using Fluxera.Extensions.Hosting;
5 |
6 | public static class Program
7 | {
8 | public static async Task Main(string[] args)
9 | {
10 | await ApplicationHost.RunAsync(args);
11 | }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/samples/WebApplication1/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://json.schemastore.org/launchsettings.json",
3 | "profiles": {
4 | "WebApplication1": {
5 | "commandName": "Project",
6 | "dotnetRunMessages": true,
7 | "launchBrowser": false,
8 | "applicationUrl": "https://localhost:7001;http://localhost:7000",
9 | "environmentVariables": {
10 | "ASPNETCORE_ENVIRONMENT": "Development"
11 | }
12 | }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/samples/WebApplication1/WeatherForecast.cs:
--------------------------------------------------------------------------------
1 | namespace WebApplication1
2 | {
3 | using System;
4 |
5 | public class WeatherForecast
6 | {
7 | public DateTime Date { get; set; }
8 |
9 | public int TemperatureC { get; set; }
10 |
11 | public int TemperatureF => 32 + (int)(this.TemperatureC / 0.5556);
12 |
13 | public string Summary { get; set; }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/samples/WebApplication1/WebApplication1.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net9.0
5 | false
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/samples/WebApplication1/WebApplication1Host.cs:
--------------------------------------------------------------------------------
1 | namespace WebApplication1
2 | {
3 | using Fluxera.Extensions.Hosting;
4 |
5 | public class WebApplication1Host : WebApplicationHost
6 | {
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/samples/WebApplication1/WebApplication1Module.cs:
--------------------------------------------------------------------------------
1 | namespace WebApplication1
2 | {
3 | using System.Reflection;
4 | using Fluxera.Extensions.Hosting;
5 | using Fluxera.Extensions.Hosting.Modules;
6 | using Microsoft.AspNetCore.Builder;
7 | using Microsoft.Extensions.DependencyInjection;
8 |
9 | public sealed class WebApplication1Module : ConfigureApplicationModule
10 | {
11 | ///
12 | public override void ConfigureServices(IServiceConfigurationContext context)
13 | {
14 | context.Services.AddControllers();
15 | context.Services
16 | .AddMvc()
17 | .AddApplicationPart(Assembly.GetExecutingAssembly())
18 | .AddControllersAsServices();
19 | context.Services.AddHttpClient();
20 | }
21 |
22 | ///
23 | public override void Configure(IApplicationInitializationContext context)
24 | {
25 | IApplicationBuilder app = context.GetApplicationBuilder();
26 |
27 | app.UseRouting();
28 | app.UseEndpoints(builder =>
29 | {
30 | builder.MapControllers();
31 | });
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/samples/WebApplication1/appsettings.Development.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft.AspNetCore": "Warning"
6 | }
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/samples/WebApplication1/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft.AspNetCore": "Warning"
6 | }
7 | },
8 | "AllowedHosts": "*"
9 | }
10 |
--------------------------------------------------------------------------------
/samples/WpfApp1/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 |
3 | [assembly: ThemeInfo(
4 | ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
5 | //(used if a resource is not found in the page,
6 | // or application resource dictionaries)
7 | ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
8 | //(used if a resource is not found in the page,
9 | // app, or any theme specific resource dictionaries)
10 | )]
11 |
--------------------------------------------------------------------------------
/samples/WpfApp1/MainWindow.xaml:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/samples/WpfApp1/MainWindow.xaml.cs:
--------------------------------------------------------------------------------
1 | namespace WpfApp1
2 | {
3 | using System.Windows;
4 | using Fluxera.Extensions.Hosting;
5 |
6 | ///
7 | /// Interaction logic for MainWindow.xaml
8 | ///
9 | public partial class MainWindow : Window, IMainWindow
10 | {
11 | public MainWindow()
12 | {
13 | this.InitializeComponent();
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/samples/WpfApp1/Program.cs:
--------------------------------------------------------------------------------
1 | namespace WpfApp1
2 | {
3 | using System.Threading.Tasks;
4 | using Fluxera.Extensions.Hosting;
5 |
6 | public static class Program
7 | {
8 | public static async Task Main(string[] args)
9 | {
10 | //Application application = new Application
11 | //{
12 | // StartupUri = new Uri("MainWindow.xaml", UriKind.Relative)
13 | //};
14 | //application.Run();
15 |
16 | await ApplicationHost.RunAsync(args);
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/samples/WpfApp1/WpfApp1.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net9.0-windows
5 | false
6 | WinExe
7 | true
8 |
9 |
10 |
11 |
12 | PreserveNewest
13 | true
14 | PreserveNewest
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/samples/WpfApp1/WpfApp1Host.cs:
--------------------------------------------------------------------------------
1 | namespace WpfApp1
2 | {
3 | using Fluxera.Extensions.Hosting;
4 | using Microsoft.Extensions.Hosting;
5 |
6 | public class WpfApp1Host : WpfApplicationHost
7 | {
8 | ///
9 | protected override void ConfigureHostBuilder(IHostBuilder builder)
10 | {
11 | base.ConfigureHostBuilder(builder);
12 |
13 | // Register the main window factory to use.
14 | builder.UseMainWindow(serviceProvider => new MainWindow());
15 | }
16 |
17 | /////
18 | //protected override void ConfigureApplicationHostEvents(ApplicationHostEvents applicationHostEvents)
19 | //{
20 | // bool showSplash = !this.CommandLineArgs.Contains("--no-splash");
21 | // if(showSplash)
22 | // {
23 | // applicationHostEvents.HostCreating
24 | // }
25 | //}
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/samples/WpfApp1/WpfApp1Module.cs:
--------------------------------------------------------------------------------
1 | namespace WpfApp1
2 | {
3 | using Fluxera.Extensions.Hosting.Modules;
4 |
5 | public class WpfApp1Module : ConfigureServicesModule
6 | {
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/samples/WpfApp1/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Trace",
5 | "Fluxera.Extensions.Hosting.ApplicationHost": "Trace",
6 | "Microsoft.Hosting.Lifetime": "Information"
7 | }
8 | },
9 | "Serilog": {
10 | "MinimumLevel": {
11 | "Default": "Verbose",
12 | "Fluxera.Extensions.Hosting.ApplicationHost": "Verbose",
13 | "Override": {
14 | "Microsoft": "Information",
15 | "System": "Warning",
16 | "Microsoft.Hosting.Lifetime": "Information"
17 | }
18 | }
19 | },
20 | "Weather": {
21 | "Unit": "C"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/Directory.Build.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | latest
5 | disable
6 | disable
7 | true
8 | true
9 |
10 |
11 |
12 | $([System.DateTime]::UtcNow.Year)
13 |
14 |
15 |
16 | Fluxera Software Development GmbH
17 | Fluxera Software Foundation
18 | Copyright © 2014-$(CurrentYear) Fluxera Software Development GmbH. All rights reserved.
19 |
20 |
21 |
22 | Matthias Gernand
23 | https://github.com/fluxera/Fluxera.Extensions.Hosting
24 | https://github.com/fluxera/Fluxera.Extensions.Hosting
25 | icon.png
26 | README.md
27 | false
28 | false
29 | en
30 | git
31 | MIT
32 | true
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/src/Fluxera.Extensions.Hosting.Abstractions/ApplicationLoaderBuilderFunc.cs:
--------------------------------------------------------------------------------
1 | namespace Fluxera.Extensions.Hosting
2 | {
3 | using System;
4 | using System.Collections.Generic;
5 | using Fluxera.Extensions.Hosting.Modules;
6 | using Fluxera.Extensions.Hosting.Plugins;
7 | using Microsoft.Extensions.DependencyInjection;
8 |
9 | ///
10 | /// A function that builds and returns the
11 | /// from the given parameters.
12 | ///
13 | /// The startup module type.
14 | /// The service collection.
15 | /// The optional plugin sources.
16 | /// The modules.
17 | ///
18 | public delegate IApplicationLoader ApplicationLoaderBuilderFunc(
19 | Type startupModuleType,
20 | IServiceCollection services,
21 | IPluginSourceList pluginSources,
22 | IReadOnlyCollection modules);
23 | }
24 |
--------------------------------------------------------------------------------
/src/Fluxera.Extensions.Hosting.Abstractions/DependsOnAttribute.cs:
--------------------------------------------------------------------------------
1 | namespace Fluxera.Extensions.Hosting
2 | {
3 | using System;
4 | using Fluxera.Extensions.Hosting.Modules;
5 | using JetBrains.Annotations;
6 |
7 | ///
8 | /// Defines a dependency of a modules. Can be used multiple times on a module class.
9 | ///
10 | [PublicAPI]
11 | [MeansImplicitUse]
12 | [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
13 | public class DependsOnAttribute : DependsOnAttribute
14 | where TModule : class, IModule
15 | {
16 | ///
17 | /// Creates a new instance of the type.
18 | ///
19 | public DependsOnAttribute() : base(typeof(TModule))
20 | {
21 | }
22 | }
23 |
24 | ///
25 | /// Defines a dependency of a modules. Can be used multiple times on a module class.
26 | ///
27 | [PublicAPI]
28 | [MeansImplicitUse]
29 | [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
30 | public class DependsOnAttribute : Attribute
31 | {
32 | ///
33 | /// Creates a new instance of the type.
34 | ///
35 | ///
36 | public DependsOnAttribute(Type dependentModuleType)
37 | {
38 | this.DependentModuleType = dependentModuleType;
39 | }
40 |
41 | ///
42 | /// The type of the module the decorated module depends on.
43 | ///
44 | public Type DependentModuleType { get; }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/Fluxera.Extensions.Hosting.Abstractions/Fluxera.Extensions.Hosting.Abstractions.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net8.0;net9.0
5 |
6 |
7 |
8 | Fluxera.Extensions.Hosting.Abstractions
9 | The abstractions for the modular application host.
10 | library;extensions;hosting;modular
11 | $(MSBuildProjectName.Replace(" ", "_").Replace(".Abstractions",""))
12 |
13 |
14 |
15 |
16 | true
17 | \
18 |
19 |
20 | true
21 | \
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 | all
34 | runtime; build; native; contentfiles; analyzers; buildtransitive
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/src/Fluxera.Extensions.Hosting.Abstractions/IApplicationHost.cs:
--------------------------------------------------------------------------------
1 | namespace Fluxera.Extensions.Hosting
2 | {
3 | using System.Threading.Tasks;
4 | using JetBrains.Annotations;
5 |
6 | ///
7 | /// A contract for an application host.
8 | ///
9 | [PublicAPI]
10 | public interface IApplicationHost
11 | {
12 | ///
13 | /// Runs the host using the given command line arguments.
14 | ///
15 | /// The command line arguments.
16 | ///
17 | Task RunAsync(string[] args);
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/Fluxera.Extensions.Hosting.Abstractions/IApplicationInitializationContext.cs:
--------------------------------------------------------------------------------
1 | namespace Fluxera.Extensions.Hosting
2 | {
3 | using System;
4 | using JetBrains.Annotations;
5 | using Microsoft.Extensions.Configuration;
6 | using Microsoft.Extensions.Hosting;
7 |
8 | ///
9 | /// A contract for a context type that is available during the application
10 | /// initialization of modules. One service context instance is passed
11 | /// down the module list.
12 | ///
13 | [PublicAPI]
14 | public interface IApplicationInitializationContext : ILoggingContext
15 | {
16 | ///
17 | /// Gets the service provider.
18 | ///
19 | IServiceProvider ServiceProvider { get; }
20 |
21 | ///
22 | /// Gets the application configuration.
23 | ///
24 | IConfiguration Configuration { get; }
25 |
26 | ///
27 | /// Gets the environment the host runs under.
28 | ///
29 | IHostEnvironment Environment { get; }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/Fluxera.Extensions.Hosting.Abstractions/IApplicationLoader.cs:
--------------------------------------------------------------------------------
1 | namespace Fluxera.Extensions.Hosting
2 | {
3 | using System;
4 | using Fluxera.Extensions.Hosting.Modules;
5 | using Fluxera.Extensions.Hosting.Plugins;
6 | using JetBrains.Annotations;
7 | using Microsoft.Extensions.Configuration;
8 | using Microsoft.Extensions.DependencyInjection;
9 |
10 | ///
11 | /// A contract for a modular application loader which configures and loads
12 | /// the configured modules and plugins.
13 | ///
14 | [PublicAPI]
15 | public interface IApplicationLoader : IModuleContainer, IDisposable
16 | {
17 | ///
18 | /// Gets the type of the startup module.
19 | ///
20 | Type StartupModuleType { get; }
21 |
22 | ///
23 | /// Gets the service collection.
24 | ///
25 | IServiceCollection Services { get; }
26 |
27 | ///
28 | /// Gets the configuration of the application.
29 | ///
30 | IConfiguration Configuration { get; }
31 |
32 | ///
33 | /// Gets the plugin sources to use when loading modules.
34 | ///
35 | IPluginSourceList PluginSources { get; }
36 |
37 | ///
38 | /// Gets the service provider.
39 | ///
40 | IServiceProvider ServiceProvider { get; }
41 |
42 | ///
43 | /// Configure the services.
44 | ///
45 | void ConfigureServices();
46 |
47 | ///
48 | /// Initializes the application using the given context.
49 | ///
50 | ///
51 | /// See:
52 | ///
53 | ///
54 | void Initialize(IApplicationLoaderInitializationContext context);
55 |
56 | ///
57 | /// Gracefully shuts down the application.
58 | ///
59 | void Shutdown();
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/src/Fluxera.Extensions.Hosting.Abstractions/IApplicationLoaderInitializationContext.cs:
--------------------------------------------------------------------------------
1 | namespace Fluxera.Extensions.Hosting
2 | {
3 | using System;
4 | using JetBrains.Annotations;
5 |
6 | ///
7 | /// A contract for a context class that is passed in to the Initialize
8 | /// method of the application loader.
9 | ///
10 | ///
11 | /// Some host may need a special implementation, but n most cases the
12 | /// default implementation is sufficient.
13 | ///
14 | [PublicAPI]
15 | public interface IApplicationLoaderInitializationContext
16 | {
17 | ///
18 | /// Gets the service provider of the application.
19 | ///
20 | IServiceProvider ServiceProvider { get; }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/Fluxera.Extensions.Hosting.Abstractions/IApplicationShutdownContext.cs:
--------------------------------------------------------------------------------
1 | namespace Fluxera.Extensions.Hosting
2 | {
3 | using System;
4 | using JetBrains.Annotations;
5 | using Microsoft.Extensions.Configuration;
6 | using Microsoft.Extensions.Hosting;
7 |
8 | ///
9 | /// A contract for a context type that is available during the application
10 | /// shutdown of modules. One service context instance is passed down the module list.
11 | ///
12 | [PublicAPI]
13 | public interface IApplicationShutdownContext : ILoggingContext
14 | {
15 | ///
16 | /// Gets the service provider.
17 | ///
18 | IServiceProvider ServiceProvider { get; }
19 |
20 | ///
21 | /// Gets the application configuration.
22 | ///
23 | IConfiguration Configuration { get; }
24 |
25 | ///
26 | /// Gets the environment the host run under.
27 | ///
28 | IHostEnvironment Environment { get; }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/Fluxera.Extensions.Hosting.Abstractions/ILoggingContext.cs:
--------------------------------------------------------------------------------
1 | namespace Fluxera.Extensions.Hosting
2 | {
3 | using JetBrains.Annotations;
4 | using Microsoft.Extensions.Logging;
5 |
6 | ///
7 | /// A contract for a context that provides logging capabilities.
8 | ///
9 | [PublicAPI]
10 | public interface ILoggingContext : ILoggingContext
11 | where T : class
12 | {
13 | ///
14 | /// Gets the context data, f.e. IServiceCollection.
15 | ///
16 | internal T LogContextData { get; }
17 | }
18 |
19 | ///
20 | /// A contract for a context that provides logging capabilities.
21 | ///
22 | [PublicAPI]
23 | public interface ILoggingContext
24 | {
25 | ///
26 | /// Gets a logger.
27 | ///
28 | ILogger Logger { get; }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/Fluxera.Extensions.Hosting.Abstractions/IModularApplicationBuilder.cs:
--------------------------------------------------------------------------------
1 | namespace Fluxera.Extensions.Hosting
2 | {
3 | using Fluxera.Extensions.Hosting.Plugins;
4 | using JetBrains.Annotations;
5 |
6 | ///
7 | /// A contract for a service that configures the service and modules
8 | /// of the application and build the application loader instance.
9 | ///
10 | [PublicAPI]
11 | public interface IModularApplicationBuilder
12 | {
13 | ///
14 | /// Gets the plugin sources.
15 | ///
16 | IPluginSourceList PluginSources { get; }
17 |
18 | ///
19 | /// Builds the application loader using an optional loader factory function.
20 | ///
21 | ///
22 | ///
23 | IApplicationLoader Build(ApplicationLoaderBuilderFunc applicationLoaderFactory = null);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/Fluxera.Extensions.Hosting.Abstractions/IServiceConfigurationContext.cs:
--------------------------------------------------------------------------------
1 | namespace Fluxera.Extensions.Hosting
2 | {
3 | using System.Collections.Generic;
4 | using JetBrains.Annotations;
5 | using Microsoft.Extensions.Configuration;
6 | using Microsoft.Extensions.DependencyInjection;
7 | using Microsoft.Extensions.Hosting;
8 |
9 | ///
10 | /// A contract for a context type that is available during the service
11 | /// configuration of modules. One service context instance is passed
12 | /// down the module list.
13 | ///
14 | [PublicAPI]
15 | public interface IServiceConfigurationContext : ILoggingContext
16 | {
17 | ///
18 | /// Gets the service collection.
19 | ///
20 | IServiceCollection Services { get; }
21 |
22 | ///
23 | /// Gets the application configuration.
24 | ///
25 | IConfiguration Configuration { get; }
26 |
27 | ///
28 | /// Gets the environment to application runs under.
29 | ///
30 | IHostEnvironment Environment { get; }
31 |
32 | ///
33 | /// Gets additional items that can be passed down the module service configuration pipeline.
34 | /// This items are shared between modules during the service configuration phase.
35 | ///
36 | IDictionary Items { get; }
37 |
38 | ///
39 | /// Gets or sets named objects that can be stored during the service configuration phase
40 | /// and shared between modules. This is a shortcut usage of the
41 | /// dictionary. Returns null if given key is not found in the
42 | /// dictionary.
43 | ///
44 | /// The key.
45 | /// The stored object or null .
46 | object this[string key] { get; set; }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/src/Fluxera.Extensions.Hosting.Abstractions/Modules/ConfigureApplicationModule.cs:
--------------------------------------------------------------------------------
1 | namespace Fluxera.Extensions.Hosting.Modules
2 | {
3 | using JetBrains.Annotations;
4 |
5 | ///
6 | /// An abstract base class for implementing module classes that supports the
7 | /// configure services actions and also the application initialization and
8 | /// shutdown actions.
9 | ///
10 | [PublicAPI]
11 | public abstract class ConfigureApplicationModule : IConfigureServicesModule, IConfigureApplicationModule, IShutdownApplicationModule
12 | {
13 | ///
14 | public virtual void PreConfigure(IApplicationInitializationContext context)
15 | {
16 | }
17 |
18 | ///
19 | public virtual void Configure(IApplicationInitializationContext context)
20 | {
21 | }
22 |
23 | ///
24 | public virtual void PostConfigure(IApplicationInitializationContext context)
25 | {
26 | }
27 |
28 | ///
29 | public virtual void PreConfigureServices(IServiceConfigurationContext context)
30 | {
31 | }
32 |
33 | ///
34 | public virtual void ConfigureServices(IServiceConfigurationContext context)
35 | {
36 | }
37 |
38 | ///
39 | public virtual void PostConfigureServices(IServiceConfigurationContext context)
40 | {
41 | }
42 |
43 | ///
44 | public virtual void OnApplicationShutdown(IApplicationShutdownContext context)
45 | {
46 | }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/src/Fluxera.Extensions.Hosting.Abstractions/Modules/ConfigureServicesModule.cs:
--------------------------------------------------------------------------------
1 | namespace Fluxera.Extensions.Hosting.Modules
2 | {
3 | using JetBrains.Annotations;
4 |
5 | ///
6 | /// An abstract base class for modules that only support service configuration.
7 | ///
8 | [PublicAPI]
9 | public abstract class ConfigureServicesModule : IConfigureServicesModule
10 | {
11 | ///
12 | public virtual void PreConfigureServices(IServiceConfigurationContext context)
13 | {
14 | }
15 |
16 | ///
17 | public virtual void ConfigureServices(IServiceConfigurationContext context)
18 | {
19 | }
20 |
21 | ///
22 | public virtual void PostConfigureServices(IServiceConfigurationContext context)
23 | {
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/Fluxera.Extensions.Hosting.Abstractions/Modules/IConfigureApplication.cs:
--------------------------------------------------------------------------------
1 | namespace Fluxera.Extensions.Hosting.Modules
2 | {
3 | using JetBrains.Annotations;
4 |
5 | ///
6 | /// A contract for a module that supports the configure application action.
7 | ///
8 | [PublicAPI]
9 | public interface IConfigureApplication : IModule
10 | {
11 | ///
12 | /// This method is called after the pre-configure and before the
13 | /// post-configure actions.
14 | ///
15 | ///
16 | void Configure(IApplicationInitializationContext context);
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/Fluxera.Extensions.Hosting.Abstractions/Modules/IConfigureConfigureApplicationModule.cs:
--------------------------------------------------------------------------------
1 | namespace Fluxera.Extensions.Hosting.Modules
2 | {
3 | using JetBrains.Annotations;
4 |
5 | ///
6 | /// A contract for a module that supports the complete application initialization pipeline.
7 | ///
8 | [PublicAPI]
9 | public interface IConfigureApplicationModule : IPreConfigureApplication, IConfigureApplication, IPostConfigureApplication
10 | {
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/Fluxera.Extensions.Hosting.Abstractions/Modules/IConfigureServices.cs:
--------------------------------------------------------------------------------
1 | namespace Fluxera.Extensions.Hosting.Modules
2 | {
3 | using JetBrains.Annotations;
4 |
5 | ///
6 | /// A contract for a module that supports the configure services action.
7 | ///
8 | [PublicAPI]
9 | public interface IConfigureServices : IModule
10 | {
11 | ///
12 | /// Configures the service of teh module. It is executed after the
13 | /// pre-configure und before the post-configure service actions.
14 | ///
15 | /// The service configuration context.
16 | void ConfigureServices(IServiceConfigurationContext context);
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/Fluxera.Extensions.Hosting.Abstractions/Modules/IConfigureServicesModule.cs:
--------------------------------------------------------------------------------
1 | namespace Fluxera.Extensions.Hosting.Modules
2 | {
3 | using JetBrains.Annotations;
4 |
5 | ///
6 | /// A contract for a module that supports the complete service configuration pipeline.
7 | ///
8 | [PublicAPI]
9 | public interface IConfigureServicesModule : IPreConfigureServices, IConfigureServices, IPostConfigureServices
10 | {
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/Fluxera.Extensions.Hosting.Abstractions/Modules/IModule.cs:
--------------------------------------------------------------------------------
1 | namespace Fluxera.Extensions.Hosting.Modules
2 | {
3 | using JetBrains.Annotations;
4 |
5 | ///
6 | /// A marker interface for modules.
7 | ///
8 | [PublicAPI]
9 | public interface IModule
10 | {
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/Fluxera.Extensions.Hosting.Abstractions/Modules/IModuleContainer.cs:
--------------------------------------------------------------------------------
1 | namespace Fluxera.Extensions.Hosting.Modules
2 | {
3 | using System.Collections.Generic;
4 | using JetBrains.Annotations;
5 |
6 | ///
7 | /// A contract for a container holding the
8 | /// instances of loader modules.
9 | ///
10 | [PublicAPI]
11 | public interface IModuleContainer
12 | {
13 | ///
14 | /// Gets the descriptors of the loaded modules.
15 | ///
16 | IReadOnlyCollection Modules { get; }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/Fluxera.Extensions.Hosting.Abstractions/Modules/IModuleDescriptor.cs:
--------------------------------------------------------------------------------
1 | namespace Fluxera.Extensions.Hosting.Modules
2 | {
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Reflection;
6 | using JetBrains.Annotations;
7 |
8 | ///
9 | /// A contract for a module descriptor that provides meta data of a module.
10 | ///
11 | [PublicAPI]
12 | public interface IModuleDescriptor
13 | {
14 | ///
15 | /// The type of the module class.
16 | ///
17 | Type Type { get; }
18 |
19 | ///
20 | /// The assembly the module is located in.
21 | ///
22 | Assembly Assembly { get; }
23 |
24 | ///
25 | /// The module instance itself.
26 | ///
27 | IModule Instance { get; }
28 |
29 | ///
30 | /// Flag, indicating if the module was loaded as a plugin.
31 | ///
32 | bool IsLoadedAsPlugin { get; }
33 |
34 | ///
35 | /// The dependent module descriptors.
36 | ///
37 | IReadOnlyCollection Dependencies { get; }
38 |
39 | ///
40 | /// Gets the name of the module.
41 | ///
42 | string Name { get; }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/Fluxera.Extensions.Hosting.Abstractions/Modules/IModuleLifecycleContributor.cs:
--------------------------------------------------------------------------------
1 | namespace Fluxera.Extensions.Hosting.Modules
2 | {
3 | using JetBrains.Annotations;
4 |
5 | ///
6 | /// A contract for a class that delegates the application lifecycle
7 | /// actions to the given modules.
8 | ///
9 | [PublicAPI]
10 | public interface IModuleLifecycleContributor
11 | {
12 | ///
13 | /// This method is called when the application initialization starts.
14 | ///
15 | ///
16 | ///
17 | void Initialize(IApplicationInitializationContext context, IModule module);
18 |
19 | ///
20 | /// This method is called when the application shuts down.
21 | ///
22 | ///
23 | ///
24 | void Shutdown(IApplicationShutdownContext context, IModule module);
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/Fluxera.Extensions.Hosting.Abstractions/Modules/IModuleLoader.cs:
--------------------------------------------------------------------------------
1 | namespace Fluxera.Extensions.Hosting.Modules
2 | {
3 | using System;
4 | using System.Collections.Generic;
5 | using Fluxera.Extensions.Hosting.Plugins;
6 | using JetBrains.Annotations;
7 | using Microsoft.Extensions.DependencyInjection;
8 |
9 | ///
10 | /// A contract for a service that loads modules.
11 | ///
12 | [PublicAPI]
13 | public interface IModuleLoader
14 | {
15 | ///
16 | /// Loads all modules starting with the given startup module and
17 | /// then loading its dependencies.
18 | ///
19 | ///
20 | ///
21 | ///
22 | ///
23 | IReadOnlyCollection LoadModules(Type startupModuleType, IServiceCollection services, IPluginSourceList pluginSources);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/Fluxera.Extensions.Hosting.Abstractions/Modules/IModuleManager.cs:
--------------------------------------------------------------------------------
1 | namespace Fluxera.Extensions.Hosting.Modules
2 | {
3 | using JetBrains.Annotations;
4 |
5 | ///
6 | /// A contract for manager service that controls the startup and
7 | /// shutdown of the application's modules.
8 | ///
9 | [PublicAPI]
10 | public interface IModuleManager
11 | {
12 | ///
13 | /// Initialize all available modules.
14 | ///
15 | ///
16 | void InitializeModules(IApplicationInitializationContext context);
17 |
18 | ///
19 | /// Shutdown all available modules.
20 | ///
21 | ///
22 | void ShutdownModules(IApplicationShutdownContext context);
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/Fluxera.Extensions.Hosting.Abstractions/Modules/IPostConfigureApplication.cs:
--------------------------------------------------------------------------------
1 | namespace Fluxera.Extensions.Hosting.Modules
2 | {
3 | using JetBrains.Annotations;
4 |
5 | ///
6 | /// A contract for a module that supports the post-configure action.
7 | ///
8 | [PublicAPI]
9 | public interface IPostConfigureApplication : IModule
10 | {
11 | ///
12 | /// This method is called after the actual configure action.
13 | ///
14 | ///
15 | void PostConfigure(IApplicationInitializationContext context);
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/Fluxera.Extensions.Hosting.Abstractions/Modules/IPostConfigureServices.cs:
--------------------------------------------------------------------------------
1 | namespace Fluxera.Extensions.Hosting.Modules
2 | {
3 | using JetBrains.Annotations;
4 |
5 | ///
6 | /// A contract for a module that supports the post-configure services action.
7 | ///
8 | [PublicAPI]
9 | public interface IPostConfigureServices : IModule
10 | {
11 | ///
12 | /// Executed after the actual configure services action.
13 | ///
14 | /// The service configuration context.
15 | void PostConfigureServices(IServiceConfigurationContext context);
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/Fluxera.Extensions.Hosting.Abstractions/Modules/IPreConfigureApplication.cs:
--------------------------------------------------------------------------------
1 | namespace Fluxera.Extensions.Hosting.Modules
2 | {
3 | using JetBrains.Annotations;
4 |
5 | ///
6 | /// A contract for a module that supports the pre-configure action.
7 | ///
8 | [PublicAPI]
9 | public interface IPreConfigureApplication : IModule
10 | {
11 | ///
12 | /// This method is called before the actual configure action.
13 | ///
14 | ///
15 | void PreConfigure(IApplicationInitializationContext context);
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/Fluxera.Extensions.Hosting.Abstractions/Modules/IPreConfigureServices.cs:
--------------------------------------------------------------------------------
1 | namespace Fluxera.Extensions.Hosting.Modules
2 | {
3 | using JetBrains.Annotations;
4 |
5 | ///
6 | /// A contract for a module that supports the pre-configure services action.
7 | ///
8 | [PublicAPI]
9 | public interface IPreConfigureServices : IModule
10 | {
11 | ///
12 | /// Executed before the actual configure services action.
13 | ///
14 | /// The service configuration context.
15 | void PreConfigureServices(IServiceConfigurationContext context);
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/Fluxera.Extensions.Hosting.Abstractions/Modules/IShutdownApplicationModule.cs:
--------------------------------------------------------------------------------
1 | namespace Fluxera.Extensions.Hosting.Modules
2 | {
3 | using JetBrains.Annotations;
4 |
5 | ///
6 | /// A contract for a module that supports the application shutdown action.
7 | ///
8 | [PublicAPI]
9 | public interface IShutdownApplicationModule : IModule
10 | {
11 | ///
12 | /// This method is called when the application shuts down.
13 | ///
14 | ///
15 | void OnApplicationShutdown(IApplicationShutdownContext context);
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/Fluxera.Extensions.Hosting.Abstractions/ObjectAccessorLifetime.cs:
--------------------------------------------------------------------------------
1 | namespace Fluxera.Extensions.Hosting
2 | {
3 | using Fluxera.Extensions.DependencyInjection;
4 | using JetBrains.Annotations;
5 |
6 | ///
7 | /// A custom object accessor context that is used to control the lifetime of an object in ser service collection.
8 | ///
9 | [PublicAPI]
10 | public sealed class ObjectAccessorLifetime
11 | {
12 | ///
13 | /// The object accessor will only be available while configuring the services.
14 | ///
15 | public static ObjectAccessorContext ConfigureServices = new ObjectAccessorContext("ConfigureServices");
16 |
17 | ///
18 | /// The object accessor will be available while configuring the services and the application.
19 | ///
20 | public static ObjectAccessorContext Configure = new ObjectAccessorContext("Configure");
21 |
22 | ///
23 | /// The object accessor will be available at any time over the lifetime of the application.
24 | ///
25 | public static ObjectAccessorContext Application = new ObjectAccessorContext("Application");
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/Fluxera.Extensions.Hosting.Abstractions/Plugins/IPluginConfigurationContext.cs:
--------------------------------------------------------------------------------
1 | namespace Fluxera.Extensions.Hosting.Plugins
2 | {
3 | using JetBrains.Annotations;
4 | using Microsoft.Extensions.Configuration;
5 | using Microsoft.Extensions.Hosting;
6 |
7 | ///
8 | /// A contract for a context type that is given to the plugin module configuration.
9 | ///
10 | [PublicAPI]
11 | public interface IPluginConfigurationContext : ILoggingContext
12 | {
13 | ///
14 | /// The list of plugin sources. One may add additional sources to configure
15 | /// the usage of plugins. use the extensions available for .
16 | ///
17 | IPluginSourceList PluginSources { get; }
18 |
19 | ///
20 | /// Gets the configuration of the application.
21 | ///
22 | IConfiguration Configuration { get; }
23 |
24 | ///
25 | /// Gets the environment the application runs under.
26 | ///
27 | IHostEnvironment Environment { get; }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/Fluxera.Extensions.Hosting.Abstractions/Plugins/IPluginSource.cs:
--------------------------------------------------------------------------------
1 | namespace Fluxera.Extensions.Hosting.Plugins
2 | {
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Reflection;
6 | using Fluxera.Extensions.Hosting.Modules;
7 | using JetBrains.Annotations;
8 |
9 | ///
10 | /// A contract for a plugin source.
11 | ///
12 | [PublicAPI]
13 | public interface IPluginSource
14 | {
15 | ///
16 | /// Gets the assemblies of the types.
17 | ///
18 | ///
19 | IEnumerable GetAssemblies();
20 |
21 | ///
22 | /// Gets the types.
23 | ///
24 | ///
25 | IEnumerable GetModules();
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/Fluxera.Extensions.Hosting.Abstractions/Plugins/IPluginSourceList.cs:
--------------------------------------------------------------------------------
1 | namespace Fluxera.Extensions.Hosting.Plugins
2 | {
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Reflection;
6 | using Fluxera.Extensions.Hosting.Modules;
7 | using JetBrains.Annotations;
8 |
9 | ///
10 | /// A contract for providing plugin module types.
11 | ///
12 | [PublicAPI]
13 | public interface IPluginSourceList : ICollection
14 | {
15 | ///
16 | /// Gets the assemblies that contain types from
17 | /// all available instances.
18 | ///
19 | ///
20 | internal IEnumerable GetAllAssemblies();
21 |
22 | ///
23 | /// Gets all types from all available
24 | /// instances including their dependencies.
25 | ///
26 | ///
27 | internal IEnumerable GetAllModules();
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/Fluxera.Extensions.Hosting.AspNetCore.TestHost/Fluxera.Extensions.Hosting.AspNetCore.TestHost.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net8.0;net9.0
5 |
6 |
7 |
8 | Fluxera.Extensions.Hosting.AspNetCore.TestHost
9 | A modular application host for the ASP.NET test host.
10 | library;extensions;hosting;modular;aspnet;testserver
11 | $(MSBuildProjectName.Replace(" ", "_").Replace(".AspNetCore.TestHost",""))
12 |
13 |
14 |
15 |
16 | true
17 | \
18 |
19 |
20 | true
21 | \
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 | all
32 | runtime; build; native; contentfiles; analyzers; buildtransitive
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/src/Fluxera.Extensions.Hosting.AspNetCore.TestHost/ITestApplicationHost.cs:
--------------------------------------------------------------------------------
1 | namespace Fluxera.Extensions.Hosting
2 | {
3 | using JetBrains.Annotations;
4 | using Microsoft.AspNetCore.TestHost;
5 |
6 | ///
7 | /// A contract for a test host.
8 | ///
9 | [PublicAPI]
10 | public interface ITestApplicationHost : IApplicationHost
11 | {
12 | ///
13 | /// Gets the test server instance.
14 | ///
15 | TestServer Server { get; }
16 | }
17 | }
--------------------------------------------------------------------------------
/src/Fluxera.Extensions.Hosting.AspNetCore/ApplicationInitializationContextExtensions.cs:
--------------------------------------------------------------------------------
1 | namespace Fluxera.Extensions.Hosting
2 | {
3 | using JetBrains.Annotations;
4 | using Microsoft.AspNetCore.Builder;
5 |
6 | ///
7 | /// Extension methods on the type.
8 | ///
9 | [PublicAPI]
10 | public static class ApplicationInitializationContextExtensions
11 | {
12 | ///
13 | /// Gets the from the .
14 | ///
15 | ///
16 | ///
17 | public static IApplicationBuilder GetApplicationBuilder(this IApplicationInitializationContext context)
18 | {
19 | WebApplicationInitializationContext webContext = (WebApplicationInitializationContext)context;
20 | return webContext.ApplicationBuilder;
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/Fluxera.Extensions.Hosting.AspNetCore/ApplicationLoaderBuilderFuncFactory.cs:
--------------------------------------------------------------------------------
1 | namespace Fluxera.Extensions.Hosting
2 | {
3 | internal static class ApplicationLoaderBuilderFuncFactory
4 | {
5 | public static readonly ApplicationLoaderBuilderFunc CreateApplication = (startupModuleType, services, pluginSources, modules) =>
6 | {
7 | IApplicationLoader application = new WebApplicationLoader(startupModuleType, services, pluginSources, modules);
8 | return application;
9 | };
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/Fluxera.Extensions.Hosting.AspNetCore/Fluxera.Extensions.Hosting.AspNetCore.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net8.0;net9.0
5 |
6 |
7 |
8 | Fluxera.Extensions.Hosting.AspNetCore
9 | A modular application host for ASP.NET.
10 | library;extensions;hosting;modular;aspnet
11 | $(MSBuildProjectName.Replace(" ", "_").Replace(".AspNetCore",""))
12 |
13 |
14 |
15 |
16 | true
17 | \
18 |
19 |
20 | true
21 | \
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 | all
36 | runtime; build; native; contentfiles; analyzers; buildtransitive
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/src/Fluxera.Extensions.Hosting.AspNetCore/ServiceCollectionExtensions.cs:
--------------------------------------------------------------------------------
1 | namespace Fluxera.Extensions.Hosting
2 | {
3 | using JetBrains.Annotations;
4 | using Microsoft.AspNetCore.Mvc.Infrastructure;
5 | using Microsoft.Extensions.DependencyInjection;
6 | using Microsoft.Extensions.DependencyInjection.Extensions;
7 |
8 | ///
9 | /// Extension methods for the type.
10 | ///
11 | [PublicAPI]
12 | public static class ServiceCollectionExtensions
13 | {
14 | ///
15 | /// Adds a default implementation for the service.
16 | ///
17 | /// The .
18 | /// The service collection.
19 | public static IServiceCollection AddActionContextAccessor(this IServiceCollection services)
20 | {
21 | Guard.ThrowIfNull(services);
22 |
23 | services.TryAddSingleton();
24 | return services;
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/Fluxera.Extensions.Hosting.AspNetCore/WebApplicationHost.cs:
--------------------------------------------------------------------------------
1 | namespace Fluxera.Extensions.Hosting
2 | {
3 | using System.Collections.Generic;
4 | using Fluxera.Extensions.Hosting.Modules;
5 | using JetBrains.Annotations;
6 | using Microsoft.AspNetCore.Builder;
7 | using Microsoft.Extensions.DependencyInjection;
8 | using Microsoft.Extensions.Hosting;
9 |
10 | ///
11 | /// An abstract base class for web host applications.
12 | ///
13 | ///
14 | [PublicAPI]
15 | public abstract class WebApplicationHost : ApplicationHost
16 | where TStartupModule : class, IModule
17 | {
18 | private WebApplicationBuilder webApplicationBuilder;
19 |
20 | ///
21 | protected sealed override ApplicationLoaderBuilderFunc ApplicationLoaderBuilder => ApplicationLoaderBuilderFuncFactory.CreateApplication;
22 |
23 | ///
24 | protected override IEnumerable HostConfigurationEnvironmentVariablesPrefixes
25 | {
26 | get
27 | {
28 | foreach(string prefix in base.HostConfigurationEnvironmentVariablesPrefixes)
29 | {
30 | yield return prefix;
31 | }
32 |
33 | yield return "ASPNETCORE_";
34 | }
35 | }
36 |
37 | ///
38 | protected override IHostBuilder CreateHostBuilder()
39 | {
40 | // Create the host builder and configure it.
41 | this.webApplicationBuilder = WebApplication.CreateBuilder(this.CommandLineArgs);
42 | return this.webApplicationBuilder.Host;
43 | }
44 |
45 | ///
46 | protected override IHost BuildHost()
47 | {
48 | // Build the host.
49 | return this.webApplicationBuilder.Build();
50 | }
51 |
52 | ///
53 | protected override void InitializeApplicationLoader(IHost host)
54 | {
55 | WebApplication webHost = (WebApplication)host;
56 | IApplicationLoader applicationLoader = host.Services.GetRequiredService();
57 | applicationLoader.Initialize(new WebApplicationLoaderInitializationContext(webHost));
58 | }
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/src/Fluxera.Extensions.Hosting.AspNetCore/WebApplicationInitializationContext.cs:
--------------------------------------------------------------------------------
1 | namespace Fluxera.Extensions.Hosting
2 | {
3 | using System;
4 | using Microsoft.AspNetCore.Builder;
5 | using Microsoft.Extensions.Configuration;
6 | using Microsoft.Extensions.DependencyInjection;
7 | using Microsoft.Extensions.Hosting;
8 | using Microsoft.Extensions.Logging;
9 |
10 | internal sealed class WebApplicationInitializationContext : IApplicationInitializationContext
11 | {
12 | public WebApplicationInitializationContext(IApplicationBuilder applicationBuilder)
13 | {
14 | Guard.ThrowIfNull(applicationBuilder);
15 |
16 | this.ApplicationBuilder = applicationBuilder;
17 | this.ServiceProvider = applicationBuilder.ApplicationServices;
18 |
19 | this.Configuration = this.ServiceProvider.GetRequiredService();
20 | this.Environment = this.ServiceProvider.GetRequiredService();
21 | ILoggerFactory loggerFactory = this.ServiceProvider.GetRequiredService();
22 | this.Logger = loggerFactory.CreateLogger(ApplicationHost.LoggerName);
23 | }
24 |
25 | public IApplicationBuilder ApplicationBuilder { get; }
26 |
27 | ///
28 | public IServiceProvider ServiceProvider { get; }
29 |
30 | ///
31 | public IConfiguration Configuration { get; }
32 |
33 | ///
34 | public IHostEnvironment Environment { get; }
35 |
36 | ///
37 | public ILogger Logger { get; }
38 |
39 | ///
40 | IServiceProvider ILoggingContext.LogContextData => this.ServiceProvider;
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/Fluxera.Extensions.Hosting.AspNetCore/WebApplicationLoader.cs:
--------------------------------------------------------------------------------
1 | namespace Fluxera.Extensions.Hosting
2 | {
3 | using System;
4 | using System.Collections.Generic;
5 | using Fluxera.Extensions.Hosting.Modules;
6 | using Fluxera.Extensions.Hosting.Plugins;
7 | using Microsoft.Extensions.DependencyInjection;
8 |
9 | ///
10 | /// A specialized for web applications.
11 | ///
12 | internal sealed class WebApplicationLoader : ApplicationLoader
13 | {
14 | private WebApplicationLoaderInitializationContext webContext;
15 |
16 | public WebApplicationLoader(
17 | Type startupModuleType,
18 | IServiceCollection services,
19 | IPluginSourceList pluginSources,
20 | IReadOnlyCollection modules)
21 | : base(startupModuleType, services, pluginSources, modules)
22 | {
23 | }
24 |
25 | ///
26 | public override void Initialize(IApplicationLoaderInitializationContext context)
27 | {
28 | this.webContext = (WebApplicationLoaderInitializationContext)context;
29 |
30 | base.Initialize(context);
31 | }
32 |
33 | protected override IApplicationInitializationContext CreateApplicationInitializationContext(IServiceProvider serviceProvider)
34 | {
35 | return new WebApplicationInitializationContext(this.webContext.ApplicationBuilder);
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/Fluxera.Extensions.Hosting.AspNetCore/WebApplicationLoaderInitializationContext.cs:
--------------------------------------------------------------------------------
1 | namespace Fluxera.Extensions.Hosting
2 | {
3 | using Microsoft.AspNetCore.Builder;
4 |
5 | internal sealed class WebApplicationLoaderInitializationContext : ApplicationLoaderInitializationContext
6 | {
7 | public WebApplicationLoaderInitializationContext(IApplicationBuilder applicationBuilder)
8 | : base(applicationBuilder.ApplicationServices)
9 | {
10 | this.ApplicationBuilder = applicationBuilder;
11 | }
12 |
13 | public IApplicationBuilder ApplicationBuilder { get; }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/Fluxera.Extensions.Hosting.Blazor/ConsoleOutLoggerFactory.cs:
--------------------------------------------------------------------------------
1 | namespace Fluxera.Extensions.Hosting
2 | {
3 | using System;
4 | using Microsoft.Extensions.Logging;
5 |
6 | internal sealed class ConsoleOutLoggerFactory : ILoggerFactory
7 | {
8 | private readonly ILoggerProvider loggerProvider;
9 |
10 | public ConsoleOutLoggerFactory()
11 | {
12 | this.loggerProvider = new ConsoleOutLoggerProvider();
13 | }
14 |
15 | ///
16 | public ILogger CreateLogger(string categoryName)
17 | {
18 | return this.loggerProvider.CreateLogger(categoryName);
19 | }
20 |
21 | ///
22 | public void AddProvider(ILoggerProvider provider)
23 | {
24 | throw new NotImplementedException();
25 | }
26 |
27 | ///
28 | public void Dispose()
29 | {
30 | this.loggerProvider.Dispose();
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/Fluxera.Extensions.Hosting.Blazor/ConsoleOutLoggerProvider.cs:
--------------------------------------------------------------------------------
1 | namespace Fluxera.Extensions.Hosting
2 | {
3 | using Microsoft.Extensions.Logging;
4 |
5 | internal sealed class ConsoleOutLoggerProvider : ILoggerProvider
6 | {
7 | ///
8 | public ILogger CreateLogger(string categoryName)
9 | {
10 | return new ConsoleOutLogger(categoryName);
11 | }
12 |
13 | ///
14 | public void Dispose()
15 | {
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/Fluxera.Extensions.Hosting.Blazor/Fluxera.Extensions.Hosting.Blazor.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net8.0;net9.0
5 |
6 |
7 |
8 | Fluxera.Extensions.Hosting.Blazor
9 | A modular application host for Blazor.
10 | library;extensions;hosting;modular;blazor
11 | $(MSBuildProjectName.Replace(" ", "_").Replace(".Blazor",""))
12 |
13 |
14 |
15 |
16 | true
17 | \
18 |
19 |
20 | true
21 | \
22 |
23 |
24 |
25 |
26 |
27 | all
28 | runtime; build; native; contentfiles; analyzers; buildtransitive
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/src/Fluxera.Extensions.Hosting.Blazor/WebAssemblyLifetime.cs:
--------------------------------------------------------------------------------
1 | namespace Fluxera.Extensions.Hosting
2 | {
3 | using System.Threading;
4 | using System.Threading.Tasks;
5 | using Microsoft.Extensions.Hosting;
6 |
7 | internal sealed class WebAssemblyLifetime : IHostLifetime
8 | {
9 | ///
10 | public Task WaitForStartAsync(CancellationToken cancellationToken)
11 | {
12 | // Wasm applications start immediately.
13 | return Task.CompletedTask;
14 | }
15 |
16 | ///
17 | public Task StopAsync(CancellationToken cancellationToken)
18 | {
19 | // There's nothing to do here.
20 | return Task.CompletedTask;
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/Fluxera.Extensions.Hosting.Console/ConsoleApplicationHost.cs:
--------------------------------------------------------------------------------
1 | namespace Fluxera.Extensions.Hosting
2 | {
3 | using System;
4 | using Fluxera.Extensions.Hosting.Modules;
5 | using JetBrains.Annotations;
6 | using Microsoft.Extensions.Hosting;
7 |
8 | ///
9 | /// An abstract base class for console application hosts.
10 | ///
11 | /// The startup module type.
12 | [PublicAPI]
13 | public abstract class ConsoleApplicationHost : ApplicationHost
14 | where TStartupModule : class, IModule
15 | {
16 | ///
17 | protected override void ConfigureHostBuilder(IHostBuilder builder)
18 | {
19 | // Configure the content root to use.
20 | builder.UseContentRoot(Environment.CurrentDirectory);
21 |
22 | // Configure to use the console lifetime.
23 | builder.UseConsoleLifetime();
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/Fluxera.Extensions.Hosting.Console/Fluxera.Extensions.Hosting.Console.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net8.0;net9.0
5 |
6 |
7 |
8 | Fluxera.Extensions.Hosting.Console
9 | A modular application host for console applications.
10 | library;extensions;hosting;modular;console
11 | $(MSBuildProjectName.Replace(" ", "_").Replace(".Console",""))
12 |
13 |
14 |
15 |
16 | true
17 | \
18 |
19 |
20 | true
21 | \
22 |
23 |
24 |
25 |
26 |
27 | all
28 | runtime; build; native; contentfiles; analyzers; buildtransitive
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/src/Fluxera.Extensions.Hosting.Maui/Fluxera.Extensions.Hosting.Maui.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net9.0
5 |
6 | true
7 | true
8 | 1701;1702;NETSDK1023
9 |
10 |
11 |
12 | Fluxera.Extensions.Hosting.Maui
13 | A modular application host for .NET MAUI.
14 | library;extensions;hosting;modular;maui
15 | $(MSBuildProjectName.Replace(" ", "_").Replace(".Maui",""))
16 |
17 |
18 |
19 |
20 | true
21 | \
22 |
23 |
24 | true
25 | \
26 |
27 |
28 |
29 |
30 |
31 | all
32 | runtime; build; native; contentfiles; analyzers; buildtransitive
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/src/Fluxera.Extensions.Hosting.Maui/IMauiApplicationHost.cs:
--------------------------------------------------------------------------------
1 | namespace Fluxera.Extensions.Hosting
2 | {
3 | using JetBrains.Annotations;
4 | using Microsoft.Maui.Hosting;
5 |
6 | ///
7 | /// A contract for an MAUI application host.
8 | ///
9 | [PublicAPI]
10 | public interface IMauiApplicationHost
11 | {
12 | ///
13 | /// Builds the MAUI app instance.
14 | ///
15 | ///
16 | internal MauiApp Build();
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/Fluxera.Extensions.Hosting.WindowsService/Fluxera.Extensions.Hosting.WindowsService.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net8.0;net9.0
5 | win7-x64
6 |
7 |
8 |
9 | Fluxera.Extensions.Hosting.WindowsService
10 | A modular application host for windows service applications.
11 | library;extensions;hosting;modular;windowsservice
12 | $(MSBuildProjectName.Replace(" ", "_").Replace(".WindowsService",""))
13 |
14 |
15 |
16 |
17 | true
18 | \
19 |
20 |
21 | true
22 | \
23 |
24 |
25 |
26 |
27 |
28 | all
29 | runtime; build; native; contentfiles; analyzers; buildtransitive
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/src/Fluxera.Extensions.Hosting.WindowsService/WindowsServiceApplicationHost.cs:
--------------------------------------------------------------------------------
1 | namespace Fluxera.Extensions.Hosting
2 | {
3 | using System;
4 | using System.Diagnostics;
5 | using System.Linq;
6 | using Fluxera.Extensions.Hosting.Modules;
7 | using JetBrains.Annotations;
8 | using Microsoft.Extensions.Hosting;
9 |
10 | ///
11 | /// An abstract base class for windows service application hosts.
12 | ///
13 | /// The startup module type.
14 | [PublicAPI]
15 | public abstract class WindowsServiceApplicationHost : ApplicationHost
16 | where TStartupModule : class, IModule
17 | {
18 | ///
19 | protected override void ConfigureHostBuilder(IHostBuilder builder)
20 | {
21 | bool isService = !(Debugger.IsAttached || this.CommandLineArgs.Contains("--console"));
22 |
23 | // Configure the content root to use.
24 | builder.UseContentRoot(Environment.CurrentDirectory);
25 |
26 | if(isService)
27 | {
28 | // Configure to use the windows service lifetime.
29 | builder.UseWindowsService();
30 | }
31 | else
32 | {
33 | // Configure to use the console lifetime.
34 | builder.UseConsoleLifetime();
35 | }
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/Fluxera.Extensions.Hosting.Wpf/ApplicationExtensions.cs:
--------------------------------------------------------------------------------
1 | namespace Fluxera.Extensions.Hosting
2 | {
3 | using System;
4 | using System.Windows;
5 | using JetBrains.Annotations;
6 |
7 | ///
8 | /// Extensions methods on the type.
9 | ///
10 | [PublicAPI]
11 | public static class ApplicationExtensions
12 | {
13 | ///
14 | /// Adds a for the given resource.
15 | ///
16 | ///
17 | ///
18 | ///
19 | public static Application AddResourceDictionary(this Application application, Uri resource)
20 | {
21 | ResourceDictionary resourceDictionary = new ResourceDictionary
22 | {
23 | Source = resource
24 | };
25 | application.Resources.MergedDictionaries.Add(resourceDictionary);
26 |
27 | return application;
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/Fluxera.Extensions.Hosting.Wpf/DictionaryExtensions.cs:
--------------------------------------------------------------------------------
1 | namespace Fluxera.Extensions.Hosting
2 | {
3 | using System.Collections.Generic;
4 |
5 | internal static class DictionaryExtensions
6 | {
7 | ///
8 | /// Helper method to retrieve a context from the host builder properties.
9 | ///
10 | public static bool TryRetrieveContext(this IDictionary properties,
11 | string contextKey, out TContext context)
12 | where TContext : class, new()
13 | {
14 | if(properties.TryGetValue(contextKey, out object value))
15 | {
16 | context = (TContext)value;
17 | return true;
18 | }
19 |
20 | context = new TContext();
21 | properties[contextKey] = context;
22 | return false;
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/Fluxera.Extensions.Hosting.Wpf/Fluxera.Extensions.Hosting.Wpf.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net8.0-windows;net9.0-windows
5 | true
6 |
7 |
8 |
9 | Fluxera.Extensions.Hosting.Wpf
10 | A modular application host for WPF.
11 | library;extensions;hosting;modular;wpf
12 | $(MSBuildProjectName.Replace(" ", "_").Replace(".Wpf",""))
13 |
14 |
15 |
16 |
17 | true
18 | \
19 |
20 |
21 | true
22 | \
23 |
24 |
25 |
26 |
27 |
28 | all
29 | runtime; build; native; contentfiles; analyzers; buildtransitive
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/src/Fluxera.Extensions.Hosting.Wpf/HostBuilderExtensions.cs:
--------------------------------------------------------------------------------
1 | namespace Fluxera.Extensions.Hosting
2 | {
3 | using System;
4 | using System.Windows;
5 | using JetBrains.Annotations;
6 | using Microsoft.Extensions.DependencyInjection;
7 | using Microsoft.Extensions.Hosting;
8 |
9 | ///
10 | /// Extension methods to configure the WFP host.
11 | ///
12 | [PublicAPI]
13 | public static class HostBuilderExtensions
14 | {
15 | ///
16 | /// Configures the main to use for the application.
17 | ///
18 | /// The type of the main window.
19 | /// The host builder.
20 | /// The factory function that creates the main window instance.
21 | ///
22 | public static IHostBuilder UseMainWindow(this IHostBuilder hostBuilder, Func mainWindowFactory)
23 | where TMainWindow : Window, IMainWindow
24 | {
25 | hostBuilder.ConfigureServices(services =>
26 | {
27 | services.AddSingleton(mainWindowFactory.Invoke);
28 | });
29 |
30 | return hostBuilder;
31 | }
32 |
33 | ///
34 | /// Configures the host to use the lifetime implementation.
35 | ///
36 | /// The host builder.
37 | /// The shutdown mode the application should use.
38 | ///
39 | ///
40 | public static IHostBuilder UseWpfApplicationLifetime(this IHostBuilder hostBuilder, ShutdownMode shutdownMode)
41 | {
42 | // Configure the WPF lifetime.
43 | hostBuilder.ConfigureServices((context, services) =>
44 | {
45 | if(!context.Properties.TryRetrieveContext(WpfContext.ContextKey, out WpfContext wpfContext))
46 | {
47 | throw new InvalidOperationException("The WPF defaults need to be configured.");
48 | }
49 |
50 | services.AddSingleton();
51 |
52 | wpfContext.ShutdownMode = shutdownMode;
53 | });
54 |
55 | return hostBuilder;
56 | }
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/src/Fluxera.Extensions.Hosting.Wpf/IMainWindow.cs:
--------------------------------------------------------------------------------
1 | namespace Fluxera.Extensions.Hosting
2 | {
3 | using JetBrains.Annotations;
4 |
5 | ///
6 | /// A contract for the main window of a WPF application.
7 | ///
8 | [PublicAPI]
9 | public interface IMainWindow
10 | {
11 | ///
12 | /// Shows the main window.
13 | ///
14 | void Show();
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/Fluxera.Extensions.Hosting.Wpf/IWpfApplicationInitializer.cs:
--------------------------------------------------------------------------------
1 | namespace Fluxera.Extensions.Hosting
2 | {
3 | using System.Windows;
4 | using JetBrains.Annotations;
5 |
6 | ///
7 | /// This defines a service which is called before the message loop is started.
8 | ///
9 | [PublicAPI]
10 | public interface IWpfApplicationInitializer
11 | {
12 | ///
13 | /// Do whatever you need to do to initialize WPF, this is called from the UI thread.
14 | ///
15 | /// Application
16 | void Initialize(Application application);
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/Fluxera.Extensions.Hosting.Wpf/LoggerExtensions.cs:
--------------------------------------------------------------------------------
1 | namespace Fluxera.Extensions.Hosting
2 | {
3 | using System.Diagnostics;
4 | using Microsoft.Extensions.Logging;
5 |
6 | internal static partial class LoggerExtensions
7 | {
8 | [DebuggerStepThrough]
9 | [LoggerMessage(0, LogLevel.Information, "Hosting environment: {EnvironmentName}.")]
10 | public static partial void LogEnvironment(this ILogger logger, string environmentName);
11 |
12 | [DebuggerStepThrough]
13 | [LoggerMessage(0, LogLevel.Information, "Content root path: {ContentRootPath}.")]
14 | public static partial void LogContentRootPath(this ILogger logger, string contentRootPath);
15 |
16 | [DebuggerStepThrough]
17 | [LoggerMessage(0, LogLevel.Debug, "Application started.")]
18 | public static partial void LogApplicationStarted(this ILogger logger);
19 |
20 | [DebuggerStepThrough]
21 | [LoggerMessage(0, LogLevel.Debug, "Application is stopping ...")]
22 | public static partial void LogApplicationStopping(this ILogger logger);
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/Fluxera.Extensions.Hosting.Wpf/WpfApplicationHost.cs:
--------------------------------------------------------------------------------
1 | namespace Fluxera.Extensions.Hosting
2 | {
3 | using System.Windows;
4 | using Fluxera.Extensions.Hosting.Modules;
5 | using JetBrains.Annotations;
6 | using Microsoft.Extensions.DependencyInjection;
7 | using Microsoft.Extensions.Hosting;
8 |
9 | ///
10 | /// An abstract base class for WPF application hosts.
11 | ///
12 | /// The type of the startup module.
13 | [PublicAPI]
14 | public abstract class WpfApplicationHost : ApplicationHost
15 | where TStartupModule : class, IModule
16 | {
17 | ///
18 | protected override void ConfigureHostBuilder(IHostBuilder builder)
19 | {
20 | base.ConfigureHostBuilder(builder);
21 |
22 | // Configure the WPF context, hosted service and UI thread.
23 | builder.ConfigureServices((context, services) =>
24 | {
25 | // Only execute if no context exists in the properties.
26 | // The context is implicitly created and added to the properties.
27 | if(!context.Properties.TryRetrieveContext(WpfContext.ContextKey, out WpfContext wpfContext))
28 | {
29 | services.AddSingleton(wpfContext);
30 | }
31 | });
32 |
33 | // Configure the WPF lifetime.
34 | builder.UseWpfApplicationLifetime(ShutdownMode.OnMainWindowClose);
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/Fluxera.Extensions.Hosting.Wpf/WpfApplicationLifetimeOptions.cs:
--------------------------------------------------------------------------------
1 | namespace Fluxera.Extensions.Hosting
2 | {
3 | ///
4 | /// Provides lifetime options for the WPF application.
5 | ///
6 | public sealed class WpfApplicationLifetimeOptions
7 | {
8 | ///
9 | /// Creates a new instance of the type.
10 | ///
11 | public WpfApplicationLifetimeOptions()
12 | {
13 | this.SuppressStatusMessages = false;
14 | }
15 |
16 | ///
17 | /// Flag, if the status messages should be suppressed.
18 | ///
19 | public bool SuppressStatusMessages { get; }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/Fluxera.Extensions.Hosting.Wpf/WpfContext.cs:
--------------------------------------------------------------------------------
1 | namespace Fluxera.Extensions.Hosting
2 | {
3 | using System.Windows;
4 | using System.Windows.Threading;
5 |
6 | internal sealed class WpfContext
7 | {
8 | internal const string ContextKey = "WpfContext";
9 |
10 | public Dispatcher Dispatcher => this.Application.Dispatcher;
11 |
12 | public ShutdownMode ShutdownMode { get; set; } = ShutdownMode.OnLastWindowClose;
13 |
14 | public Application Application { get; set; }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/Fluxera.Extensions.Hosting/ApplicationHostEvents.cs:
--------------------------------------------------------------------------------
1 | namespace Fluxera.Extensions.Hosting
2 | {
3 | using System;
4 |
5 | ///
6 | /// A class that provides several events that provide feedback of the host creation cycle.
7 | ///
8 | public sealed class ApplicationHostEvents : IDisposable
9 | {
10 | ///
11 | public void Dispose()
12 | {
13 | this.HostCreating = null;
14 | this.HostCreated = null;
15 | this.HostCreationFailed = null;
16 | }
17 |
18 | ///
19 | /// An event that is raised before the host is created.
20 | ///
21 | public event EventHandler HostCreating;
22 |
23 | ///
24 | /// An event that is raised after the host was created.
25 | ///
26 | public event EventHandler HostCreated;
27 |
28 | ///
29 | /// An event that is raised, if the host creation failed.
30 | ///
31 | public event EventHandler HostCreationFailed;
32 |
33 | ///
34 | /// Raise the event.
35 | ///
36 | public void OnHostCreating()
37 | {
38 | this.HostCreating?.Invoke(null, EventArgs.Empty);
39 | }
40 |
41 | ///
42 | /// Raise the event.
43 | ///
44 | public void OnHostCreated()
45 | {
46 | this.HostCreated?.Invoke(null, EventArgs.Empty);
47 | }
48 |
49 | ///
50 | /// Raise the event.
51 | ///
52 | ///
53 | public void OnHostCreationFailed(Exception exception)
54 | {
55 | this.HostCreationFailed?.Invoke(null, new HostInitializationFailedEventArgs(exception));
56 | }
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/src/Fluxera.Extensions.Hosting/ApplicationInitializationContext.cs:
--------------------------------------------------------------------------------
1 | namespace Fluxera.Extensions.Hosting
2 | {
3 | using System;
4 | using Microsoft.Extensions.Configuration;
5 | using Microsoft.Extensions.DependencyInjection;
6 | using Microsoft.Extensions.Hosting;
7 | using Microsoft.Extensions.Logging;
8 |
9 | internal class ApplicationInitializationContext : IApplicationInitializationContext
10 | {
11 | public ApplicationInitializationContext(IServiceProvider serviceProvider)
12 | {
13 | Guard.ThrowIfNull(serviceProvider);
14 |
15 | this.ServiceProvider = serviceProvider;
16 | this.Configuration = this.ServiceProvider.GetRequiredService();
17 | this.Environment = this.ServiceProvider.GetRequiredService();
18 | ILoggerFactory loggerFactory = this.ServiceProvider.GetRequiredService();
19 | this.Logger = loggerFactory.CreateLogger(ApplicationHost.LoggerName);
20 | }
21 |
22 | ///
23 | public IServiceProvider ServiceProvider { get; }
24 |
25 | ///
26 | public IConfiguration Configuration { get; }
27 |
28 | ///
29 | public IHostEnvironment Environment { get; }
30 |
31 | ///
32 | public ILogger Logger { get; }
33 |
34 | ///
35 | IServiceProvider ILoggingContext.LogContextData => this.ServiceProvider;
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/Fluxera.Extensions.Hosting/ApplicationLoaderInitializationContext.cs:
--------------------------------------------------------------------------------
1 | namespace Fluxera.Extensions.Hosting
2 | {
3 | using System;
4 |
5 | ///
6 | /// The default implementation.
7 | ///
8 | public class ApplicationLoaderInitializationContext : IApplicationLoaderInitializationContext
9 | {
10 | ///
11 | /// Creates a new instance of the type.
12 | ///
13 | ///
14 | public ApplicationLoaderInitializationContext(IServiceProvider serviceProvider)
15 | {
16 | this.ServiceProvider = serviceProvider;
17 | }
18 |
19 | ///
20 | public IServiceProvider ServiceProvider { get; }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/Fluxera.Extensions.Hosting/ApplicationShutdownContext.cs:
--------------------------------------------------------------------------------
1 | namespace Fluxera.Extensions.Hosting
2 | {
3 | using System;
4 | using Microsoft.Extensions.Configuration;
5 | using Microsoft.Extensions.DependencyInjection;
6 | using Microsoft.Extensions.Hosting;
7 | using Microsoft.Extensions.Logging;
8 |
9 | internal sealed class ApplicationShutdownContext : IApplicationShutdownContext
10 | {
11 | public ApplicationShutdownContext(IServiceProvider serviceProvider)
12 | {
13 | Guard.ThrowIfNull(serviceProvider);
14 |
15 | this.ServiceProvider = serviceProvider;
16 |
17 | this.Configuration = this.ServiceProvider.GetRequiredService();
18 | this.Environment = this.ServiceProvider.GetRequiredService();
19 | ILoggerFactory loggerFactory = this.ServiceProvider.GetRequiredService();
20 | this.Logger = loggerFactory.CreateLogger(ApplicationHost.LoggerName);
21 | }
22 |
23 | public IServiceProvider ServiceProvider { get; }
24 |
25 | ///
26 | public IConfiguration Configuration { get; }
27 |
28 | ///
29 | public IHostEnvironment Environment { get; }
30 |
31 | ///
32 | public ILogger Logger { get; }
33 |
34 | ///
35 | IServiceProvider ILoggingContext.LogContextData => this.ServiceProvider;
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/Fluxera.Extensions.Hosting/CollectionExtensions.cs:
--------------------------------------------------------------------------------
1 | namespace Fluxera.Extensions.Hosting
2 | {
3 | using System.Collections.Generic;
4 |
5 | internal static class CollectionExtensions
6 | {
7 | ///
8 | /// Adds an item to the collection if it's not already in the collection.
9 | ///
10 | /// The collection
11 | /// Item to check and add
12 | /// Type of the items in the collection
13 | /// Returns True if added, returns False if not.
14 | public static bool AddIfNotContains(this ICollection collection, T item)
15 | {
16 | Guard.ThrowIfNull(collection);
17 |
18 | if(collection.Contains(item))
19 | {
20 | return false;
21 | }
22 |
23 | collection.Add(item);
24 | return true;
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/Fluxera.Extensions.Hosting/Fluxera.Extensions.Hosting.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net8.0;net9.0
5 |
6 |
7 |
8 | Fluxera.Extensions.Hosting
9 | A modular application host.
10 | library;extensions;hosting;modular
11 |
12 |
13 |
14 |
15 | true
16 | \
17 |
18 |
19 | true
20 | \
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 | all
38 | runtime; build; native; contentfiles; analyzers; buildtransitive
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/src/Fluxera.Extensions.Hosting/HostEnvironmentExtensions.cs:
--------------------------------------------------------------------------------
1 | namespace Fluxera.Extensions.Hosting
2 | {
3 | using JetBrains.Annotations;
4 | using Microsoft.Extensions.Hosting;
5 |
6 | ///
7 | /// Extension methods for the type.
8 | ///
9 | [PublicAPI]
10 | public static class HostEnvironmentExtensions
11 | {
12 | private static readonly string Testing = "Testing";
13 |
14 | ///
15 | /// Checks if the current host environment name is .
16 | ///
17 | /// An instance of .
18 | /// True if the environment name is , otherwise false.
19 | public static bool IsTesting(this IHostEnvironment hostEnvironment)
20 | {
21 | hostEnvironment = Guard.ThrowIfNull(hostEnvironment);
22 |
23 | return hostEnvironment.IsEnvironment(Testing);
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/Fluxera.Extensions.Hosting/HostInitializationFailedEventArgs.cs:
--------------------------------------------------------------------------------
1 | namespace Fluxera.Extensions.Hosting
2 | {
3 | using System;
4 | using JetBrains.Annotations;
5 |
6 | ///
7 | /// Event args that provide the exception that occurred when the host initialization failed.
8 | ///
9 | [PublicAPI]
10 | public sealed class HostInitializationFailedEventArgs : EventArgs
11 | {
12 | ///
13 | /// Creates a new instance of the type.
14 | ///
15 | /// The exception.
16 | public HostInitializationFailedEventArgs(Exception exception)
17 | {
18 | this.Exception = exception;
19 | }
20 |
21 | ///
22 | /// Gets the exception.
23 | ///
24 | public Exception Exception { get; }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/Fluxera.Extensions.Hosting/LoggerExtensions.cs:
--------------------------------------------------------------------------------
1 | namespace Fluxera.Extensions.Hosting
2 | {
3 | using System;
4 | using System.Diagnostics;
5 | using JetBrains.Annotations;
6 | using Microsoft.Extensions.Logging;
7 |
8 | [PublicAPI]
9 | internal static partial class LoggerExtensions
10 | {
11 | [DebuggerStepThrough]
12 | [LoggerMessage(0, LogLevel.Information, "Host configuration starting.")]
13 | public static partial void LogHostConfigurationStarting(this ILogger logger);
14 |
15 | [DebuggerStepThrough]
16 | [LoggerMessage(0, LogLevel.Information, "Running host using {HostLifetime}.")]
17 | public static partial void LogHostLifetime(this ILogger logger, string hostLifetime);
18 |
19 | [DebuggerStepThrough]
20 | [LoggerMessage(0, LogLevel.Information, "Host configured in {Duration} ms.")]
21 | public static partial void LogHostConfigurationDuration(this ILogger logger, long duration);
22 |
23 | [DebuggerStepThrough]
24 | [LoggerMessage(0, LogLevel.Critical, "Application terminated unexpectedly.")]
25 | public static partial void LogHostTerminatedUnexpectedly(this ILogger logger, Exception exception);
26 |
27 | [DebuggerStepThrough]
28 | [LoggerMessage(0, LogLevel.Debug, "Executing service configuration {CallerMemberName}: {MethodName}")]
29 | internal static partial void LogServiceConfiguration(this ILogger logger, string callerMemberName, string methodName);
30 |
31 | [DebuggerStepThrough]
32 | [LoggerMessage(0, LogLevel.Error, "An error occurred trying to invoke the service configuration.")]
33 | internal static partial void LogServiceConfigurationError(this ILogger logger, Exception exception);
34 |
35 | [DebuggerStepThrough]
36 | [LoggerMessage(0, LogLevel.Information, "Loaded module: {Module}")]
37 | internal static partial void LogLoadedModule(this ILogger logger, string module);
38 |
39 | [DebuggerStepThrough]
40 | [LoggerMessage(0, LogLevel.Debug, "Initialized all modules.")]
41 | internal static partial void LogModulesInitialized(this ILogger logger);
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/Fluxera.Extensions.Hosting/ModuleHelper.cs:
--------------------------------------------------------------------------------
1 | namespace Fluxera.Extensions.Hosting
2 | {
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Reflection;
6 | using Fluxera.Extensions.Hosting.Modules;
7 |
8 | internal static class ModuleHelper
9 | {
10 | public static IEnumerable FindAllModuleTypes(Type startupModuleType)
11 | {
12 | IList moduleTypes = new List();
13 | AddModuleAndDependenciesRecursive(moduleTypes, startupModuleType);
14 | return moduleTypes;
15 | }
16 |
17 | private static void CheckModuleType(Type moduleType)
18 | {
19 | if(!IsModule(moduleType))
20 | {
21 | throw new ArgumentException($"Given type is not a module: {moduleType.AssemblyQualifiedName}.");
22 | }
23 | }
24 |
25 | public static IEnumerable FindDependedModuleTypes(Type moduleType)
26 | {
27 | CheckModuleType(moduleType);
28 |
29 | IList dependencies = new List();
30 |
31 | IEnumerable dependencyAttributes = moduleType.GetCustomAttributes(true);
32 | foreach(DependsOnAttribute dependencyAttribute in dependencyAttributes)
33 | {
34 | if(!dependencies.Contains(dependencyAttribute.DependentModuleType))
35 | {
36 | dependencies.Add(dependencyAttribute.DependentModuleType);
37 | }
38 | }
39 |
40 | return dependencies;
41 | }
42 |
43 | public static bool IsModule(Type type)
44 | {
45 | TypeInfo typeInfo = type.GetTypeInfo();
46 |
47 | return
48 | typeInfo.IsClass &&
49 | !typeInfo.IsAbstract &&
50 | typeof(IModule).GetTypeInfo().IsAssignableFrom(type);
51 | }
52 |
53 | private static void AddModuleAndDependenciesRecursive(ICollection moduleTypes, Type moduleType)
54 | {
55 | CheckModuleType(moduleType);
56 |
57 | if(moduleTypes.Contains(moduleType))
58 | {
59 | return;
60 | }
61 |
62 | moduleTypes.Add(moduleType);
63 |
64 | foreach(Type dependedModuleType in FindDependedModuleTypes(moduleType))
65 | {
66 | AddModuleAndDependenciesRecursive(moduleTypes, dependedModuleType);
67 | }
68 | }
69 |
70 | internal static IList FindDependedModuleTypesRecursiveIncludingGivenModule(Type moduleType)
71 | {
72 | IList list = new List();
73 | AddModuleAndDependenciesRecursive(list, moduleType);
74 | return list;
75 | }
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/src/Fluxera.Extensions.Hosting/ModuleLifecycleContributorBase.cs:
--------------------------------------------------------------------------------
1 | namespace Fluxera.Extensions.Hosting
2 | {
3 | using Fluxera.Extensions.Hosting.Modules;
4 |
5 | internal abstract class ModuleLifecycleContributorBase : IModuleLifecycleContributor
6 | {
7 | public virtual void Initialize(IApplicationInitializationContext context, IModule module)
8 | {
9 | }
10 |
11 | public virtual void Shutdown(IApplicationShutdownContext context, IModule module)
12 | {
13 | }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/Fluxera.Extensions.Hosting/ModuleLoaderExtensions.cs:
--------------------------------------------------------------------------------
1 | namespace Fluxera.Extensions.Hosting
2 | {
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using Fluxera.Extensions.DependencyInjection;
6 | using Fluxera.Extensions.Hosting.Modules;
7 | using Microsoft.Extensions.DependencyInjection;
8 |
9 | internal static class ModuleLoaderExtensions
10 | {
11 | private const string PreviousModuleKey = "PreviousModule";
12 |
13 | public static void ConfigureServices(this IReadOnlyCollection modules, IServiceCollection services)
14 | {
15 | ServiceConfigurationContext context = new ServiceConfigurationContext(services);
16 |
17 | // PreConfigureServices
18 | context.Items.Remove(PreviousModuleKey);
19 | foreach(IModuleDescriptor module in modules.Where(m => m.Instance is IPreConfigureServices))
20 | {
21 | ((IPreConfigureServices)module.Instance).PreConfigureServices(context);
22 | context.Items[PreviousModuleKey] = module.Type.FullName;
23 | }
24 |
25 | // ConfigureServices
26 | context.Items.Remove(PreviousModuleKey);
27 | foreach(IModuleDescriptor module in modules.Where(m => m.Instance is IConfigureServices))
28 | {
29 | ((IConfigureServices)module.Instance).ConfigureServices(context);
30 | context.Items[PreviousModuleKey] = module.Type.FullName;
31 | }
32 |
33 | // PostConfigureServices
34 | context.Items.Remove(PreviousModuleKey);
35 | foreach(IModuleDescriptor module in modules.Where(m => m.Instance is IPostConfigureServices))
36 | {
37 | ((IPostConfigureServices)module.Instance).PostConfigureServices(context);
38 | context.Items[PreviousModuleKey] = module.Type.FullName;
39 | }
40 |
41 | // Remove all "ConfigureServices" object accessor instances, because they are only needed for configuring services.
42 | IList serviceDescriptors = services
43 | .Where(x => x.ServiceType.IsAssignableTo(typeof(IObjectAccessor)))
44 | .Where(x => (x.ImplementationInstance != null) && (((IObjectAccessor)x.ImplementationInstance).Context == ObjectAccessorLifetime.ConfigureServices))
45 | .ToList();
46 | foreach(ServiceDescriptor serviceDescriptor in serviceDescriptors)
47 | {
48 | services.Remove(serviceDescriptor);
49 | if(serviceDescriptor != null)
50 | {
51 | IObjectAccessor accessor = serviceDescriptor.ImplementationInstance as IObjectAccessor;
52 | accessor?.Dispose();
53 | }
54 | }
55 | }
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/Fluxera.Extensions.Hosting/Modules/ModuleDescriptor.cs:
--------------------------------------------------------------------------------
1 | namespace Fluxera.Extensions.Hosting.Modules
2 | {
3 | using System;
4 | using System.Collections.Generic;
5 | #if NET6_0
6 | using System.Collections.ObjectModel;
7 | #endif
8 | using System.Reflection;
9 |
10 | internal sealed class ModuleDescriptor : IModuleDescriptor
11 | {
12 | private readonly IList dependencies;
13 |
14 | public ModuleDescriptor(Type type, IModule instance, bool isLoadedAsPlugin)
15 | {
16 | Guard.ThrowIfNull(type);
17 | Guard.ThrowIfNull(instance);
18 |
19 | if(!type.GetTypeInfo().IsInstanceOfType(instance))
20 | {
21 | throw new ArgumentException(
22 | $"Given module instance ({instance.GetType().AssemblyQualifiedName}) is not an instance of given module type: {type.AssemblyQualifiedName}.");
23 | }
24 |
25 | this.Type = type;
26 | this.Assembly = type.Assembly;
27 | this.Instance = instance;
28 | this.IsLoadedAsPlugin = isLoadedAsPlugin;
29 |
30 | this.dependencies = new List();
31 | }
32 |
33 | public Type Type { get; }
34 |
35 | #if NET6_0
36 | public IReadOnlyCollection Dependencies => new ReadOnlyCollection(this.dependencies);
37 | #endif
38 |
39 | #if NET7_0_OR_GREATER
40 | public IReadOnlyCollection Dependencies => this.dependencies.AsReadOnly();
41 | #endif
42 |
43 | public Assembly Assembly { get; }
44 |
45 | public IModule Instance { get; }
46 |
47 | public bool IsLoadedAsPlugin { get; }
48 |
49 | public string Name => this.Assembly.FullName;
50 |
51 | public void AddDependency(IModuleDescriptor descriptor)
52 | {
53 | if(!this.dependencies.Contains(descriptor))
54 | {
55 | this.dependencies.Add(descriptor);
56 | }
57 | }
58 |
59 | public override string ToString()
60 | {
61 | return $"[ModuleDescriptor {this.Type.FullName}]";
62 | }
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/src/Fluxera.Extensions.Hosting/Modules/ModuleManager.cs:
--------------------------------------------------------------------------------
1 | namespace Fluxera.Extensions.Hosting.Modules
2 | {
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using JetBrains.Annotations;
6 | using Microsoft.Extensions.Logging;
7 |
8 | [UsedImplicitly]
9 | internal sealed class ModuleManager : IModuleManager
10 | {
11 | private readonly IModuleLifecycleContributor[] lifecycleContributors;
12 | private readonly ILogger logger;
13 | private readonly IModuleContainer moduleContainer;
14 |
15 | public ModuleManager(
16 | ILogger logger,
17 | IModuleContainer moduleContainer,
18 | IEnumerable lifecycleContributors)
19 | {
20 | this.moduleContainer = moduleContainer;
21 | this.logger = logger;
22 |
23 | // Get the lifecycle contributor services from the service provider.
24 | this.lifecycleContributors = lifecycleContributors.ToArray();
25 | }
26 |
27 | public void InitializeModules(IApplicationInitializationContext context)
28 | {
29 | this.LogListOfModules();
30 |
31 | foreach(IModuleLifecycleContributor contributor in this.lifecycleContributors)
32 | {
33 | foreach(IModuleDescriptor module in this.moduleContainer.Modules)
34 | {
35 | contributor.Initialize(context, module.Instance);
36 | }
37 | }
38 |
39 | this.logger.LogModulesInitialized();
40 | }
41 |
42 | public void ShutdownModules(IApplicationShutdownContext context)
43 | {
44 | IList modules = this.moduleContainer.Modules.Reverse().ToList();
45 |
46 | foreach(IModuleLifecycleContributor contributor in this.lifecycleContributors)
47 | {
48 | foreach(IModuleDescriptor module in modules)
49 | {
50 | contributor.Shutdown(context, module.Instance);
51 | }
52 | }
53 | }
54 |
55 | private void LogListOfModules()
56 | {
57 | foreach(IModuleDescriptor module in this.moduleContainer.Modules)
58 | {
59 | this.logger.LogLoadedModule(module.Type.FullName);
60 | }
61 | }
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/src/Fluxera.Extensions.Hosting/Modules/OnApplicationInitializationModuleLifecycleContributor.cs:
--------------------------------------------------------------------------------
1 | namespace Fluxera.Extensions.Hosting.Modules
2 | {
3 | using JetBrains.Annotations;
4 |
5 | [UsedImplicitly]
6 | internal sealed class OnApplicationInitializationModuleLifecycleContributor : ModuleLifecycleContributorBase
7 | {
8 | public override void Initialize(IApplicationInitializationContext context, IModule module)
9 | {
10 | (module as IConfigureApplication)?.Configure(context);
11 | }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/Fluxera.Extensions.Hosting/Modules/OnApplicationShutdownModuleLifecycleContributor.cs:
--------------------------------------------------------------------------------
1 | namespace Fluxera.Extensions.Hosting.Modules
2 | {
3 | using JetBrains.Annotations;
4 |
5 | [UsedImplicitly]
6 | internal sealed class OnApplicationShutdownModuleLifecycleContributor : ModuleLifecycleContributorBase
7 | {
8 | public override void Shutdown(IApplicationShutdownContext context, IModule module)
9 | {
10 | (module as IShutdownApplicationModule)?.OnApplicationShutdown(context);
11 | }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/Fluxera.Extensions.Hosting/Modules/OnPostApplicationInitializationModuleLifecycleContributor.cs:
--------------------------------------------------------------------------------
1 | namespace Fluxera.Extensions.Hosting.Modules
2 | {
3 | using JetBrains.Annotations;
4 |
5 | [UsedImplicitly]
6 | internal sealed class OnPostApplicationInitializationModuleLifecycleContributor : ModuleLifecycleContributorBase
7 | {
8 | public override void Initialize(IApplicationInitializationContext context, IModule module)
9 | {
10 | (module as IPostConfigureApplication)?.PostConfigure(context);
11 | }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/Fluxera.Extensions.Hosting/Modules/OnPreApplicationInitializationModuleLifecycleContributor.cs:
--------------------------------------------------------------------------------
1 | namespace Fluxera.Extensions.Hosting.Modules
2 | {
3 | using JetBrains.Annotations;
4 |
5 | [UsedImplicitly]
6 | internal sealed class OnPreApplicationInitializationModuleLifecycleContributor : ModuleLifecycleContributorBase
7 | {
8 | public override void Initialize(IApplicationInitializationContext context, IModule module)
9 | {
10 | (module as IPreConfigureApplication)?.PreConfigure(context);
11 | }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/Fluxera.Extensions.Hosting/NumericExtensions.cs:
--------------------------------------------------------------------------------
1 | namespace Fluxera.Extensions.Hosting
2 | {
3 | using System.Numerics;
4 |
5 | internal static class NumericExtensions
6 | {
7 | #if NET7_0_OR_GREATER
8 | ///
9 | /// Determines if the given value is between the specified values a and b (inclusive).
10 | ///
11 | /// true if the given value is between the specified values a and b; otherwise, false .
12 | /// Value.
13 | /// The alpha component.
14 | /// The blue component.
15 | public static bool IsBetween(this T value, T a, T b) where T : notnull, INumber
16 | {
17 | return a < b
18 | ? value >= a && value <= b
19 | : value >= b && value <= a;
20 | }
21 | #endif
22 |
23 | #if NET6_0
24 | ///
25 | /// Determines if the given value is between the specified values a and b (inclusive).
26 | ///
27 | /// true if the given value is between the specified values a and b; otherwise, false .
28 | /// Value.
29 | /// The alpha component.
30 | /// The blue component.
31 | public static bool IsBetween(this int value, int a, int b)
32 | {
33 | return a < b
34 | ? value >= a && value <= b
35 | : value >= b && value <= a;
36 | }
37 | #endif
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/Fluxera.Extensions.Hosting/PluginConfigurationContext.cs:
--------------------------------------------------------------------------------
1 | namespace Fluxera.Extensions.Hosting
2 | {
3 | using Fluxera.Extensions.DependencyInjection;
4 | using Fluxera.Extensions.Hosting.Plugins;
5 | using JetBrains.Annotations;
6 | using Microsoft.Extensions.Configuration;
7 | using Microsoft.Extensions.DependencyInjection;
8 | using Microsoft.Extensions.Hosting;
9 | using Microsoft.Extensions.Logging;
10 |
11 | [PublicAPI]
12 | internal sealed class PluginConfigurationContext : IPluginConfigurationContext
13 | {
14 | public PluginConfigurationContext(IServiceCollection services, IPluginSourceList pluginSources)
15 | {
16 | Guard.ThrowIfNull(services);
17 | Guard.ThrowIfNull(pluginSources);
18 |
19 | this.PluginSources = pluginSources;
20 |
21 | this.Configuration = services.GetObject();
22 | this.Environment = services.GetObject();
23 | this.Logger = services.GetObject();
24 | }
25 |
26 | public IPluginSourceList PluginSources { get; }
27 |
28 | ///
29 | public IConfiguration Configuration { get; }
30 |
31 | ///
32 | public IHostEnvironment Environment { get; }
33 |
34 | ///
35 | public ILogger Logger { get; }
36 |
37 | ///
38 | IPluginSourceList ILoggingContext.LogContextData => this.PluginSources;
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/Fluxera.Extensions.Hosting/PluginConfigurationContextExtensions.cs:
--------------------------------------------------------------------------------
1 | namespace Fluxera.Extensions.Hosting
2 | {
3 | using System;
4 | using Fluxera.Extensions.Hosting.Modules;
5 | using Fluxera.Extensions.Hosting.Plugins;
6 | using JetBrains.Annotations;
7 |
8 | ///
9 | /// Extensions methods to simplify the configuration of plugin sources.
10 | ///
11 | [PublicAPI]
12 | public static class PluginConfigurationContextExtensions
13 | {
14 | ///
15 | /// Adds all assemblies containing plugin from a folder.
16 | ///
17 | /// The plugin configuration context.
18 | /// The folder to scan for plugin modules.
19 | ///
20 | public static IPluginConfigurationContext AddPlugins(this IPluginConfigurationContext context, string pluginAssembliesFolder)
21 | {
22 | Guard.ThrowIfNull(context);
23 |
24 | context.PluginSources.Add(new FolderPluginSource(pluginAssembliesFolder));
25 |
26 | return context;
27 | }
28 |
29 | ///
30 | /// Adds the given plugin modules types.
31 | ///
32 | /// The plugin configuration context.
33 | /// The plugin modules.
34 | ///
35 | public static IPluginConfigurationContext AddPlugins(this IPluginConfigurationContext context, params Type[] pluginModuleTypes)
36 | {
37 | Guard.ThrowIfNull(context);
38 |
39 | context.PluginSources.Add(new PluginTypeListSource(pluginModuleTypes));
40 |
41 | return context;
42 | }
43 |
44 | ///
45 | /// Adds the plugin module of teh given type.
46 | ///
47 | /// The type of the plugin module.
48 | /// The plugin configuration context.
49 | ///
50 | public static IPluginConfigurationContext AddPlugin(this IPluginConfigurationContext context)
51 | where TPluginModule : class, IModule
52 | {
53 | Guard.ThrowIfNull(context);
54 |
55 | return context.AddPlugin(typeof(TPluginModule));
56 | }
57 |
58 | ///
59 | /// Adds the plugin module of teh given type.
60 | ///
61 | /// The plugin configuration context.
62 | /// The plugin module type.
63 | ///
64 | public static IPluginConfigurationContext AddPlugin(this IPluginConfigurationContext context, Type pluginModuleType)
65 | {
66 | Guard.ThrowIfNull(context);
67 |
68 | context.PluginSources.Add(new PluginModuleTypeSource(pluginModuleType));
69 |
70 | return context;
71 | }
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/src/Fluxera.Extensions.Hosting/Plugins/FolderPluginSource.cs:
--------------------------------------------------------------------------------
1 | namespace Fluxera.Extensions.Hosting.Plugins
2 | {
3 | using System;
4 | using System.Collections.Generic;
5 | using System.IO;
6 | using System.Linq;
7 | using System.Reflection;
8 |
9 | ///
10 | /// Loads plugin modules from a folder containing assemblies.
11 | ///
12 | internal sealed class FolderPluginSource : IPluginSource
13 | {
14 | private readonly string folder;
15 | private readonly Lazy> moduleAssemblies;
16 | private readonly SearchOption searchOption;
17 |
18 | public FolderPluginSource(string folder, SearchOption searchOption = SearchOption.TopDirectoryOnly)
19 | {
20 | Guard.ThrowIfNullOrWhiteSpace(folder);
21 |
22 | this.folder = folder;
23 | this.searchOption = searchOption;
24 |
25 | this.moduleAssemblies = new Lazy>(this.LoadAssemblies, true);
26 | }
27 |
28 | public IEnumerable GetAssemblies()
29 | {
30 | return this.moduleAssemblies.Value;
31 | }
32 |
33 | public IEnumerable GetModules()
34 | {
35 | IList modules = new List();
36 |
37 | foreach(Assembly assembly in this.GetAssemblies())
38 | {
39 | try
40 | {
41 | foreach(Type type in assembly.GetTypes())
42 | {
43 | if(ModuleHelper.IsModule(type))
44 | {
45 | modules.AddIfNotContains(type);
46 | }
47 | }
48 | }
49 | catch(Exception ex)
50 | {
51 | throw new InvalidOperationException(
52 | $"Could not get module types from assembly: {assembly.FullName}", ex);
53 | }
54 | }
55 |
56 | return modules;
57 | }
58 |
59 | private IEnumerable LoadAssemblies()
60 | {
61 | return GetAllAssembliesInFolder(this.folder, this.searchOption);
62 | }
63 |
64 | private static IEnumerable GetAllAssembliesInFolder(string folderPath, SearchOption searchOption)
65 | {
66 | return Directory
67 | .EnumerateFiles(folderPath, "*.dll", searchOption)
68 | .Select(Assembly.LoadFile);
69 | }
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/src/Fluxera.Extensions.Hosting/Plugins/PluginModuleTypeSource.cs:
--------------------------------------------------------------------------------
1 | namespace Fluxera.Extensions.Hosting.Plugins
2 | {
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Reflection;
6 |
7 | ///
8 | /// A plugin source for manually adding a module type.
9 | ///
10 | internal sealed class PluginModuleTypeSource : IPluginSource
11 | {
12 | private readonly Lazy moduleAssembly;
13 | private readonly Type moduleType;
14 |
15 | public PluginModuleTypeSource(Type moduleType)
16 | {
17 | Guard.ThrowIfNull(moduleType);
18 |
19 | this.moduleType = moduleType;
20 | this.moduleAssembly = new Lazy(this.LoadAssembly, true);
21 | }
22 |
23 | public IEnumerable GetAssemblies()
24 | {
25 | yield return this.moduleAssembly.Value;
26 | }
27 |
28 | public IEnumerable GetModules()
29 | {
30 | yield return this.moduleType;
31 | }
32 |
33 | private Assembly LoadAssembly()
34 | {
35 | return this.moduleType.GetTypeInfo().Assembly;
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/Fluxera.Extensions.Hosting/Plugins/PluginSourceExtensions.cs:
--------------------------------------------------------------------------------
1 | namespace Fluxera.Extensions.Hosting.Plugins
2 | {
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 |
7 | internal static class PluginSourceExtensions
8 | {
9 | public static IEnumerable GetModulesWithAllDependencies(this IPluginSource pluginSource)
10 | {
11 | return pluginSource
12 | .GetModules()
13 | .SelectMany(ModuleHelper.FindDependedModuleTypesRecursiveIncludingGivenModule)
14 | .Distinct();
15 | }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/Fluxera.Extensions.Hosting/Plugins/PluginSourceList.cs:
--------------------------------------------------------------------------------
1 | namespace Fluxera.Extensions.Hosting.Plugins
2 | {
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Reflection;
7 | using JetBrains.Annotations;
8 |
9 | [UsedImplicitly]
10 | internal sealed class PluginSourceList : List, IPluginSourceList
11 | {
12 | IEnumerable IPluginSourceList.GetAllAssemblies()
13 | {
14 | return this
15 | .SelectMany(pluginSource => pluginSource.GetAssemblies())
16 | .Distinct();
17 | }
18 |
19 | IEnumerable IPluginSourceList.GetAllModules()
20 | {
21 | return this
22 | .SelectMany(pluginSource => pluginSource.GetModulesWithAllDependencies())
23 | .Distinct();
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/Fluxera.Extensions.Hosting/Plugins/PluginTypeListSource.cs:
--------------------------------------------------------------------------------
1 | namespace Fluxera.Extensions.Hosting.Plugins
2 | {
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Reflection;
7 |
8 | ///
9 | /// A plugin source for manually adding module types.
10 | ///
11 | internal sealed class PluginTypeListSource : IPluginSource
12 | {
13 | private readonly Lazy> moduleAssemblies;
14 | private readonly Type[] moduleTypes;
15 |
16 | public PluginTypeListSource(params Type[] moduleTypes)
17 | {
18 | Guard.ThrowIfNull(moduleTypes);
19 |
20 | this.moduleTypes = moduleTypes;
21 |
22 | this.moduleAssemblies = new Lazy>(this.LoadAssemblies, true);
23 | }
24 |
25 | public IEnumerable GetAssemblies()
26 | {
27 | return this.moduleAssemblies.Value;
28 | }
29 |
30 | public IEnumerable GetModules()
31 | {
32 | return this.moduleTypes;
33 | }
34 |
35 | private IEnumerable LoadAssemblies()
36 | {
37 | return this.moduleTypes.Select(type => type.GetTypeInfo().Assembly);
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/Fluxera.Extensions.Hosting/ServiceConfigurationContext.cs:
--------------------------------------------------------------------------------
1 | namespace Fluxera.Extensions.Hosting
2 | {
3 | using System.Collections.Generic;
4 | using Fluxera.Extensions.DependencyInjection;
5 | using JetBrains.Annotations;
6 | using Microsoft.Extensions.Configuration;
7 | using Microsoft.Extensions.DependencyInjection;
8 | using Microsoft.Extensions.Hosting;
9 | using Microsoft.Extensions.Logging;
10 |
11 | [PublicAPI]
12 | internal sealed class ServiceConfigurationContext : IServiceConfigurationContext
13 | {
14 | public ServiceConfigurationContext(IServiceCollection services)
15 | {
16 | Guard.ThrowIfNull(services);
17 |
18 | this.Services = services;
19 | this.Configuration = services.GetObject();
20 | this.Environment = services.GetObject();
21 | this.Logger = services.GetObject();
22 |
23 | this.Items = new Dictionary();
24 | }
25 |
26 | ///
27 | public IDictionary Items { get; }
28 |
29 | ///
30 | public IServiceCollection Services { get; }
31 |
32 | ///
33 | public IConfiguration Configuration { get; }
34 |
35 | ///
36 | public IHostEnvironment Environment { get; }
37 |
38 | ///
39 | public ILogger Logger { get; }
40 |
41 | ///
42 | public object this[string key]
43 | {
44 | get => this.Items.TryGetValue(key, out object obj) ? obj : null;
45 | set => this.Items[key] = value;
46 | }
47 |
48 | ///
49 | IServiceCollection ILoggingContext.LogContextData => this.Services;
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/tests/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/Directory.Build.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | latest
5 | disable
6 | disable
7 | false
8 | false
9 |
10 |
11 |
12 | $([System.DateTime]::UtcNow.Year)
13 |
14 |
15 |
16 | Fluxera Software Development GmbH
17 | Fluxera Software Foundation
18 | Copyright © 2014-$(CurrentYear) Fluxera Software Development GmbH. All rights reserved.
19 |
20 |
21 |
--------------------------------------------------------------------------------
/tests/Fluxera.Extensions.Hosting.UnitTests/ApplicationLoaderServicesTests.cs:
--------------------------------------------------------------------------------
1 | namespace Fluxera.Extensions.Hosting.UnitTests
2 | {
3 | using System;
4 | using System.Linq;
5 | using FluentAssertions;
6 | using Fluxera.Extensions.Hosting.Modules;
7 | using NUnit.Framework;
8 |
9 | [TestFixture]
10 | public class ApplicationLoaderServicesTests : StartupModuleTestBase
11 | {
12 | [Test]
13 | public void ShouldHaveModuleLoader()
14 | {
15 | IModuleDescriptor descriptor = this.ApplicationLoader.Modules.First();
16 | TestApplicationModule module = descriptor.Instance as TestApplicationModule;
17 |
18 | module.HasModuleContainer.Should().BeTrue();
19 | }
20 |
21 | [Test]
22 | public void ShouldNotAllowCallingConfigureServicesMultipleTimes()
23 | {
24 | Action action = () =>
25 | {
26 | this.ApplicationLoader.ConfigureServices();
27 | };
28 |
29 | action.Should().ThrowExactly();
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/tests/Fluxera.Extensions.Hosting.UnitTests/DependsOn/DependsOnAttributeTests.cs:
--------------------------------------------------------------------------------
1 | namespace Fluxera.Extensions.Hosting.UnitTests.DependsOn
2 | {
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using FluentAssertions;
6 | using Fluxera.Extensions.Hosting.Modules;
7 | using Fluxera.Extensions.Hosting.UnitTests.DependsOn.Modules;
8 | using NUnit.Framework;
9 |
10 | [TestFixture]
11 | public class DependsOnAttributeTests : StartupModuleTestBase
12 | {
13 | [Test]
14 | public void ShouldLoadAllFourModules()
15 | {
16 | IList descriptors = this.ApplicationLoader.Modules.ToList();
17 |
18 | descriptors.Should().HaveCount(4);
19 |
20 | descriptors[3].Type.Should().Be();
21 | descriptors[2].Type.Should().Be();
22 | descriptors[1].Type.Should().Be();
23 | descriptors[0].Type.Should().Be();
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/tests/Fluxera.Extensions.Hosting.UnitTests/DependsOn/Modules/DependsOnThirdModule.cs:
--------------------------------------------------------------------------------
1 | namespace Fluxera.Extensions.Hosting.UnitTests.DependsOn.Modules
2 | {
3 | public class DependsOnThirdModule : DependsOnAttribute
4 | {
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/tests/Fluxera.Extensions.Hosting.UnitTests/DependsOn/Modules/FirstModule.cs:
--------------------------------------------------------------------------------
1 | namespace Fluxera.Extensions.Hosting.UnitTests.DependsOn.Modules
2 | {
3 | using Fluxera.Extensions.Hosting.Modules;
4 |
5 | [DependsOn]
6 | public class FirstModule : IModule
7 | {
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/tests/Fluxera.Extensions.Hosting.UnitTests/DependsOn/Modules/RootModule.cs:
--------------------------------------------------------------------------------
1 | namespace Fluxera.Extensions.Hosting.UnitTests.DependsOn.Modules
2 | {
3 | using Fluxera.Extensions.Hosting.Modules;
4 |
5 | [DependsOn(typeof(FirstModule))]
6 | public class RootModule : IModule
7 | {
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/tests/Fluxera.Extensions.Hosting.UnitTests/DependsOn/Modules/SecondModule.cs:
--------------------------------------------------------------------------------
1 | namespace Fluxera.Extensions.Hosting.UnitTests.DependsOn.Modules
2 | {
3 | using Fluxera.Extensions.Hosting.Modules;
4 |
5 | [DependsOnThirdModule]
6 | public class SecondModule : IModule
7 | {
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/tests/Fluxera.Extensions.Hosting.UnitTests/DependsOn/Modules/ThirdModule.cs:
--------------------------------------------------------------------------------
1 | namespace Fluxera.Extensions.Hosting.UnitTests.DependsOn.Modules
2 | {
3 | using Fluxera.Extensions.Hosting.Modules;
4 |
5 | public class ThirdModule : IModule
6 | {
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/tests/Fluxera.Extensions.Hosting.UnitTests/Fluxera.Extensions.Hosting.UnitTests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net8.0;net9.0
5 | false
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | all
16 | runtime; build; native; contentfiles; analyzers; buildtransitive
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/tests/Fluxera.Extensions.Hosting.UnitTests/GenericApplicationModule.cs:
--------------------------------------------------------------------------------
1 | namespace Fluxera.Extensions.Hosting.UnitTests
2 | {
3 | using Fluxera.Extensions.Hosting.Modules;
4 | using JetBrains.Annotations;
5 |
6 | [PublicAPI]
7 | public class GenericApplicationModule : ConfigureApplicationModule
8 | {
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/tests/Fluxera.Extensions.Hosting.UnitTests/HostingGenericModuleTests.cs:
--------------------------------------------------------------------------------
1 | namespace Fluxera.Extensions.Hosting.UnitTests
2 | {
3 | using System.Linq;
4 | using FluentAssertions;
5 | using Fluxera.Extensions.Hosting.Modules;
6 | using NUnit.Framework;
7 |
8 | [TestFixture]
9 | public class HostingGenericModuleTests : StartupModuleTestBase>
10 | {
11 | [Test]
12 | public void ShouldLoadModule()
13 | {
14 | IModuleDescriptor descriptor = this.ApplicationLoader.Modules.First();
15 | descriptor.Instance.Should().BeOfType>();
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/tests/Fluxera.Extensions.Hosting.UnitTests/HostingModuleTests.cs:
--------------------------------------------------------------------------------
1 | namespace Fluxera.Extensions.Hosting.UnitTests
2 | {
3 | using System.Linq;
4 | using FluentAssertions;
5 | using Fluxera.Extensions.Hosting.Modules;
6 | using NUnit.Framework;
7 |
8 | [TestFixture]
9 | public class HostingModuleTests : StartupModuleTestBase
10 | {
11 | [Test]
12 | public void ShouldCallConfigure()
13 | {
14 | IModuleDescriptor descriptor = this.ApplicationLoader.Modules.First();
15 | TestApplicationModule module = descriptor.Instance as TestApplicationModule;
16 |
17 | module.Should().NotBeNull();
18 | module.ConfigureWasCalled.Should().BeTrue();
19 | }
20 |
21 | [Test]
22 | public void ShouldCallConfigureServices()
23 | {
24 | IModuleDescriptor descriptor = this.ApplicationLoader.Modules.First();
25 | TestApplicationModule module = descriptor.Instance as TestApplicationModule;
26 |
27 | module.Should().NotBeNull();
28 | module.ConfigureServicesWasCalled.Should().BeTrue();
29 | }
30 |
31 | [Test]
32 | public void ShouldCallOnApplicationShutdown()
33 | {
34 | this.ApplicationLoader.Shutdown();
35 | IModuleDescriptor descriptor = this.ApplicationLoader.Modules.First();
36 | TestApplicationModule module = descriptor.Instance as TestApplicationModule;
37 |
38 | module.Should().NotBeNull();
39 | module.OnApplicationShutdownWasCalled.Should().BeTrue();
40 | }
41 |
42 | [Test]
43 | public void ShouldCallPostConfigure()
44 | {
45 | IModuleDescriptor descriptor = this.ApplicationLoader.Modules.First();
46 | TestApplicationModule module = descriptor.Instance as TestApplicationModule;
47 |
48 | module.Should().NotBeNull();
49 | module.PostConfigureWasCalled.Should().BeTrue();
50 | }
51 |
52 | [Test]
53 | public void ShouldCallPostConfigureServices()
54 | {
55 | IModuleDescriptor descriptor = this.ApplicationLoader.Modules.First();
56 | TestApplicationModule module = descriptor.Instance as TestApplicationModule;
57 |
58 | module.Should().NotBeNull();
59 | module.PostConfigureServicesWasCalled.Should().BeTrue();
60 | }
61 |
62 | [Test]
63 | public void ShouldCallPreConfigure()
64 | {
65 | IModuleDescriptor descriptor = this.ApplicationLoader.Modules.First();
66 | TestApplicationModule module = descriptor.Instance as TestApplicationModule;
67 |
68 | module.Should().NotBeNull();
69 | module.PreConfigureWasCalled.Should().BeTrue();
70 | }
71 |
72 | [Test]
73 | public void ShouldCallPreConfigureServices()
74 | {
75 | IModuleDescriptor descriptor = this.ApplicationLoader.Modules.First();
76 | TestApplicationModule module = descriptor.Instance as TestApplicationModule;
77 |
78 | module.Should().NotBeNull();
79 | module.PreConfigureServicesWasCalled.Should().BeTrue();
80 | }
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/tests/Fluxera.Extensions.Hosting.UnitTests/ServiceCollectionTests.cs:
--------------------------------------------------------------------------------
1 | namespace Fluxera.Extensions.Hosting.UnitTests
2 | {
3 | using FluentAssertions;
4 | using NUnit.Framework;
5 |
6 | [TestFixture]
7 | public class ServiceCollectionTests
8 | {
9 | [Test]
10 | public void Should()
11 | {
12 | true.Should().BeTrue();
13 | }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/tests/Fluxera.Extensions.Hosting.UnitTests/StartupModuleTestBase.cs:
--------------------------------------------------------------------------------
1 | namespace Fluxera.Extensions.Hosting.UnitTests
2 | {
3 | using System;
4 | using Fluxera.Extensions.Hosting.Modules;
5 | using JetBrains.Annotations;
6 | using Microsoft.Extensions.Configuration;
7 | using Microsoft.Extensions.DependencyInjection;
8 | using Microsoft.Extensions.Hosting;
9 | using Microsoft.Extensions.Hosting.Internal;
10 | using NUnit.Framework;
11 |
12 | [PublicAPI]
13 | public abstract class StartupModuleTestBase : TestBase
14 | where TStartupModule : class, IModule
15 | {
16 | protected IApplicationLoader ApplicationLoader { get; private set; }
17 |
18 | [SetUp]
19 | public void Setup()
20 | {
21 | IServiceProvider serviceProvider = BuildServiceProvider(services =>
22 | {
23 | IConfiguration configuration = new ConfigurationBuilder().Build();
24 | IHostEnvironment environment = new HostingEnvironment
25 | {
26 | EnvironmentName = "Development",
27 | ApplicationName = "UnitTests",
28 | };
29 |
30 | services.AddSingleton(environment);
31 | services.AddSingleton();
32 | services.AddSingleton();
33 |
34 | services.AddApplicationLoader(configuration, environment, CreateBootstrapperLogger());
35 | });
36 |
37 | this.ApplicationLoader = serviceProvider.GetRequiredService();
38 | this.ApplicationLoader.Initialize(new ApplicationLoaderInitializationContext(serviceProvider));
39 | }
40 |
41 | [TearDown]
42 | public void TearDown()
43 | {
44 | this.ApplicationLoader?.Shutdown();
45 | this.ApplicationLoader = null;
46 | }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/tests/Fluxera.Extensions.Hosting.UnitTests/TestApplicationLifetime.cs:
--------------------------------------------------------------------------------
1 | namespace Fluxera.Extensions.Hosting.UnitTests
2 | {
3 | using System.Diagnostics.CodeAnalysis;
4 | using System.Threading;
5 | using Microsoft.Extensions.Hosting;
6 |
7 | [SuppressMessage("ReSharper", "UnassignedGetOnlyAutoProperty")]
8 | public class TestApplicationLifetime : IHostApplicationLifetime
9 | {
10 | ///
11 | public void StopApplication()
12 | {
13 | }
14 |
15 | ///
16 | public CancellationToken ApplicationStarted { get; }
17 |
18 | ///
19 | public CancellationToken ApplicationStopping { get; }
20 |
21 | ///
22 | public CancellationToken ApplicationStopped { get; }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/tests/Fluxera.Extensions.Hosting.UnitTests/TestBase.cs:
--------------------------------------------------------------------------------
1 | namespace Fluxera.Extensions.Hosting.UnitTests
2 | {
3 | using System;
4 | using JetBrains.Annotations;
5 | using Microsoft.Extensions.DependencyInjection;
6 | using Microsoft.Extensions.Logging;
7 |
8 | [PublicAPI]
9 | public abstract class TestBase
10 | {
11 | protected static IServiceProvider BuildServiceProvider(Action configure)
12 | {
13 | IServiceCollection services = new ServiceCollection();
14 |
15 | services.AddLogging(builder =>
16 | {
17 | builder.SetMinimumLevel(LogLevel.Trace);
18 | builder.AddConsole();
19 | });
20 |
21 | configure(services);
22 | return services.BuildServiceProvider();
23 | }
24 |
25 | protected static ILogger CreateBootstrapperLogger()
26 | {
27 | ILoggerFactory loggerFactory = LoggerFactory.Create(builder =>
28 | {
29 | builder.SetMinimumLevel(LogLevel.Trace);
30 | builder.AddConsole();
31 | });
32 |
33 | return loggerFactory.CreateLogger(ApplicationHost.LoggerName);
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/tests/Fluxera.Extensions.Hosting.UnitTests/TestConfigureApplicationModule.cs:
--------------------------------------------------------------------------------
1 | namespace Fluxera.Extensions.Hosting.UnitTests
2 | {
3 | using Fluxera.Extensions.DependencyInjection;
4 | using Fluxera.Extensions.Hosting.Modules;
5 | using JetBrains.Annotations;
6 |
7 | [PublicAPI]
8 | public class TestApplicationModule : ConfigureApplicationModule
9 | {
10 | public bool PreConfigureServicesWasCalled { get; set; }
11 |
12 | public bool ConfigureServicesWasCalled { get; set; }
13 |
14 | public bool PostConfigureServicesWasCalled { get; set; }
15 |
16 | public bool PreConfigureWasCalled { get; set; }
17 |
18 | public bool ConfigureWasCalled { get; set; }
19 |
20 | public bool PostConfigureWasCalled { get; set; }
21 |
22 | public bool OnApplicationShutdownWasCalled { get; set; }
23 |
24 | public bool HasModuleContainer { get; set; }
25 |
26 | ///
27 | public override void PreConfigureServices(IServiceConfigurationContext context)
28 | {
29 | this.PreConfigureServicesWasCalled = true;
30 | }
31 |
32 | ///
33 | public override void ConfigureServices(IServiceConfigurationContext context)
34 | {
35 | this.ConfigureServicesWasCalled = true;
36 |
37 | IModuleContainer moduleLoader = context.Services.GetObjectOrDefault();
38 | this.HasModuleContainer = moduleLoader != null;
39 | }
40 |
41 | ///
42 | public override void PostConfigureServices(IServiceConfigurationContext context)
43 | {
44 | this.PostConfigureServicesWasCalled = true;
45 | }
46 |
47 | ///
48 | public override void PreConfigure(IApplicationInitializationContext context)
49 | {
50 | this.PreConfigureWasCalled = true;
51 | }
52 |
53 | ///
54 | public override void Configure(IApplicationInitializationContext context)
55 | {
56 | this.ConfigureWasCalled = true;
57 | }
58 |
59 | ///
60 | public override void PostConfigure(IApplicationInitializationContext context)
61 | {
62 | this.PostConfigureWasCalled = true;
63 | }
64 |
65 | ///
66 | public override void OnApplicationShutdown(IApplicationShutdownContext context)
67 | {
68 | this.OnApplicationShutdownWasCalled = true;
69 | }
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/tests/Fluxera.Extensions.Hosting.UnitTests/TestLifetime.cs:
--------------------------------------------------------------------------------
1 | namespace Fluxera.Extensions.Hosting.UnitTests
2 | {
3 | using System.Threading;
4 | using System.Threading.Tasks;
5 | using Microsoft.Extensions.Hosting;
6 |
7 | public class TestLifetime : IHostLifetime
8 | {
9 | ///
10 | public Task WaitForStartAsync(CancellationToken cancellationToken)
11 | {
12 | return Task.CompletedTask;
13 | }
14 |
15 | ///
16 | public Task StopAsync(CancellationToken cancellationToken)
17 | {
18 | return Task.CompletedTask;
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------