diff --git a/.github/workflows/nuget-publish.yml b/.github/workflows/nuget-publish.yml
index 2b4a141..b36a76d 100644
--- a/.github/workflows/nuget-publish.yml
+++ b/.github/workflows/nuget-publish.yml
@@ -31,6 +31,11 @@ jobs:
with:
dotnet-version: "9.0.x"
+ - name: Setup .NET 10
+ uses: actions/setup-dotnet@v4
+ with:
+ dotnet-version: "10.0.x"
+
- name: Restore dependencies
run: dotnet restore
@@ -41,7 +46,7 @@ jobs:
run: dotnet test --configuration Release --no-build --verbosity normal
- name: Pack
- run: dotnet pack --configuration Release --no-build --output ./nupkgs -p:IncludeSymbols=true -p:SymbolPackageFormat=snupkg
+ run: dotnet pack --configuration Release --output ./nupkgs -p:IncludeSymbols=true -p:SymbolPackageFormat=snupkg
- name: Publish
uses: actions/upload-artifact@v4
@@ -67,7 +72,7 @@ jobs:
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
- dotnet-version: "9.0.x"
+ dotnet-version: "10.0.x"
- name: Publish to NuGet
run: |
diff --git a/Directory.Build.props b/Directory.Build.props
index 28b43e0..b1b6c7e 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -12,7 +12,7 @@
Peter Nylander
LICENSE
README.md
- Copyright © 2025 Peter Nylander
+ Copyright © $([System.DateTime]::Now.Year) Peter Nylander
@@ -49,8 +49,8 @@
git
true
- https://github.com/penyland/infinity-tomahawk
- https://github.com/penyland/infinity-tomahawk
+ https://github.com/penyland/infinity-toolkit
+ https://github.com/penyland/infinity-toolkit
diff --git a/samples/AzureSample/AzureSample.csproj b/samples/AzureSample/AzureSample.csproj
index 4469668..3abbf72 100644
--- a/samples/AzureSample/AzureSample.csproj
+++ b/samples/AzureSample/AzureSample.csproj
@@ -9,9 +9,8 @@
-
-
-
+
+
diff --git a/samples/AzureSample/Program.cs b/samples/AzureSample/Program.cs
index bb79964..10f8aa1 100644
--- a/samples/AzureSample/Program.cs
+++ b/samples/AzureSample/Program.cs
@@ -1,5 +1,5 @@
using Azure.Identity;
-using Infinity.Toolkit.Azure.Configuration;
+using Infinity.Toolkit.Azure;
using Infinity.Toolkit.OpenApi;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
@@ -9,7 +9,13 @@
builder.ConfigureAzureAppConfiguration(configureSettings: options =>
{
- options.TokenCredential = new AzureCliCredential();
+ //options.TokenCredential = new VisualStudioCredential(new() { TenantId = "cf4e6228-1dc7-45f6-aa1c-71e47553e4ac" });
+ //options.TokenCredential = new AzureCliCredential(new() { TenantId = "cf4e6228-1dc7-45f6-aa1c-71e47553e4ac" });
+ //options.TokenCredential = new DefaultAzureCredential();
+ options.TokenCredential = new ChainedTokenCredential(
+ new AzureCliCredential(),
+ new VisualStudioCredential()
+ );
}, refreshOptions: refreshOptions =>
{
refreshOptions.SetRefreshInterval(TimeSpan.FromSeconds(15));
@@ -43,6 +49,7 @@
}
app.UseHttpsRedirection();
+app.UseAzureAppConfiguration();
app.MapGet("/config", ([FromServices] IConfiguration configuration) =>
{
diff --git a/samples/AzureSample/appsettings.json b/samples/AzureSample/appsettings.json
index 2a3eb48..49d8b97 100644
--- a/samples/AzureSample/appsettings.json
+++ b/samples/AzureSample/appsettings.json
@@ -22,7 +22,7 @@
"AppConfig": {
"ApplicationName": "",
"Endpoint": "",
- "GlobalKeyFilter": "Global",
+ "GlobalKeyFilter": "",
"UseFeatureFlags": true
}
}
diff --git a/samples/AzureServiceBusMessagingSample/AzureServiceBusMessagingSample.csproj b/samples/AzureServiceBusMessagingSample/AzureServiceBusMessagingSample.csproj
index 9b9856c..30b168d 100644
--- a/samples/AzureServiceBusMessagingSample/AzureServiceBusMessagingSample.csproj
+++ b/samples/AzureServiceBusMessagingSample/AzureServiceBusMessagingSample.csproj
@@ -9,8 +9,8 @@
-
-
+
+
diff --git a/samples/FeatureModulesSample.Module1/FeatureModulesSample.Module1.csproj b/samples/FeatureModulesSample.Module1/FeatureModulesSample.Module1.csproj
index 8d39c89..dbb5777 100644
--- a/samples/FeatureModulesSample.Module1/FeatureModulesSample.Module1.csproj
+++ b/samples/FeatureModulesSample.Module1/FeatureModulesSample.Module1.csproj
@@ -13,8 +13,8 @@
-
-
+
+
diff --git a/samples/FeatureModulesSample/FeatureModulesSample.csproj b/samples/FeatureModulesSample/FeatureModulesSample.csproj
index 5186432..3625f5e 100644
--- a/samples/FeatureModulesSample/FeatureModulesSample.csproj
+++ b/samples/FeatureModulesSample/FeatureModulesSample.csproj
@@ -9,9 +9,9 @@
-
-
-
+
+
+
diff --git a/samples/MediatorSample/MediatorSample.csproj b/samples/MediatorSample/MediatorSample.csproj
index b13950d..cc5f3d8 100644
--- a/samples/MediatorSample/MediatorSample.csproj
+++ b/samples/MediatorSample/MediatorSample.csproj
@@ -9,7 +9,7 @@
-
+
diff --git a/samples/MessagingSample/MessagingSample.csproj b/samples/MessagingSample/MessagingSample.csproj
index 2c52571..446bec9 100644
--- a/samples/MessagingSample/MessagingSample.csproj
+++ b/samples/MessagingSample/MessagingSample.csproj
@@ -9,8 +9,8 @@
-
-
+
+
diff --git a/samples/PipelineSample/PipelineSample.csproj b/samples/PipelineSample/PipelineSample.csproj
index 40a0c07..f21be1d 100644
--- a/samples/PipelineSample/PipelineSample.csproj
+++ b/samples/PipelineSample/PipelineSample.csproj
@@ -9,7 +9,7 @@
-
+
diff --git a/src/Infinity.Toolkit.AspNetCore/Infinity.Toolkit.AspNetCore.csproj b/src/Infinity.Toolkit.AspNetCore/Infinity.Toolkit.AspNetCore.csproj
index 02e7886..17ace32 100644
--- a/src/Infinity.Toolkit.AspNetCore/Infinity.Toolkit.AspNetCore.csproj
+++ b/src/Infinity.Toolkit.AspNetCore/Infinity.Toolkit.AspNetCore.csproj
@@ -1,11 +1,11 @@
- net9.0
+ net10.0;net9.0
enable
enable
Infinity.Toolkit.AspNetCore
- 1.0.0
+ 1.1.0
@@ -17,7 +17,7 @@
-
+
diff --git a/src/Infinity.Toolkit.Azure/Configuration/ConfigurationBuilderExtensions.cs b/src/Infinity.Toolkit.Azure/Configuration/ConfigurationBuilderExtensions.cs
index f8a94ae..866fc53 100644
--- a/src/Infinity.Toolkit.Azure/Configuration/ConfigurationBuilderExtensions.cs
+++ b/src/Infinity.Toolkit.Azure/Configuration/ConfigurationBuilderExtensions.cs
@@ -6,7 +6,7 @@
using System.Data.Common;
using System.Text.Json.Serialization;
-namespace Infinity.Toolkit.Azure.Configuration;
+namespace Infinity.Toolkit.Azure;
// Config section specifications
//"Infinity": {
@@ -23,7 +23,7 @@ namespace Infinity.Toolkit.Azure.Configuration;
public class AzureAppConfigSettings
{
- internal const string DefaultConfigSectionName = "Infinity:Azure:AppConfig";
+ internal const string DefaultConfigSectionName = "AzureAppConfiguration";
public string ApplicationName { get; set; }
@@ -33,10 +33,10 @@ public class AzureAppConfigSettings
public bool UseFeatureFlags { get; set; } = true;
- public bool UseKeyVault { get; set; } = true;
+ public bool UseKeyVault { get; set; } = false;
[JsonIgnore]
- public TokenCredential? TokenCredential { get; set; } = Identity.TokenCredentialHelper.GetTokenCredential();
+ public TokenCredential? TokenCredential { get; set; }
internal void ParseConnectionString(string? connectionString)
{
@@ -84,52 +84,63 @@ configuration section.
public static class ConfigurationBuilderExtensions
{
- private const string DefaultConfigSectionName = "Infinity:Azure:AppConfig";
-
public static IHostApplicationBuilder ConfigureAzureAppConfiguration(this IHostApplicationBuilder builder)
- => builder.ConfigureAzureAppConfiguration(DefaultConfigSectionName, null, null);
+ => builder.ConfigureAzureAppConfiguration(AzureAppConfigSettings.DefaultConfigSectionName, null, null);
public static IHostApplicationBuilder ConfigureAzureAppConfiguration(this IHostApplicationBuilder app, Action? configure = null, Action? refreshOptions = null)
- => app.ConfigureAzureAppConfiguration(DefaultConfigSectionName, configure, refreshOptions);
+ => app.ConfigureAzureAppConfiguration(AzureAppConfigSettings.DefaultConfigSectionName, configure, refreshOptions);
- public static IHostApplicationBuilder ConfigureAzureAppConfiguration(this IHostApplicationBuilder builder, string configSectionName = DefaultConfigSectionName, Action? configureSettings = null, Action? refreshOptions = null)
+ public static IHostApplicationBuilder ConfigureAzureAppConfiguration(this IHostApplicationBuilder builder, string configSectionName = AzureAppConfigSettings.DefaultConfigSectionName, Action? configureSettings = null, Action? refreshOptions = null)
{
ArgumentNullException.ThrowIfNull(builder, nameof(builder));
var settings = new AzureAppConfigSettings()
{
- ApplicationName = builder.Environment.ApplicationName
+ ApplicationName = builder.Environment.ApplicationName,
+ TokenCredential = Identity.TokenCredentialHelper.GetTokenCredential()
};
builder.Configuration.GetSection(configSectionName).Bind(settings);
configureSettings?.Invoke(settings);
+ builder.Services.AddAzureAppConfiguration();
+
builder.Configuration.AddAzureAppConfiguration(options =>
{
if (builder.Configuration.GetConnectionString("AzureAppConfig") is string connectionString)
{
settings.ParseConnectionString(connectionString);
- options.Connect(builder.Configuration.GetConnectionString("AzureAppConfig"));
+ options.Connect(connectionString);
}
else
{
- if (Uri.TryCreate(settings.Endpoint.ToString(), UriKind.Absolute, out var endpointUri))
+ // Try to use configured endpoint
+ if (settings.Endpoint != null && Uri.TryCreate(settings.Endpoint.ToString(), UriKind.Absolute, out var endpointUri))
{
- options.Connect(endpointUri, settings.TokenCredential);
+ // Endpoint from settings is valid
}
else
{
- throw new InvalidOperationException($"""
- The 'Endpoint' key in
- '{configSectionName}') isn't a valid URI.
+ // Try to get endpoint from environment variable
+ var envEndpoint = Environment.GetEnvironmentVariable("AZURE_APP_CONFIG_ENDPOINT");
+ if (!Uri.TryCreate(envEndpoint, UriKind.Absolute, out endpointUri))
+ {
+ throw new InvalidOperationException($"""
+ ConnectionString is missing.
+ It should be provided in 'ConnectionStrings:AzureAppConfig'
+ or '{configSectionName}:Endpoint' key
+ configuration section or 'AZURE_APP_CONFIG_ENDPOINT' environment variable.
""");
+ }
}
+
+ options.Connect(endpointUri, settings.TokenCredential);
}
if (!string.IsNullOrEmpty(settings.GlobalKeyFilter))
{
// Filter by global key filter
options
- .Select($"{settings.GlobalKeyFilter}*")
+ .Select($"{settings.GlobalKeyFilter}*", LabelFilter.Null)
.Select($"{settings.GlobalKeyFilter}*", builder.Environment.EnvironmentName)
.TrimKeyPrefix($"{settings.GlobalKeyFilter}:");
}
@@ -138,7 +149,7 @@ public static IHostApplicationBuilder ConfigureAzureAppConfiguration(this IHostA
{
// Filter by application name
options
- .Select($"{settings.ApplicationName}*")
+ .Select($"{settings.ApplicationName}*", LabelFilter.Null)
.Select($"{settings.ApplicationName}*", builder.Environment.EnvironmentName)
.TrimKeyPrefix(settings.ApplicationName + ":");
}
@@ -162,7 +173,10 @@ public static IHostApplicationBuilder ConfigureAzureAppConfiguration(this IHostA
});
}
- options.ConfigureRefresh(refreshOptions);
+ if (refreshOptions != null)
+ {
+ options.ConfigureRefresh(refreshOptions);
+ }
});
return builder;
diff --git a/src/Infinity.Toolkit.Azure/EnvironmentHelper.cs b/src/Infinity.Toolkit.Azure/EnvironmentHelper.cs
new file mode 100644
index 0000000..c45f849
--- /dev/null
+++ b/src/Infinity.Toolkit.Azure/EnvironmentHelper.cs
@@ -0,0 +1,14 @@
+namespace Infinity.Toolkit.Azure;
+
+internal static class EnvironmentHelper
+{
+ public static bool IsRunningInContainer => Equals(Environment.GetEnvironmentVariable("DOTNET_RUNNING_IN_CONTAINER"), "true");
+
+ public static bool IsRunningInAzureAppService => Equals(Environment.GetEnvironmentVariable("WEBSITE_SITE_NAME"), "true");
+
+ public static bool IsRunningInAzureContainerApps => IsRunningInContainer && !string.IsNullOrEmpty(Environment.GetEnvironmentVariable("CONTAINER_APP_NAME"));
+
+ public static bool IsRunningInAzureFunctions => !string.IsNullOrEmpty(Environment.GetEnvironmentVariable("FUNCTIONS_WORKER_RUNTIME"));
+
+ public static bool IsRunningInAzure => IsRunningInAzureAppService || IsRunningInAzureContainerApps || IsRunningInAzureFunctions;
+}
diff --git a/src/Infinity.Toolkit.Azure/Identity/TokenCredentialHelper.cs b/src/Infinity.Toolkit.Azure/Identity/TokenCredentialHelper.cs
index c46c97b..7666c2f 100644
--- a/src/Infinity.Toolkit.Azure/Identity/TokenCredentialHelper.cs
+++ b/src/Infinity.Toolkit.Azure/Identity/TokenCredentialHelper.cs
@@ -7,11 +7,13 @@ public static class TokenCredentialHelper
{
///
/// Helps creating a ChainedTokenCredential used to authenticate with Azure services.
- /// By default, the following credential types are included:
+ /// By default if the application is running in Azure (App Service, Functions, Container Apps), the following credential types are included:
/// EnvironmentCredential
/// ManagedIdentityCredential
///
- /// To include additional credential types, set the corresponding environment variable to "true".
+ /// If the application is not running in Azure, only the EnvironmentCredential is included by default.
+ ///
+ /// To include additional credential types, set the value of the corresponding environment variable to "true".
/// INCLUDE_VISUAL_STUDIO_CREDENTIAL
/// INCLUDE_VISUAL_STUDIO_CODE_CREDENTIAL
/// INCLUDE_INTERACTIVE_BROWSER_CREDENTIAL
@@ -19,52 +21,65 @@ public static class TokenCredentialHelper
/// INCLUDE_AZURE_POWER_SHELL_CREDENTIAL
/// INCLUDE_AZURE_CLI_CREDENTIAL
/// INCLUDE_WORKLOAD_IDENTITY_CREDENTIAL
- ///
///
- /// A ChainedTokenCredential with the specified credential types.
- public static TokenCredential GetTokenCredential()
+ /// The client ID of the user-assigned managed identity. If null, the AZURE_CLIENT_ID environment variable will be used.
+ /// A ChainedTokenCredential with the specified credential types or DefaultAzureCredentials if no credentials are specified.
+ public static TokenCredential GetTokenCredential(string? clientId = null)
{
TokenCredential[] tokenCredentials =[];
- if (Equals(Environment.GetEnvironmentVariable("INCLUDE_AZURE_CLI_CREDENTIAL"), "true"))
+ // First check if the app is running in Azure
+ if (EnvironmentHelper.IsRunningInAzure)
{
- tokenCredentials = [.. tokenCredentials, new AzureCliCredential()];
- }
+ tokenCredentials = [
+ new EnvironmentCredential(),
+ new ManagedIdentityCredential(ManagedIdentityId.FromUserAssignedClientId(clientId ?? Environment.GetEnvironmentVariable("AZURE_CLIENT_ID") ?? string.Empty))];
- if (Equals(Environment.GetEnvironmentVariable("INCLUDE_WORKLOAD_IDENTITY_CREDENTIAL"), "true"))
- {
- tokenCredentials = [.. tokenCredentials, new WorkloadIdentityCredential()];
+ var tokenCredential = new ChainedTokenCredential(tokenCredentials);
+ return tokenCredential;
}
-
- if (Equals(Environment.GetEnvironmentVariable("INCLUDE_AZURE_DEVELOPER_CLI_CREDENTIAL"), "true"))
+ else
{
- tokenCredentials = [.. tokenCredentials, new AzureDeveloperCliCredential()];
- }
+ if (Equals(Environment.GetEnvironmentVariable("INCLUDE_AZURE_CLI_CREDENTIAL"), "true"))
+ {
+ tokenCredentials = [.. tokenCredentials, new AzureCliCredential()];
+ }
- if (Equals(Environment.GetEnvironmentVariable("INCLUDE_VISUAL_STUDIO_CREDENTIAL"), "true"))
- {
- tokenCredentials = [.. tokenCredentials, new VisualStudioCredential()];
- }
+ if (Equals(Environment.GetEnvironmentVariable("INCLUDE_WORKLOAD_IDENTITY_CREDENTIAL"), "true"))
+ {
+ tokenCredentials = [.. tokenCredentials, new WorkloadIdentityCredential()];
+ }
- if (Equals(Environment.GetEnvironmentVariable("INCLUDE_VISUAL_STUDIO_CODE_CREDENTIAL"), "true"))
- {
- tokenCredentials = [.. tokenCredentials, new VisualStudioCodeCredential()];
- }
+ if (Equals(Environment.GetEnvironmentVariable("INCLUDE_AZURE_DEVELOPER_CLI_CREDENTIAL"), "true"))
+ {
+ tokenCredentials = [.. tokenCredentials, new AzureDeveloperCliCredential()];
+ }
- if (Equals(Environment.GetEnvironmentVariable("INCLUDE_AZURE_POWER_SHELL_CREDENTIAL"), "true"))
- {
- tokenCredentials = [.. tokenCredentials, new AzurePowerShellCredential()];
- }
+ if (Equals(Environment.GetEnvironmentVariable("INCLUDE_VISUAL_STUDIO_CREDENTIAL"), "true"))
+ {
+ tokenCredentials = [.. tokenCredentials, new VisualStudioCredential()];
+ }
- if (Equals(Environment.GetEnvironmentVariable("INCLUDE_INTERACTIVE_BROWSER_CREDENTIAL"), "true"))
- {
- tokenCredentials = [.. tokenCredentials, new InteractiveBrowserCredential()];
- }
+ if (Equals(Environment.GetEnvironmentVariable("INCLUDE_VISUAL_STUDIO_CODE_CREDENTIAL"), "true"))
+ {
+ tokenCredentials = [.. tokenCredentials, new VisualStudioCodeCredential()];
+ }
- tokenCredentials = [.. tokenCredentials, new EnvironmentCredential(), new ManagedIdentityCredential()];
+ if (Equals(Environment.GetEnvironmentVariable("INCLUDE_AZURE_POWER_SHELL_CREDENTIAL"), "true"))
+ {
+ tokenCredentials = [.. tokenCredentials, new AzurePowerShellCredential()];
+ }
- var tokenCredential = new ChainedTokenCredential(tokenCredentials);
+ if (Equals(Environment.GetEnvironmentVariable("INCLUDE_INTERACTIVE_BROWSER_CREDENTIAL"), "true"))
+ {
+ tokenCredentials = [.. tokenCredentials, new InteractiveBrowserCredential()];
+ }
- return tokenCredential;
+ return tokenCredentials.Length switch
+ {
+ 0 => new DefaultAzureCredential(),
+ _ => new ChainedTokenCredential(tokenCredentials)
+ };
+ }
}
}
diff --git a/src/Infinity.Toolkit.Azure/Infinity.Toolkit.Azure.csproj b/src/Infinity.Toolkit.Azure/Infinity.Toolkit.Azure.csproj
index 377ceb0..3d5245b 100644
--- a/src/Infinity.Toolkit.Azure/Infinity.Toolkit.Azure.csproj
+++ b/src/Infinity.Toolkit.Azure/Infinity.Toolkit.Azure.csproj
@@ -1,12 +1,11 @@
- net9.0
+ net10.0;net9.0
enable
enable
Infinity.Toolkit.Azure
- 0.1.3
- false
+ 1.0.0
@@ -15,8 +14,8 @@
-
-
+
+
diff --git a/src/Infinity.Toolkit.EntityFramework/Infinity.Toolkit.EntityFramework.csproj b/src/Infinity.Toolkit.EntityFramework/Infinity.Toolkit.EntityFramework.csproj
index 25ead20..3a704a6 100644
--- a/src/Infinity.Toolkit.EntityFramework/Infinity.Toolkit.EntityFramework.csproj
+++ b/src/Infinity.Toolkit.EntityFramework/Infinity.Toolkit.EntityFramework.csproj
@@ -5,7 +5,7 @@
enable
enable
Infinity.Toolkit.EntityFramework
- 1.0.0
+ 1.0.1
false
@@ -14,7 +14,7 @@
-
+
diff --git a/src/Infinity.Toolkit.Experimental/Infinity.Toolkit.Experimental.csproj b/src/Infinity.Toolkit.Experimental/Infinity.Toolkit.Experimental.csproj
index 2b9be59..a5322ce 100644
--- a/src/Infinity.Toolkit.Experimental/Infinity.Toolkit.Experimental.csproj
+++ b/src/Infinity.Toolkit.Experimental/Infinity.Toolkit.Experimental.csproj
@@ -18,9 +18,9 @@
-
+
-
+
diff --git a/src/Infinity.Toolkit.FeatureModules/FeatureModule.cs b/src/Infinity.Toolkit.FeatureModules/FeatureModule.cs
index 05e1fbe..251a724 100644
--- a/src/Infinity.Toolkit.FeatureModules/FeatureModule.cs
+++ b/src/Infinity.Toolkit.FeatureModules/FeatureModule.cs
@@ -5,7 +5,7 @@
///
public abstract class FeatureModule : IFeatureModule
{
- public virtual IModuleInfo? ModuleInfo => new FeatureModuleInfo(nameof(FeatureModule), Assembly.GetExecutingAssembly()?.GetName()?.Version?.ToString() ?? "1.0.0");
+ public abstract IModuleInfo? ModuleInfo { get; }
public virtual ModuleContext RegisterModule(ModuleContext moduleContext) => moduleContext;
}
@@ -16,9 +16,9 @@ public abstract class FeatureModule : IFeatureModule
///
public abstract class WebFeatureModule : IWebFeatureModule
{
- public virtual IModuleInfo? ModuleInfo => new FeatureModuleInfo(nameof(WebFeatureModule), Assembly.GetExecutingAssembly()?.GetName()?.Version?.ToString() ?? "1.0.0");
+ public abstract IModuleInfo? ModuleInfo { get; }
- public virtual void RegisterModule(WebApplicationBuilder builder) { }
+ public virtual void RegisterModule(IHostApplicationBuilder builder) { }
public virtual void MapEndpoints(WebApplication app) { }
}
diff --git a/src/Infinity.Toolkit.FeatureModules/IFeatureModule.cs b/src/Infinity.Toolkit.FeatureModules/IFeatureModule.cs
index ce36b73..b97420f 100644
--- a/src/Infinity.Toolkit.FeatureModules/IFeatureModule.cs
+++ b/src/Infinity.Toolkit.FeatureModules/IFeatureModule.cs
@@ -43,5 +43,5 @@ public interface IWebFeatureModule : IFeatureModuleBase
///
/// Register all dependencies needed by a web module in the DI-container.
///
- void RegisterModule(WebApplicationBuilder builder);
+ void RegisterModule(IHostApplicationBuilder builder);
}
diff --git a/src/Infinity.Toolkit.FeatureModules/Infinity.Toolkit.FeatureModules.csproj b/src/Infinity.Toolkit.FeatureModules/Infinity.Toolkit.FeatureModules.csproj
index 25ad52d..12ca6b8 100644
--- a/src/Infinity.Toolkit.FeatureModules/Infinity.Toolkit.FeatureModules.csproj
+++ b/src/Infinity.Toolkit.FeatureModules/Infinity.Toolkit.FeatureModules.csproj
@@ -1,10 +1,10 @@
- net9.0;net8.0
+ net10.0;net9.0;net8.0
enable
enable
- 1.2.1
+ 1.3.0
Infinity.Toolkit.FeatureModules
Infinity Toolkit Feature Modules let's you automatically register dependencies and endpoints in modules which simplifies development when you are working with vertical feature slices.
FeatureModules;VerticalSliceArchitecture;ModularMonoliths;MinimalApis
@@ -19,7 +19,7 @@
-
+
diff --git a/src/Infinity.Toolkit.FeatureModules/ServiceCollectionExtensions.cs b/src/Infinity.Toolkit.FeatureModules/ServiceCollectionExtensions.cs
deleted file mode 100644
index 47e7836..0000000
--- a/src/Infinity.Toolkit.FeatureModules/ServiceCollectionExtensions.cs
+++ /dev/null
@@ -1,104 +0,0 @@
-using Infinity.Toolkit.LogFormatter;
-using Microsoft.Extensions.DependencyInjection.Extensions;
-
-namespace Infinity.Toolkit.FeatureModules;
-
-public static class ServiceCollectionExtensions
-{
- ///
- /// Add all feature modules that are found in all assemblies.
- ///
- public static IServiceCollection AddFeatureModules(this IServiceCollection services, HostBuilderContext hostBuilderContext, ILoggerFactory? loggerFactory)
- {
- return services.AddFeatureModules(hostBuilderContext, options => { }, loggerFactory);
- }
-
- ///
- /// Add all feature modules that are found in all assemblies.
- ///
- public static IServiceCollection AddFeatureModules(this IServiceCollection services, HostBuilderContext hostBuilderContext, Action configure, ILoggerFactory? loggerFactory)
- {
- var options = new FeatureModuleOptions();
- services.TryAddSingleton(options);
- configure(options);
-
- return services.RegisterFeatureModules(hostBuilderContext.Configuration, hostBuilderContext.HostingEnvironment, options, loggerFactory);
- }
-
- internal static IServiceCollection RegisterFeatureModules(this IServiceCollection services, IConfiguration configuration, IHostEnvironment hostEnvironment, FeatureModuleOptions options, ILoggerFactory? loggerFactory)
- {
- loggerFactory ??= LoggerFactory.Create(builder =>
- {
- builder
- .AddConfiguration(configuration.GetSection("Logging"))
-#if DEBUG
- .AddDebug()
-#endif
- .AddConsole(options => options.FormatterName = "CodeThemeConsoleFormatter").AddConsoleFormatter();
- });
- var logger = loggerFactory.CreateLogger("Infinity.Toolkit.FeatureModules");
-
- try
- {
- logger?.LogDebug(new EventId(1000, "Scanning"), "Scanning assemblies for feature modules...");
-
- var discoveredModules = ModuleUtilities.DiscoverModules(options, logger);
- RegisterModules(discoveredModules, services, configuration, hostEnvironment, logger);
-
- logger?.LogDebug(new EventId(1003, "ScanningComplete"), "Registering feature modules completed.");
-
- return services;
- }
- catch (Exception ex)
- {
- logger.LogError(new EventId(5000, "ScanningFailed"), "Failed to register feature modules. {ex}", ex.Message);
- return services;
- }
- }
-
- ///
- /// Register all classes implementing IFeatureModule while scanning the project to IServiceCollection.
- ///
- /// List of found feature modules.
- /// The .
- /// The .
- /// The .
- /// The .
- /// Thrown if no modules are found while scanning.
- private static void RegisterModules(IEnumerable discoveredModules, IServiceCollection services, IConfiguration configuration, IHostEnvironment hostEnvironment, ILogger? logger)
- {
- ArgumentNullException.ThrowIfNull(discoveredModules, nameof(discoveredModules));
- ArgumentNullException.ThrowIfNull(services, nameof(services));
-
- Dictionary registeredFeatureModules = [];
-
- var serviceDescriptors = discoveredModules
- .Select(type => ServiceDescriptor.Transient(typeof(IFeatureModuleBase), type));
- services.TryAddEnumerable(serviceDescriptors);
-
- var modules = discoveredModules
- .Select(Activator.CreateInstance)
- .Cast();
-
- foreach (var module in modules)
- {
- logger?.LogDebug(new EventId(1002, "RegisteringModules"), "Registering feature module: {module} - v{version}", module.GetType().FullName, module.ModuleInfo?.Version);
- registeredFeatureModules.Add(module.GetType(), module);
-
- if (module is IFeatureModule featureModule)
- {
- featureModule.RegisterModule(new()
- {
- Configuration = configuration,
- Environment = hostEnvironment,
- Services = services
- });
- }
- }
-
- services.Configure(options =>
- {
- options.AdditionalAssemblies.AddRange([.. registeredFeatureModules.Keys.Select(x => x.Assembly)]);
- });
- }
-}
diff --git a/src/Infinity.Toolkit.FeatureModules/WebApplicationBuilderExtensions.cs b/src/Infinity.Toolkit.FeatureModules/WebApplicationBuilderExtensions.cs
index 5903088..b078c22 100644
--- a/src/Infinity.Toolkit.FeatureModules/WebApplicationBuilderExtensions.cs
+++ b/src/Infinity.Toolkit.FeatureModules/WebApplicationBuilderExtensions.cs
@@ -80,7 +80,7 @@ internal static WebApplicationBuilder RegisterFeatureModules(this WebApplication
/// The .
/// The .
/// Thrown if no modules are found while scanning.
- private static void RegisterModules(IEnumerable discoveredModules, WebApplicationBuilder builder, ILogger? logger)
+ private static void RegisterModules(IEnumerable discoveredModules, IHostApplicationBuilder builder, ILogger? logger)
{
ArgumentNullException.ThrowIfNull(discoveredModules, nameof(discoveredModules));
ArgumentNullException.ThrowIfNull(builder, nameof(builder));
@@ -97,15 +97,22 @@ private static void RegisterModules(IEnumerable discoveredModules, Web
foreach (var module in modules)
{
- logger?.LogDebug(new EventId(1002, "RegisteringModules"), "Registering feature module: {module} - Version: {version}", module.GetType().FullName, module.ModuleInfo?.Version);
+ if (registeredFeatureModules.ContainsKey(module.GetType()))
+ {
+ logger?.LogWarning(new EventId(1001, "RegisteringModules"), "Module {module} is already registered. Skipping duplicate registration.", module.GetType().FullName);
+ continue;
+ }
+
registeredFeatureModules.Add(module.GetType(), module);
if (module is IWebFeatureModule webModule)
{
+ logger?.LogInformation(new EventId(1002, "RegisteringModules"), "Registering web feature module: {module}", module.GetType().FullName);
webModule.RegisterModule(builder);
}
else if (module is IFeatureModule featureModule)
{
+ logger?.LogInformation(new EventId(1002, "RegisteringModules"), "Registering feature module: {module}", module.GetType().FullName);
featureModule?.RegisterModule(new()
{
Configuration = builder.Configuration,
diff --git a/src/Infinity.Toolkit.IntegrationTests/Infinity.Toolkit.IntegrationTests.csproj b/src/Infinity.Toolkit.IntegrationTests/Infinity.Toolkit.IntegrationTests.csproj
index 99b32b8..e8641d5 100644
--- a/src/Infinity.Toolkit.IntegrationTests/Infinity.Toolkit.IntegrationTests.csproj
+++ b/src/Infinity.Toolkit.IntegrationTests/Infinity.Toolkit.IntegrationTests.csproj
@@ -1,19 +1,19 @@
- net9.0
+ net10.0;net9.0
enable
enable
Infinity.Toolkit.IntegrationTests
- 1.0.0
+ 1.1.0
false
-
-
-
-
+
+
+
+
diff --git a/src/Infinity.Toolkit.LogFormatter/Infinity.Toolkit.LogFormatter.csproj b/src/Infinity.Toolkit.LogFormatter/Infinity.Toolkit.LogFormatter.csproj
index f1adbbe..8ec6412 100644
--- a/src/Infinity.Toolkit.LogFormatter/Infinity.Toolkit.LogFormatter.csproj
+++ b/src/Infinity.Toolkit.LogFormatter/Infinity.Toolkit.LogFormatter.csproj
@@ -1,10 +1,10 @@
- net9.0;net8.0
+ net10.0;net9.0;net8.0
enable
enable
- 1.0.7
+ 1.1.0
Infinity.Toolkit.LogFormatter
A logging formatter that formats log messages with a Visual Studio Code inspired theme and Serilog like formatting.
Logging formatter
@@ -15,8 +15,8 @@
-
-
+
+
diff --git a/src/Infinity.Toolkit.Messaging.AzureServiceBus/Infinity.Toolkit.Messaging.AzureServiceBus.csproj b/src/Infinity.Toolkit.Messaging.AzureServiceBus/Infinity.Toolkit.Messaging.AzureServiceBus.csproj
index 8704c24..2c36ee3 100644
--- a/src/Infinity.Toolkit.Messaging.AzureServiceBus/Infinity.Toolkit.Messaging.AzureServiceBus.csproj
+++ b/src/Infinity.Toolkit.Messaging.AzureServiceBus/Infinity.Toolkit.Messaging.AzureServiceBus.csproj
@@ -1,10 +1,10 @@
- net9.0
+ net10.0;net9.0
enable
enable
- 1.0.4
+ 1.1.0
Azure Service Bus Integration for Infinity.Toolkit.Messaging.
Infinity.Toolkit.Messaging.AzureServiceBus
@@ -18,7 +18,7 @@
-
+
diff --git a/src/Infinity.Toolkit.Messaging/Infinity.Toolkit.Messaging.csproj b/src/Infinity.Toolkit.Messaging/Infinity.Toolkit.Messaging.csproj
index e12021f..8301f35 100644
--- a/src/Infinity.Toolkit.Messaging/Infinity.Toolkit.Messaging.csproj
+++ b/src/Infinity.Toolkit.Messaging/Infinity.Toolkit.Messaging.csproj
@@ -1,9 +1,9 @@
- net9.0
+ net10.0;net9.0
Infinity.Toolkit.Messaging
- 1.0.5
+ 1.1.0
@@ -16,18 +16,17 @@
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
-
-
+
diff --git a/src/Infinity.Toolkit.OpenApi/Infinity.Toolkit.OpenApi.csproj b/src/Infinity.Toolkit.OpenApi/Infinity.Toolkit.OpenApi.csproj
index 290eb55..889fe2f 100644
--- a/src/Infinity.Toolkit.OpenApi/Infinity.Toolkit.OpenApi.csproj
+++ b/src/Infinity.Toolkit.OpenApi/Infinity.Toolkit.OpenApi.csproj
@@ -5,7 +5,7 @@
enable
enable
Infinity.Toolkit.OpenApi
- 0.1.3
+ 0.1.4
false
@@ -14,9 +14,9 @@
-
-
-
+
+
+
diff --git a/src/Infinity.Toolkit.TestUtils/Infinity.Toolkit.TestUtils.csproj b/src/Infinity.Toolkit.TestUtils/Infinity.Toolkit.TestUtils.csproj
index c46ff90..920ef10 100644
--- a/src/Infinity.Toolkit.TestUtils/Infinity.Toolkit.TestUtils.csproj
+++ b/src/Infinity.Toolkit.TestUtils/Infinity.Toolkit.TestUtils.csproj
@@ -14,13 +14,13 @@
-
-
-
-
-
-
-
+
+
+
+
+
+
+
diff --git a/src/Infinity.Toolkit/EnvironmentHelper.cs b/src/Infinity.Toolkit/EnvironmentHelper.cs
index 6a2e10d..a1ca90a 100644
--- a/src/Infinity.Toolkit/EnvironmentHelper.cs
+++ b/src/Infinity.Toolkit/EnvironmentHelper.cs
@@ -4,7 +4,7 @@ public static partial class EnvironmentHelper
{
public static bool IsRunningInContainer => Equals(Environment.GetEnvironmentVariable("DOTNET_RUNNING_IN_CONTAINER"), "true");
- public static bool IsRunningInAzureAppService => Equals(Environment.GetEnvironmentVariable("WEBSITE_SITE_NAME"), "true");
+ public static bool IsRunningInKubernetes => !string.IsNullOrEmpty(Environment.GetEnvironmentVariable("KUBERNETES_SERVICE_HOST"));
- public static bool IsRunningInAzureContainerApps => IsRunningInContainer && !string.IsNullOrEmpty(Environment.GetEnvironmentVariable("CONTAINER_APP_NAME"));
+ public static bool IsRunningInDockerDesktop => IsRunningInContainer && Equals(Environment.GetEnvironmentVariable("DOCKER_DESKTOP_ENVIRONMENT"), "true");
}
diff --git a/src/Infinity.Toolkit/Infinity.Toolkit.csproj b/src/Infinity.Toolkit/Infinity.Toolkit.csproj
index 9748f39..1ea7f69 100644
--- a/src/Infinity.Toolkit/Infinity.Toolkit.csproj
+++ b/src/Infinity.Toolkit/Infinity.Toolkit.csproj
@@ -5,7 +5,7 @@
enable
enable
Infinity.Toolkit
- 1.1.0
+ 1.2.0
@@ -13,10 +13,10 @@
-
+
-
+
diff --git a/tests/Infinity.Toolkit.Tests/Infinity.Toolkit.Tests.csproj b/tests/Infinity.Toolkit.Tests/Infinity.Toolkit.Tests.csproj
index adbcfbe..e55709d 100644
--- a/tests/Infinity.Toolkit.Tests/Infinity.Toolkit.Tests.csproj
+++ b/tests/Infinity.Toolkit.Tests/Infinity.Toolkit.Tests.csproj
@@ -1,7 +1,7 @@
- net9.0
+ net10.0
enable
enable
false
@@ -11,7 +11,7 @@
-
+
@@ -32,8 +32,4 @@
-
-
-
-