ServiceRegistryModules 1.2.0
dotnet add package ServiceRegistryModules --version 1.2.0
NuGet\Install-Package ServiceRegistryModules -Version 1.2.0
<PackageReference Include="ServiceRegistryModules" Version="1.2.0" />
paket add ServiceRegistryModules --version 1.2.0
#r "nuget: ServiceRegistryModules, 1.2.0"
// Install ServiceRegistryModules as a Cake Addin #addin nuget:?package=ServiceRegistryModules&version=1.2.0 // Install ServiceRegistryModules as a Cake Tool #tool nuget:?package=ServiceRegistryModules&version=1.2.0
ServiceRegistryModules
ServiceRegistryModules is a package that allows you use modules to register services using Microsoft's native
IServiceCollection
. Some of the benefits you get from this are:
- Reducing the size of bloated
Startup
classes - Ability to move service registration closer to servies being registered
- Add custom providers to inject into the registry modules
- Using the built-in
IConfiguration
to dynamically change runtime services - Integration with the .NET 6
WebApplicationBuilder
Install the packages
There are 3 available packages to choose from to suit your needs:
ServiceRegistryModules
- Provides the core funtionality for creating registry modules for your services.ServiceRegistryModules.Abstractions
- Contains just the abstract classes and interfaces needed to implement a registry. Use this in projects where you want to define a registry, but don't need the ability to apply the registry (Included inServiceRegistryModules
).ServiceRegistryModules.AspNetCore
- ExtendsServiceRegistryModules
by adding integration with theWebApplicationBuilder
introduced in .NET 6.
Defining a registry
To define a registry, create a class that implements IRegistryModule
. This interface contains the following three implementation details:
ConfigureServices(IServiceCollection)
- The method that gets run to register your custom services.TargetEnvironments
- A collection of strings indicating which environments the registry should apply to. If it should be applied regardless of environment, set this to an empty collection.Priority
- An integer used to control the order registries are applied in (highest priority is applied first). This is useful, for instance, if you are running an integration test and you need to override services registered by the app - you can define a registry with a negative priority to ensure it is applied last.
There is also an abstract helper class called AbstractRegistryModule
which provides defaults for Priority
and TargetEnvironments
so all you
have to do is provide the implementation of ConfigureServices
.
Examples
public class HighPriorityRegistry : IRegistryModule {
public IReadOnlyCollection<string> TargetEnvironments => Array.Empty<string>();
// Any registry with a lower priority than 1000 will be registered AFTER this one
public int Priority => 1000;
public void ConfigureServices(IServiceCollection services) {
// Custom service registration here
}
}
public class DevelopmentRegistry : AbstractRegistryModule {
// This registry will only be applied if the host environment name is "Development" (case-insensitive)
public override IReadOnlyCollection<string> TargetEnvironments => new[] { "Development" };
public override void ConfigureServices(IServiceCollection services) {
// Custom service registration here
}
}
public class SimpleRegistry : AbstractRegistryModule {
/*
Simplest way to create a registry module.
The TargetEnvironments default to an empty array
and the Priority defaults to zero.
*/
public override void ConfigureServices(IServiceCollection services) {
// Custom service registration here
}
}
IMPORTANT! TargetEnviornments will only be enforced so long as the code that is applying the registries has provided an environment to use. More on that below.
Applying the registries
Registries are applied by calling the IServiceCollection
extension method ApplyRegistries()
. When calling this method
you can provide a set of assemblies that will be scanned for IRegistryModule
implementations, or you can use the
configuration builder to have more control of how the registries are discovered and applied.
A few of the most important configuration builder options are
- Ability to define providers that can be injected into the registries.
- Defining the
IHostEnvironment
to provide to the registries (and use for enforcing theTargetEnvironments
).* - Defining the
IConfiguration
to provide to the registries.* - Controlling whether to apply internal/private registries or only public registries.
*If using ServiceRegistryModules.AspNetCore, the same extensions can be used directly on the WebApplicationBuilder. This also provides the benefit of automatically using the Environment and Configuration provided by WebApplicationBuilder
Examples
IServiceCollection services;
IHostEnvironment environment;
IConfiguration configuration;
// Scans the given assemblies for IRegistryModule implementations and applies them
services.ApplyRegistries(typeof(MyRegistry).Assembly, typeof(MyOtherRegistry).Assembly);
// Scans the assembly in which "MyRegistry" is defined for IRegistryModule implementations
// and applies any public registries found there, injecting the given environment and configuration
// into the registries if required.
services.ApplyRegistries(config =>
config.PublicOnly()
.FromAssembliesOf<MyRegistry>()
.UsingEnvironment(environment)
.UsingConfigurationProvider(configuration)
);
// Applies the given registry types (regardless of access modifiers). If either registry
// has a constructor that requires a string or boolean parameter, they will be given
// "a string to inject" and true (respectively).
services.ApplyRegistries(config =>
config.OfTypes(typeof(MyRegistry), typeof(MyOtherRegistry))
.UsingProviders("a string to inject", true)
);
// Applies only the given registry instance
services.ApplyRegistries(config => config.From(new MyRegistry()));
If ApplyRegistries() is called without providing either an assembly to scan, a set of registry types, or any registry instances, then the assembly from which the extension was called will be scanned for IRegistryModule implementations.
Registry configuration
You can provide runtime configuration for your registries by defining a section in any of the sources
used by your application's IConfiguration
. Add a configuration key called "service_registries" to one
of your configuration sources (the key can be changed if you apply the registries using: services.ApplyRegistries(config => config.UsingConfigurationProvider("my_custom_key"))
).
This section is comprised of 3 subkeys:
configuration
- Configuration for properties/events of registries before they are applied.add
- Additional registries to be loaded an applied.skip
- Registries that should NOT be applied even if loaded.
Configuration section
Each entry under this key represents a registry you want to configure. And each registry configuration can
define properties or events of the registry to set before the registry is applied. The access modifiers of the members
and their setters don't matter unless your applying the registries using the PublicOnly()
setting. Each member
can be configured with errorSuppression on or off (off by default). If error suppression is turned on for a member,
no errors will be thrown due to the member not existing, having incorrect access modifiers, or having an invalid value.
Registry keys are matched in the following order:
- The full name of the registry is tried first (AssemblyName + TypeName).
- The short name of the registry is tried next (TypeName only).
- Wildcard matching is performed against the registry's full name.
A wildcard character of "*" can be used to indicate 0 or more occurrances of any character.
- Wildcard matches with the most specifity are given preferences. Meaning the longest set of non-wildcard characters wins. Ties are decided by the least number of wildcard characters.
When registries are being applied, if a configuration key is found that matches one of those 3 criteria, the properties of the registry will be set according to the configured members listed.
Event configuration
Events on the registry can be configured by providing the fully qualified name of a static method to be used as
an event handler for the event. If the handler method is located in an assembly that is not referenced by the assembly
applying the registries, a HintPath
may be specified to dicate where the assembly can be loaded from.
Dynamically added registries
This key is an array of registries to add at runtime. The registry can either be defined just by specifying its fully
qualified name or by defining its FullName
, SuppressErrors
and HintPath
properties (use HintPath
to load a registry
from an unreferenced assembly).
Dynamically skipped registries
This key is an array of registries to skip at runtime and consists of the fully qualified names of the registries to skip. Any registry in this list that is not loaded, will be ignored.
Examples
{
"service_registries": {
"add": [
"AnAssemblyWith.RegistryToAdd",
{
"FullName": "UnreferencedAssembly.Registry",
"SuppressErrors": true,
"HintPath": "../path/to/assembly"
}
],
"skip": [
"AnAssemblyWith.RegistryToSkip"
],
"configuration": {
"*Registry*": {
"Property1": 30
},
"AnotherRegistry": {
"APropertyToSet": "the new value"
},
"MyAssembly.With.A.RegistryModule": {
"Property1": "runtime value",
"AnotherProperty": false,
"PropertyWithErrorSuppression": {
"Value": "the value to assign to the property",
"SuppressErrors": true
}
},
"MyAssembly.*": {
"PropertyToSetInAllRegistiresInMyAssembly": {
"Value": true,
"SuppressErrors": true
},
"EventToAddHandlerFor": {
"Value": "SomeAssembly.StaticMethod.ForEventHandler",
"HintPath": "../path/to/unreferenced/handler/assembly"
}
}
}
}
}
In the above example:
SomeAssembly.AnotherRegistry
would match the 2nd and 1st configurations. The 2nd one would be applied.MyAssembly.With.A.RegistryModule
would match the 1st, 3rd and 4th configurations. The 3rd one would be applied.MyAssembly.MyRegistry.Module
would match the 1st and 4th configurations. The 4th one would be applied.
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net5.0 was computed. net5.0-windows was computed. net6.0 is compatible. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 is compatible. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. |
.NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
.NET Standard | netstandard2.0 is compatible. netstandard2.1 is compatible. |
.NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
MonoAndroid | monoandroid was computed. |
MonoMac | monomac was computed. |
MonoTouch | monotouch was computed. |
Tizen | tizen40 was computed. tizen60 was computed. |
Xamarin.iOS | xamarinios was computed. |
Xamarin.Mac | xamarinmac was computed. |
Xamarin.TVOS | xamarintvos was computed. |
Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- Microsoft.Extensions.DependencyInjection (>= 8.0.0)
- Microsoft.Extensions.Hosting.Abstractions (>= 8.0.0)
- ServiceRegistryModules.Abstractions (>= 1.2.0)
-
.NETStandard 2.1
- Microsoft.Extensions.DependencyInjection (>= 8.0.0)
- Microsoft.Extensions.Hosting.Abstractions (>= 8.0.0)
- ServiceRegistryModules.Abstractions (>= 1.2.0)
-
net6.0
- Microsoft.Extensions.DependencyInjection (>= 8.0.0)
- Microsoft.Extensions.Hosting.Abstractions (>= 8.0.0)
- ServiceRegistryModules.Abstractions (>= 1.2.0)
-
net7.0
- Microsoft.Extensions.DependencyInjection (>= 8.0.0)
- Microsoft.Extensions.Hosting.Abstractions (>= 8.0.0)
- ServiceRegistryModules.Abstractions (>= 1.2.0)
-
net8.0
- Microsoft.Extensions.DependencyInjection (>= 8.0.0)
- Microsoft.Extensions.Hosting.Abstractions (>= 8.0.0)
- ServiceRegistryModules.Abstractions (>= 1.2.0)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on ServiceRegistryModules:
Package | Downloads |
---|---|
ServiceRegistryModules.AspNetCore
ASP.NET extensions for ServiceRegistryModules |
GitHub repositories
This package is not used by any popular GitHub repositories.