diff --git a/VpSharp.Commands/CommandsExtension.cs b/VpSharp.Commands/CommandsExtension.cs
index cb5b414..a2f8d8f 100644
--- a/VpSharp.Commands/CommandsExtension.cs
+++ b/VpSharp.Commands/CommandsExtension.cs
@@ -1,4 +1,5 @@
using System.Reflection;
+using Microsoft.Extensions.DependencyInjection;
using VpSharp.ClientExtensions;
using VpSharp.Commands.Attributes;
using VpSharp.Entities;
@@ -30,6 +31,7 @@ public sealed class CommandsExtension : VirtualParadiseClientExtension
: base(client)
{
_configuration = configuration ?? throw new ArgumentNullException(nameof(configuration));
+ _configuration.Services ??= client.Services;
}
///
@@ -37,6 +39,7 @@ public sealed class CommandsExtension : VirtualParadiseClientExtension
///
/// The assembly whose command modules to register.
///
+ /// A module in the specified assembly does not have a public constructor, or has more than one public constructor.
///
/// A command module could not be instantiated.
///
@@ -48,6 +51,10 @@ public sealed class CommandsExtension : VirtualParadiseClientExtension
/// A command in the specified assembly has on a parameter that is not the last in
/// the parameter list.
///
+ /// -or-
+ ///
+ /// A module is expecting services but no was registered.
+ ///
///
public void RegisterCommands(Assembly assembly)
{
@@ -66,7 +73,11 @@ public sealed class CommandsExtension : VirtualParadiseClientExtension
/// Registers the commands defined in the specified type.
///
///
- /// refers to a type that does not inherit .
+ /// refers to a type that does not inherit .
+ /// -or-
+ ///
+ /// does not have a public constructor, or has more than one public constructor.
+ ///
///
/// could not be instantiated.
///
@@ -78,6 +89,10 @@ public sealed class CommandsExtension : VirtualParadiseClientExtension
/// A command in the specified module has on a parameter that is not the last in the
/// parameter list.
///
+ /// -or-
+ ///
+ /// The module is expecting services but no was registered.
+ ///
///
public void RegisterCommands() where T : CommandModule
{
@@ -93,6 +108,10 @@ public sealed class CommandsExtension : VirtualParadiseClientExtension
/// refers to an abstract type.
/// -or-
/// refers to a type that does not inherit .
+ /// -or-
+ ///
+ /// does not have a public constructor, or has more than one public constructor.
+ ///
///
/// could not be instantiated.
///
@@ -104,6 +123,10 @@ public sealed class CommandsExtension : VirtualParadiseClientExtension
/// A command in the specified module has on a parameter that is not the last in the
/// parameter list.
///
+ /// -or-
+ ///
+ /// The module is expecting services but no was registered.
+ ///
///
public void RegisterCommands(Type moduleType)
{
@@ -119,7 +142,29 @@ public sealed class CommandsExtension : VirtualParadiseClientExtension
throw new ArgumentException($"Module type is not a subclass of {typeof(CommandModule)}");
}
- if (Activator.CreateInstance(moduleType) is not CommandModule module)
+ ConstructorInfo[] constructors = moduleType.GetTypeInfo().DeclaredConstructors.Where(c => c.IsPublic).ToArray();
+ if (constructors.Length != 0)
+ {
+ throw new ArgumentException(
+ $"Constructor for {moduleType} is not public, or {moduleType} has more than one public constructor.");
+ }
+
+ ConstructorInfo constructor = constructors[0];
+ ParameterInfo[] parameters = constructor.GetParameters();
+
+ IServiceProvider? serviceProvider = _configuration.Services;
+ if (parameters.Length != 0 && serviceProvider is null)
+ {
+ throw new InvalidOperationException("No ServiceProvider has been registered!");
+ }
+
+ var args = new object[parameters.Length];
+ for (var index = 0; index < args.Length; index++)
+ {
+ args[index] = serviceProvider!.GetRequiredService(parameters[index].ParameterType);
+ }
+
+ if (Activator.CreateInstance(moduleType, args) is not CommandModule module)
{
throw new TypeInitializationException(moduleType.FullName, null);
}
diff --git a/VpSharp.Commands/CommandsExtensionConfiguration.cs b/VpSharp.Commands/CommandsExtensionConfiguration.cs
index e023c04..8e125e1 100644
--- a/VpSharp.Commands/CommandsExtensionConfiguration.cs
+++ b/VpSharp.Commands/CommandsExtensionConfiguration.cs
@@ -5,9 +5,30 @@ namespace VpSharp.Commands;
///
public sealed class CommandsExtensionConfiguration
{
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The configuration to copy.
+ public CommandsExtensionConfiguration(CommandsExtensionConfiguration? configuration = null)
+ {
+ if (configuration is null)
+ {
+ return;
+ }
+
+ Prefixes = configuration.Prefixes;
+ Services = configuration.Services;
+ }
+
///
/// Gets or sets the prefixes to be use for commands.
///
/// The command prefixes, as an array of values.
public IReadOnlyList Prefixes { get; set; } = Array.Empty();
+
+ ///
+ /// Gets or sets the service provider.
+ ///
+ /// The service provider.
+ public IServiceProvider? Services { get; set; }
}
diff --git a/VpSharp/VpSharp.csproj b/VpSharp/VpSharp.csproj
index b0fc31d..f6b91a5 100644
--- a/VpSharp/VpSharp.csproj
+++ b/VpSharp/VpSharp.csproj
@@ -57,6 +57,7 @@
+
diff --git a/VpSharp/src/VirtualParadiseClient.cs b/VpSharp/src/VirtualParadiseClient.cs
index 6528031..a25900c 100644
--- a/VpSharp/src/VirtualParadiseClient.cs
+++ b/VpSharp/src/VirtualParadiseClient.cs
@@ -46,6 +46,7 @@ public sealed partial class VirtualParadiseClient : IDisposable
/// The configuration for this client.
public VirtualParadiseClient(VirtualParadiseConfiguration configuration)
{
+ Services = configuration.Services;
_configuration = new VirtualParadiseConfiguration(configuration);
Initialize();
}
@@ -84,6 +85,12 @@ public sealed partial class VirtualParadiseClient : IDisposable
get => CurrentAvatar?.Location.World;
}
+ ///
+ /// Gets the service provider.
+ ///
+ /// The service provider.
+ public IServiceProvider? Services { get; }
+
///
/// Gets a read-only view of the cached worlds.
///
diff --git a/VpSharp/src/VirtualParadiseConfiguration.cs b/VpSharp/src/VirtualParadiseConfiguration.cs
index 558a697..ba8d405 100644
--- a/VpSharp/src/VirtualParadiseConfiguration.cs
+++ b/VpSharp/src/VirtualParadiseConfiguration.cs
@@ -61,6 +61,12 @@ public sealed class VirtualParadiseConfiguration
///
/// The login password.
public string Password { get; set; } = string.Empty;
+
+ ///
+ /// Gets or sets the service provider.
+ ///
+ /// The service provider.
+ public IServiceProvider? Services { get; set; }
///
/// Gets or sets the login username.