diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json
index 0c468f1b1..05fe57231 100644
--- a/.config/dotnet-tools.json
+++ b/.config/dotnet-tools.json
@@ -31,7 +31,7 @@
"commands": ["docfx"]
},
"strawberryshake.tools": {
- "version": "14.0.0-p.90",
+ "version": "14.0.0-p.93",
"commands": ["dotnet-graphql"]
},
"dotnet-outdated-tool": {
diff --git a/Directory.Packages.props b/Directory.Packages.props
index d541dd160..58e030a53 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -1,6 +1,8 @@
+
+
@@ -32,27 +34,27 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -72,6 +74,7 @@
+
@@ -91,15 +94,15 @@
-
-
-
-
-
+
+
+
+
+
-
-
+
+
@@ -133,6 +136,7 @@
+
diff --git a/sample/Sample.BlazorServer/Program.cs b/sample/Sample.BlazorServer/Program.cs
index 16071cc9c..9355fa055 100644
--- a/sample/Sample.BlazorServer/Program.cs
+++ b/sample/Sample.BlazorServer/Program.cs
@@ -1,5 +1,3 @@
-using System.Runtime.Loader;
-using Rocket.Surgery.Conventions;
using Rocket.Surgery.Hosting;
using Rocket.Surgery.LaunchPad.AspNetCore;
using Sample.BlazorServer;
@@ -11,7 +9,7 @@
builder.Services.AddServerSideBlazor();
builder.Services.AddSingleton();
-var app = await builder.LaunchWith(RocketBooster.For(Imports.Instance), b => b.Set(AssemblyLoadContext.Default));
+var app = await builder.LaunchWith(RocketBooster.For(Imports.Instance));
if (builder.Environment.IsDevelopment())
{
diff --git a/sample/Sample.Classic.Restful/Program.cs b/sample/Sample.Classic.Restful/Program.cs
index cc6378eef..06e7104d1 100644
--- a/sample/Sample.Classic.Restful/Program.cs
+++ b/sample/Sample.Classic.Restful/Program.cs
@@ -1,7 +1,5 @@
using System.Reflection;
-using System.Runtime.Loader;
using Hellang.Middleware.ProblemDetails;
-using Rocket.Surgery.Conventions;
using Rocket.Surgery.Hosting;
using Rocket.Surgery.LaunchPad.AspNetCore;
using Sample.Classic.Restful;
@@ -22,7 +20,7 @@
}
)
);
-var app = await builder.LaunchWith(RocketBooster.For(Imports.Instance), b => b.Set(AssemblyLoadContext.Default));
+var app = await builder.LaunchWith(RocketBooster.For(Imports.Instance));
app.UseProblemDetails();
app.UseHttpsRedirection();
diff --git a/sample/Sample.Graphql/Program.cs b/sample/Sample.Graphql/Program.cs
index 05a39b914..df1a93b41 100644
--- a/sample/Sample.Graphql/Program.cs
+++ b/sample/Sample.Graphql/Program.cs
@@ -1,6 +1,4 @@
-using System.Runtime.Loader;
using HotChocolate.Types.Spatial;
-using Rocket.Surgery.Conventions;
using Rocket.Surgery.Hosting;
using Rocket.Surgery.LaunchPad.AspNetCore;
using Rocket.Surgery.LaunchPad.HotChocolate;
@@ -30,7 +28,7 @@
.ModifyRequestOptions(options => options.IncludeExceptionDetails = true);
var app = await builder
- .LaunchWith(RocketBooster.For(Imports.Instance), b => b.Set(AssemblyLoadContext.Default));
+ .LaunchWith(RocketBooster.For(Imports.Instance));
app.UseHttpLogging();
app.UseLaunchPadRequestLogging();
diff --git a/sample/Sample.Pages/Program.cs b/sample/Sample.Pages/Program.cs
index 688d52c7a..078dbfab6 100644
--- a/sample/Sample.Pages/Program.cs
+++ b/sample/Sample.Pages/Program.cs
@@ -1,9 +1,7 @@
-using System.Runtime.Loader;
using System.Text;
using System.Text.Json;
using Humanizer;
using Microsoft.Extensions.Diagnostics.HealthChecks;
-using Rocket.Surgery.Conventions;
using Rocket.Surgery.Hosting;
using Rocket.Surgery.LaunchPad.AspNetCore;
using Sample.Pages;
@@ -12,7 +10,7 @@
builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();
-var app = await builder.LaunchWith(RocketBooster.For(Imports.Instance), b => b.Set(AssemblyLoadContext.Default));
+var app = await builder.LaunchWith(RocketBooster.For(Imports.Instance));
if (builder.Environment.IsDevelopment())
{
diff --git a/src/AspNetCore/Conventions/AspNetCoreConventionInstrumentationConvention.cs b/src/AspNetCore/Conventions/AspNetCoreConventionInstrumentationConvention.cs
index 1f9e17776..a15a0e056 100644
--- a/src/AspNetCore/Conventions/AspNetCoreConventionInstrumentationConvention.cs
+++ b/src/AspNetCore/Conventions/AspNetCoreConventionInstrumentationConvention.cs
@@ -19,7 +19,7 @@ namespace Rocket.Surgery.LaunchPad.AspNetCore.Conventions;
public class AspNetCoreConventionInstrumentationConvention : IOpenTelemetryConvention
{
///
- public void Register(IConventionContext conventionContext, IConfiguration configuration, IOpenTelemetryBuilder builder)
+ public void Register(IConventionContext context, IConfiguration configuration, IOpenTelemetryBuilder builder)
{
builder.WithTracing(b => b.AddAspNetCoreInstrumentation(options => options.RecordException = true));
builder.WithMetrics(b => b.AddAspNetCoreInstrumentation());
diff --git a/src/Directory.Build.props b/src/Directory.Build.props
index e8adea179..81b1e87aa 100644
--- a/src/Directory.Build.props
+++ b/src/Directory.Build.props
@@ -15,5 +15,6 @@
+
diff --git a/src/Foundation/Conventions/InstrumentationConvention.cs b/src/Foundation/Conventions/InstrumentationConvention.cs
index c020f0c46..5ef29f59e 100644
--- a/src/Foundation/Conventions/InstrumentationConvention.cs
+++ b/src/Foundation/Conventions/InstrumentationConvention.cs
@@ -17,9 +17,9 @@ namespace Rocket.Surgery.LaunchPad.Foundation.Conventions;
public class InstrumentationConvention : IOpenTelemetryConvention
{
///
- public void Register(IConventionContext conventionContext, IConfiguration configuration, IOpenTelemetryBuilder builder)
+ public void Register(IConventionContext context, IConfiguration configuration, IOpenTelemetryBuilder builder)
{
builder.WithTracing(b => b.AddHttpClientInstrumentation(x => x.RecordException = true));
- builder.WithMetrics(b => b.AddHttpClientInstrumentation());
+ builder.WithMetrics(b => b.AddRuntimeInstrumentation().AddHttpClientInstrumentation());
}
}
\ No newline at end of file
diff --git a/src/Foundation/Conventions/OptionsConvention.cs b/src/Foundation/Conventions/OptionsConvention.cs
new file mode 100644
index 000000000..40d0326bc
--- /dev/null
+++ b/src/Foundation/Conventions/OptionsConvention.cs
@@ -0,0 +1,40 @@
+using System.Reflection;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using Rocket.Surgery.Conventions;
+using Rocket.Surgery.Conventions.DependencyInjection;
+
+namespace Rocket.Surgery.LaunchPad.Foundation.Conventions;
+
+///
+/// A convention that registers any options POCOs that are found with the
+///
+[ExportConvention]
+public class OptionsConvention : IServiceConvention
+{
+ private readonly MethodInfo _configureMethod;
+
+ ///
+ /// A convention that registers any options POCOs that are found with the
+ ///
+ public OptionsConvention()
+ {
+ _configureMethod = typeof(OptionsConfigurationServiceCollectionExtensions).GetMethod(
+ nameof(OptionsConfigurationServiceCollectionExtensions.Configure),
+ [typeof(IServiceCollection), typeof(string), typeof(IConfiguration),]
+ )!;
+ }
+
+ ///
+ public void Register(IConventionContext context, IConfiguration configuration, IServiceCollection services)
+ {
+ var classes = context.AssemblyProvider.GetTypes(
+ s => s.FromAssemblyDependenciesOf().GetTypes(f => f.WithAttribute())
+ );
+ foreach (var options in classes)
+ {
+ var attribute = options.GetCustomAttribute()!;
+ _configureMethod.MakeGenericMethod(options).Invoke(null, [services, attribute.OptionsName, configuration.GetSection(attribute.ConfigurationKey),]);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Foundation/Conventions/ServiceDiscoveryConvention.cs b/src/Foundation/Conventions/ServiceDiscoveryConvention.cs
new file mode 100644
index 000000000..13866f843
--- /dev/null
+++ b/src/Foundation/Conventions/ServiceDiscoveryConvention.cs
@@ -0,0 +1,28 @@
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using Rocket.Surgery.Conventions;
+using Rocket.Surgery.Conventions.DependencyInjection;
+
+namespace Rocket.Surgery.LaunchPad.Foundation.Conventions;
+
+///
+/// Service conventions using service discovery
+///
+[PublicAPI]
+[ExportConvention]
+public class ServiceDiscoveryConvention : IServiceConvention
+{
+ ///
+ public void Register(IConventionContext context, IConfiguration configuration, IServiceCollection services)
+ {
+ services.AddServiceDiscovery();
+
+ services.ConfigureHttpClientDefaults(
+ http =>
+ {
+ http.AddStandardResilienceHandler();
+ http.AddServiceDiscovery();
+ }
+ );
+ }
+}
\ No newline at end of file
diff --git a/src/Foundation/GenerationIgnoreAttribute.cs b/src/Foundation/GenerationIgnoreAttribute.cs
index 8fcbdcb60..65c7a825e 100644
--- a/src/Foundation/GenerationIgnoreAttribute.cs
+++ b/src/Foundation/GenerationIgnoreAttribute.cs
@@ -3,5 +3,6 @@ namespace Rocket.Surgery.LaunchPad.Foundation;
///
/// Exclude the given property from the generation via launch pad source generators
///
+[PublicAPI]
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Method | AttributeTargets.Constructor)]
public sealed class GenerationIgnoreAttribute : Attribute;
\ No newline at end of file
diff --git a/src/Foundation/RegisterOptionsConfigurationAttribute.cs b/src/Foundation/RegisterOptionsConfigurationAttribute.cs
new file mode 100644
index 000000000..918063ff3
--- /dev/null
+++ b/src/Foundation/RegisterOptionsConfigurationAttribute.cs
@@ -0,0 +1,19 @@
+namespace Rocket.Surgery.LaunchPad.Foundation;
+
+///
+/// Register the options using the configuration key as the configuration root
+///
+[PublicAPI]
+[AttributeUsage(AttributeTargets.Class)]
+public sealed class RegisterOptionsConfigurationAttribute(string configurationKey) : Attribute
+{
+ ///
+ /// The configuration key to use
+ ///
+ public string ConfigurationKey { get; } = configurationKey;
+
+ ///
+ /// The optional options name
+ ///
+ public string? OptionsName { get; set; }
+}
\ No newline at end of file
diff --git a/src/Foundation/Rocket.Surgery.LaunchPad.Foundation.csproj b/src/Foundation/Rocket.Surgery.LaunchPad.Foundation.csproj
index c9ba1712f..3a25e4f96 100644
--- a/src/Foundation/Rocket.Surgery.LaunchPad.Foundation.csproj
+++ b/src/Foundation/Rocket.Surgery.LaunchPad.Foundation.csproj
@@ -16,7 +16,9 @@
-
+
+
+
@@ -28,6 +30,7 @@
+
diff --git a/src/Hosting/ApplicationLifecycleExtensions.cs b/src/Hosting/ApplicationLifecycleExtensions.cs
new file mode 100644
index 000000000..f9bc30e16
--- /dev/null
+++ b/src/Hosting/ApplicationLifecycleExtensions.cs
@@ -0,0 +1,203 @@
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Hosting;
+
+namespace Rocket.Surgery.LaunchPad.Hosting;
+
+///
+/// Extensions for configuring the application lifecycle
+///
+[PublicAPI]
+public static class ApplicationLifecycleExtensions
+{
+ ///
+ /// Run a simple action when the host has started
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static T OnHostStarted(this T builder, Action action) where T : IHostApplicationBuilder
+ {
+ builder.Services.AddSingleton(
+ new ApplicationLifecycleRegistration(
+ nameof(IHostedLifecycleService.StartedAsync),
+ (provider, _) =>
+ {
+ action(provider);
+ return Task.CompletedTask;
+ }
+ )
+ );
+ return builder;
+ }
+
+ ///
+ /// Run a simple action when the host has started
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static T OnHostStarted(this T builder, Func action) where T : IHostApplicationBuilder
+ {
+ builder.Services.AddSingleton(new ApplicationLifecycleRegistration(nameof(IHostedLifecycleService.StartedAsync), (provider, _) => action(provider)));
+ return builder;
+ }
+
+ ///
+ /// Run a simple action when the host has started
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static T OnHostStarted(this T builder, Func action) where T : IHostApplicationBuilder
+ {
+ builder.Services.AddSingleton(new ApplicationLifecycleRegistration(nameof(IHostedLifecycleService.StartedAsync), action));
+ return builder;
+ }
+
+ ///
+ /// Run a simple action when the host has starting
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static T OnHostStarting(this T builder, Action action) where T : IHostApplicationBuilder
+ {
+ builder.Services.AddSingleton(
+ new ApplicationLifecycleRegistration(
+ nameof(IHostedLifecycleService.StartingAsync),
+ (provider, _) =>
+ {
+ action(provider);
+ return Task.CompletedTask;
+ }
+ )
+ );
+ return builder;
+ }
+
+ ///
+ /// Run a simple action when the host has starting
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static T OnHostStarting(this T builder, Func action) where T : IHostApplicationBuilder
+ {
+ builder.Services.AddSingleton(new ApplicationLifecycleRegistration(nameof(IHostedLifecycleService.StartingAsync), (provider, _) => action(provider)));
+ return builder;
+ }
+
+ ///
+ /// Run a simple action when the host has starting
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static T OnHostStarting(this T builder, Func action) where T : IHostApplicationBuilder
+ {
+ builder.Services.AddSingleton(new ApplicationLifecycleRegistration(nameof(IHostedLifecycleService.StartingAsync), action));
+ return builder;
+ }
+
+ ///
+ /// Run a simple action when the host has stopping
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static T OnHostStopping(this T builder, Action action) where T : IHostApplicationBuilder
+ {
+ builder.Services.AddSingleton(
+ new ApplicationLifecycleRegistration(
+ nameof(IHostedLifecycleService.StoppingAsync),
+ (provider, _) =>
+ {
+ action(provider);
+ return Task.CompletedTask;
+ }
+ )
+ );
+ return builder;
+ }
+
+ ///
+ /// Run a simple action when the host has stopping
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static T OnHostStopping(this T builder, Func action) where T : IHostApplicationBuilder
+ {
+ builder.Services.AddSingleton(new ApplicationLifecycleRegistration(nameof(IHostedLifecycleService.StoppingAsync), (provider, _) => action(provider)));
+ return builder;
+ }
+
+ ///
+ /// Run a simple action when the host has stopping
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static T OnHostStopping(this T builder, Func action) where T : IHostApplicationBuilder
+ {
+ builder.Services.AddSingleton(new ApplicationLifecycleRegistration(nameof(IHostedLifecycleService.StoppingAsync), action));
+ return builder;
+ }
+
+ ///
+ /// Run a simple action when the host has stopped
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static T OnHostStopped(this T builder, Action action) where T : IHostApplicationBuilder
+ {
+ builder.Services.AddSingleton(
+ new ApplicationLifecycleRegistration(
+ nameof(IHostedLifecycleService.StoppedAsync),
+ (provider, _) =>
+ {
+ action(provider);
+ return Task.CompletedTask;
+ }
+ )
+ );
+ return builder;
+ }
+
+ ///
+ /// Run a simple action when the host has stopped
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static T OnHostStopped(this T builder, Func action) where T : IHostApplicationBuilder
+ {
+ builder.Services.AddSingleton(new ApplicationLifecycleRegistration(nameof(IHostedLifecycleService.StoppedAsync), (provider, _) => action(provider)));
+ return builder;
+ }
+
+ ///
+ /// Run a simple action when the host has stopped
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static T OnHostStopped(this T builder, Func action) where T : IHostApplicationBuilder
+ {
+ builder.Services.AddSingleton(new ApplicationLifecycleRegistration(nameof(IHostedLifecycleService.StoppedAsync), action));
+ return builder;
+ }
+}
\ No newline at end of file
diff --git a/src/Hosting/ApplicationLifecycleRegistration.cs b/src/Hosting/ApplicationLifecycleRegistration.cs
new file mode 100644
index 000000000..e19859bf5
--- /dev/null
+++ b/src/Hosting/ApplicationLifecycleRegistration.cs
@@ -0,0 +1,3 @@
+namespace Rocket.Surgery.LaunchPad.Hosting;
+
+internal record ApplicationLifecycleRegistration(string Method, Func Action);
\ No newline at end of file
diff --git a/src/Hosting/ApplicationLifecycleService.cs b/src/Hosting/ApplicationLifecycleService.cs
new file mode 100644
index 000000000..2010002ce
--- /dev/null
+++ b/src/Hosting/ApplicationLifecycleService.cs
@@ -0,0 +1,37 @@
+using Microsoft.Extensions.Hosting;
+
+namespace Rocket.Surgery.LaunchPad.Hosting;
+
+internal class ApplicationLifecycleService
+ (IServiceProvider serviceProvider, IEnumerable registrations) : IHostedLifecycleService
+{
+ public Task StartAsync(CancellationToken cancellationToken)
+ {
+ return Task.CompletedTask;
+ }
+
+ public Task StopAsync(CancellationToken cancellationToken)
+ {
+ return Task.CompletedTask;
+ }
+
+ public Task StartingAsync(CancellationToken cancellationToken)
+ {
+ return Task.WhenAll(registrations.Where(z => z.Method == nameof(StartingAsync)).Select(z => z.Action(serviceProvider, cancellationToken)));
+ }
+
+ public Task StartedAsync(CancellationToken cancellationToken)
+ {
+ return Task.WhenAll(registrations.Where(z => z.Method == nameof(StartedAsync)).Select(z => z.Action(serviceProvider, cancellationToken)));
+ }
+
+ public Task StoppingAsync(CancellationToken cancellationToken)
+ {
+ return Task.WhenAll(registrations.Where(z => z.Method == nameof(StoppingAsync)).Select(z => z.Action(serviceProvider, cancellationToken)));
+ }
+
+ public Task StoppedAsync(CancellationToken cancellationToken)
+ {
+ return Task.WhenAll(registrations.Where(z => z.Method == nameof(StoppedAsync)).Select(z => z.Action(serviceProvider, cancellationToken)));
+ }
+}
\ No newline at end of file
diff --git a/src/Hosting/Conventions/HostingConvention.cs b/src/Hosting/Conventions/HostingConvention.cs
new file mode 100644
index 000000000..cdfe897a5
--- /dev/null
+++ b/src/Hosting/Conventions/HostingConvention.cs
@@ -0,0 +1,68 @@
+using System.Reflection;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Hosting;
+using Microsoft.Extensions.Logging;
+using OpenTelemetry;
+using OpenTelemetry.Resources;
+using Rocket.Surgery.Conventions;
+using Rocket.Surgery.Conventions.DependencyInjection;
+using Rocket.Surgery.Hosting;
+using Rocket.Surgery.LaunchPad.Serilog;
+using Rocket.Surgery.LaunchPad.Telemetry;
+
+namespace Rocket.Surgery.LaunchPad.Hosting.Conventions;
+
+[ExportConvention]
+internal class HostingConvention : IServiceConvention, IHostApplicationConvention, IOpenTelemetryConvention
+{
+ public void Register(IConventionContext context, IHostApplicationBuilder builder)
+ {
+ if (context.GetOrAdd(() => new LaunchPadLoggingOptions()).WriteToProviders != true)
+ {
+ var providers = builder.Services.Where(z => z.ServiceType == typeof(ILoggerProvider)).ToArray();
+ builder.Logging.ClearProviders();
+ builder.OnHostStarting(
+ provider => providers.Aggregate(
+ provider.GetRequiredService(),
+ (factory, descriptor) =>
+ {
+ switch (descriptor)
+ {
+ case { ImplementationFactory: { } method, } when method(provider) is ILoggerProvider p:
+ factory.AddProvider(p);
+ break;
+ case { ImplementationInstance: ILoggerProvider instance, }:
+ factory.AddProvider(instance);
+ break;
+ case { ImplementationType: { } type, } when ActivatorUtilities.CreateInstance(provider, type) is ILoggerProvider instance:
+ factory.AddProvider(instance);
+ break;
+ }
+
+ return factory;
+ }
+ )
+ );
+ }
+ }
+
+ public void Register(IConventionContext context, IConfiguration configuration, IOpenTelemetryBuilder builder)
+ {
+ builder.ConfigureResource(
+ z => z
+ .AddTelemetrySdk()
+ .AddService(
+ configuration["OTEL_SERVICE_NAME"] ?? context.Get()?.ApplicationName ?? "unknown",
+ "Syndicates",
+ Assembly.GetExecutingAssembly().GetCustomAttribute()?.InformationalVersion,
+ serviceInstanceId: configuration["WEBSITE_SITE_NAME"]
+ )
+ );
+ }
+
+ public void Register(IConventionContext context, IConfiguration configuration, IServiceCollection services)
+ {
+ services.AddHostedService();
+ }
+}
\ No newline at end of file
diff --git a/src/HotChocolate/Conventions/InstrumentationConvention.cs b/src/HotChocolate/Conventions/InstrumentationConvention.cs
index ece094307..a6d01de0c 100644
--- a/src/HotChocolate/Conventions/InstrumentationConvention.cs
+++ b/src/HotChocolate/Conventions/InstrumentationConvention.cs
@@ -16,7 +16,7 @@ namespace Rocket.Surgery.LaunchPad.HotChocolate.Conventions;
public class InstrumentationConvention : IOpenTelemetryConvention
{
///
- public void Register(IConventionContext conventionContext, IConfiguration configuration, IOpenTelemetryBuilder builder)
+ public void Register(IConventionContext context, IConfiguration configuration, IOpenTelemetryBuilder builder)
{
builder.WithTracing(b => b.AddHotChocolateInstrumentation());
}
diff --git a/src/Serilog/LaunchPadLoggingOptions.cs b/src/Serilog/LaunchPadLoggingOptions.cs
index 8b61c7a8f..eebe219d7 100644
--- a/src/Serilog/LaunchPadLoggingOptions.cs
+++ b/src/Serilog/LaunchPadLoggingOptions.cs
@@ -1,5 +1,3 @@
-using Microsoft.Extensions.Logging;
-
namespace Rocket.Surgery.LaunchPad.Serilog;
///
@@ -32,15 +30,10 @@ public class LaunchPadLoggingOptions
///
/// Base option from the serilog package
///
- public bool WriteToProviders { get; set; } = true;
+ public bool WriteToProviders { get; set; } = false;
///
/// Base option from the serilog package
///
public bool PreserveStaticLogger { get; set; }
-
- ///
- /// Set a custom logger factory
- ///
- public ILoggerFactory? LoggerFactory { get; set; }
-}
+}
\ No newline at end of file
diff --git a/src/Telemetry/IOpenTelemetryConvention.cs b/src/Telemetry/IOpenTelemetryConvention.cs
index 22a63e84a..0a950b1af 100644
--- a/src/Telemetry/IOpenTelemetryConvention.cs
+++ b/src/Telemetry/IOpenTelemetryConvention.cs
@@ -14,8 +14,8 @@ public interface IOpenTelemetryConvention : IConvention
///
/// Register metrics
///
- ///
+ ///
///
///
- void Register(IConventionContext conventionContext, IConfiguration configuration, IOpenTelemetryBuilder builder);
+ void Register(IConventionContext context, IConfiguration configuration, IOpenTelemetryBuilder builder);
}
\ No newline at end of file
diff --git a/test/Extensions.Tests/ConventionFakeTest.cs b/test/Extensions.Tests/ConventionFakeTest.cs
index 319309b24..773999ba5 100644
--- a/test/Extensions.Tests/ConventionFakeTest.cs
+++ b/test/Extensions.Tests/ConventionFakeTest.cs
@@ -1,4 +1,4 @@
-using System.Runtime.Loader;
+using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Rocket.Surgery.Conventions;
using Rocket.Surgery.Conventions.Testing;
@@ -13,10 +13,12 @@ protected async Task Init(Action? action = null)
var conventionContextBuilder = ConventionContextBuilder
.Create()
.ForTesting(Imports.Instance, LoggerFactory)
- .Set(AssemblyLoadContext.Default)
.WithLogger(Logger);
action?.Invoke(conventionContextBuilder);
+
var context = await ConventionContext.FromAsync(conventionContextBuilder);
+ var configuration = await new ConfigurationBuilder().ApplyConventionsAsync(context);
+ context.Set(configuration.Build());
Populate(await new ServiceCollection().ApplyConventionsAsync(context));
}
diff --git a/test/Extensions.Tests/Extensions.Tests.csproj b/test/Extensions.Tests/Extensions.Tests.csproj
index 9158f4084..58a56169b 100644
--- a/test/Extensions.Tests/Extensions.Tests.csproj
+++ b/test/Extensions.Tests/Extensions.Tests.csproj
@@ -9,12 +9,6 @@
-
-
-
-
-
-
diff --git a/test/Extensions.Tests/FakeClockConventionTests.cs b/test/Extensions.Tests/FakeClockConventionTests.cs
index f7b50c735..4cf63ebf6 100644
--- a/test/Extensions.Tests/FakeClockConventionTests.cs
+++ b/test/Extensions.Tests/FakeClockConventionTests.cs
@@ -1,7 +1,10 @@
-using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Options;
using NodaTime;
using NodaTime.Testing;
using Rocket.Surgery.Conventions;
+using Rocket.Surgery.LaunchPad.Foundation;
using Rocket.Surgery.LaunchPad.Testing;
namespace Extensions.Tests;
@@ -28,4 +31,29 @@ public async Task Clock_Convention_Override()
clock.GetCurrentInstant().Should().Be(Instant.FromUnixTimeSeconds(0));
clock.GetCurrentInstant().Should().Be(Instant.FromUnixTimeSeconds(0) + Duration.FromMinutes(1));
}
+}
+
+public class AutoRegisterOptions(ITestOutputHelper testOutputHelper) : ConventionFakeTest(testOutputHelper)
+{
+ [Fact]
+ public async Task Should_Register_Options()
+ {
+ await Init(x => x.ConfigureConfiguration(builder => builder.AddInMemoryCollection([new("OptionsA:A", "B"), new("OptionsB:B", "A"),])));
+ ServiceProvider.GetRequiredService>().Value.A.Should().Be("B");
+ ServiceProvider.GetRequiredService>().Value.B.Should().Be("A");
+ }
+
+ [RegisterOptionsConfiguration("OptionsA")]
+ [PublicAPI]
+ private class OptionsA
+ {
+ public string A { get; set; }
+ }
+
+ [RegisterOptionsConfiguration("OptionsB")]
+ [PublicAPI]
+ private class OptionsB
+ {
+ public string B { get; set; }
+ }
}
\ No newline at end of file
diff --git a/test/Extensions.Tests/Mapping/AutoMapperProfile.cs b/test/Extensions.Tests/Mapping/AutoMapperProfile.cs
index 4ee1d8634..7c75c8eb4 100644
--- a/test/Extensions.Tests/Mapping/AutoMapperProfile.cs
+++ b/test/Extensions.Tests/Mapping/AutoMapperProfile.cs
@@ -1,4 +1,3 @@
-using System.Runtime.Loader;
using AutoMapper;
using Rocket.Surgery.Conventions;
using Rocket.Surgery.Extensions.Testing;
@@ -252,8 +251,7 @@ public class AutoMapperConventionTests
public async Task ShouldRegisterAutoMapperTypes()
{
var conventionBuilder = new ConventionContextBuilder(new Dictionary