diff --git a/DependencyInjection/src/AppCore.Extensions.DependencyInjection.Abstractions/AppCore.Extensions.DependencyInjection.Abstractions.csproj b/DependencyInjection/src/AppCore.Extensions.DependencyInjection.Abstractions/AppCore.Extensions.DependencyInjection.Abstractions.csproj
index c2f5bed..70671c9 100644
--- a/DependencyInjection/src/AppCore.Extensions.DependencyInjection.Abstractions/AppCore.Extensions.DependencyInjection.Abstractions.csproj
+++ b/DependencyInjection/src/AppCore.Extensions.DependencyInjection.Abstractions/AppCore.Extensions.DependencyInjection.Abstractions.csproj
@@ -10,6 +10,9 @@
all
+
+ all
+
diff --git a/DependencyInjection/src/AppCore.Extensions.DependencyInjection.Abstractions/Facilities/FacilityBuilder.cs b/DependencyInjection/src/AppCore.Extensions.DependencyInjection.Abstractions/Facilities/FacilityBuilder.cs
index 494bfb3..d5cbc2e 100644
--- a/DependencyInjection/src/AppCore.Extensions.DependencyInjection.Abstractions/Facilities/FacilityBuilder.cs
+++ b/DependencyInjection/src/AppCore.Extensions.DependencyInjection.Abstractions/Facilities/FacilityBuilder.cs
@@ -2,6 +2,7 @@
// Copyright (c) 2018-2022 the AppCore .NET project.
using System;
+using System.Linq;
using AppCore.Diagnostics;
using AppCore.Extensions.DependencyInjection.Activator;
using Microsoft.Extensions.DependencyInjection;
@@ -35,6 +36,18 @@ internal FacilityBuilder(IServiceCollection services, IActivator activator, Type
FacilityType = facilityType;
}
+ private IFacilityExtension CreateExtension(Type extensionType)
+ {
+ Type contractType = extensionType.GetInterfaces()
+ .First(i => i.GetGenericTypeDefinition() == typeof(IFacilityExtension<>))
+ .GenericTypeArguments[0];
+
+ Type extensionWrapperType = typeof(FacilityExtensionWrapper<>).MakeGenericType(contractType);
+ object extension = Activator.CreateInstance(extensionType);
+
+ return (IFacilityExtension)System.Activator.CreateInstance(extensionWrapperType, extension);
+ }
+
///
/// Adds an extension to the facility.
///
@@ -49,7 +62,7 @@ public FacilityBuilder AddExtension(Type extensionType)
Ensure.Arg.NotNull(extensionType);
Ensure.Arg.OfType(extensionType, typeof(IFacilityExtension<>).MakeGenericType(FacilityType));
- var extension = (IFacilityExtension)Activator.CreateInstance(extensionType);
+ IFacilityExtension extension = CreateExtension(extensionType);
extension.ConfigureServices(Services);
return this;
}
@@ -107,9 +120,9 @@ internal FacilityBuilder(IServiceCollection services, IActivator activator)
/// The type of the extension.
/// The to allow chaining.
public FacilityBuilder AddExtension()
- where TExtension : IFacilityExtension
+ where TExtension : class, IFacilityExtension
{
- var extension = (IFacilityExtension)Activator.CreateInstance(typeof(TExtension));
+ IFacilityExtension extension = Activator.CreateInstance();
extension.ConfigureServices(Services);
return this;
}
diff --git a/DependencyInjection/src/AppCore.Extensions.DependencyInjection.Abstractions/Facilities/FacilityExtensionReflectionBuilder.cs b/DependencyInjection/src/AppCore.Extensions.DependencyInjection.Abstractions/Facilities/FacilityExtensionReflectionBuilder.cs
index 680bff5..53c2775 100644
--- a/DependencyInjection/src/AppCore.Extensions.DependencyInjection.Abstractions/Facilities/FacilityExtensionReflectionBuilder.cs
+++ b/DependencyInjection/src/AppCore.Extensions.DependencyInjection.Abstractions/Facilities/FacilityExtensionReflectionBuilder.cs
@@ -36,7 +36,11 @@ public IFacilityExtensionReflectionBuilder AddResolver(Action? configure =
public IReadOnlyCollection> Resolve(Type facilityType)
{
- return _resolvers.SelectMany(s => s.Resolve(facilityType))
+ Type[] facilityTypes = facilityType.GetTypesAssignableFrom()
+ .Where(t => t.GetInterfaces().Contains(typeof(IFacility)))
+ .ToArray();
+
+ return _resolvers.SelectMany(s => facilityTypes.SelectMany(s.Resolve))
.ToList()
.AsReadOnly();
}
diff --git a/DependencyInjection/src/AppCore.Extensions.DependencyInjection.Abstractions/Facilities/FacilityExtensionWrapper.cs b/DependencyInjection/src/AppCore.Extensions.DependencyInjection.Abstractions/Facilities/FacilityExtensionWrapper.cs
new file mode 100644
index 0000000..3991493
--- /dev/null
+++ b/DependencyInjection/src/AppCore.Extensions.DependencyInjection.Abstractions/Facilities/FacilityExtensionWrapper.cs
@@ -0,0 +1,22 @@
+// Licensed under the MIT License.
+// Copyright (c) 2018-2022 the AppCore .NET project.
+
+using Microsoft.Extensions.DependencyInjection;
+
+namespace AppCore.Extensions.DependencyInjection.Facilities;
+
+internal sealed class FacilityExtensionWrapper : IFacilityExtension
+ where TContract : IFacility
+{
+ private readonly IFacilityExtension _extension;
+
+ public FacilityExtensionWrapper(IFacilityExtension extension)
+ {
+ _extension = extension;
+ }
+
+ public void ConfigureServices(IServiceCollection services)
+ {
+ _extension.ConfigureServices(services);
+ }
+}
\ No newline at end of file
diff --git a/DependencyInjection/src/AppCore.Extensions.DependencyInjection.Abstractions/Facilities/IFacilityExtension.cs b/DependencyInjection/src/AppCore.Extensions.DependencyInjection.Abstractions/Facilities/IFacilityExtension.cs
index 831a4b8..8edc7b4 100644
--- a/DependencyInjection/src/AppCore.Extensions.DependencyInjection.Abstractions/Facilities/IFacilityExtension.cs
+++ b/DependencyInjection/src/AppCore.Extensions.DependencyInjection.Abstractions/Facilities/IFacilityExtension.cs
@@ -8,7 +8,7 @@ namespace AppCore.Extensions.DependencyInjection.Facilities;
///
/// Represents an extension for a facility.
///
-public interface IFacilityExtension
+public interface IFacilityExtension
where T : IFacility
{
///
diff --git a/DependencyInjection/src/AppCore.Extensions.DependencyInjection.AssemblyExtensions/Facilities/AssemblyResolver.cs b/DependencyInjection/src/AppCore.Extensions.DependencyInjection.AssemblyExtensions/Facilities/AssemblyResolver.cs
index bb0e691..238dcfe 100644
--- a/DependencyInjection/src/AppCore.Extensions.DependencyInjection.AssemblyExtensions/Facilities/AssemblyResolver.cs
+++ b/DependencyInjection/src/AppCore.Extensions.DependencyInjection.AssemblyExtensions/Facilities/AssemblyResolver.cs
@@ -114,6 +114,18 @@ IEnumerable IFacilityResolver.Resolve()
.Select(facilityType => (IFacility) _activator.CreateInstance(facilityType));
}
+ private IFacilityExtension CreateExtension(Type extensionType)
+ {
+ Type contractType = extensionType.GetInterfaces()
+ .First(i => i.GetGenericTypeDefinition() == typeof(IFacilityExtension<>))
+ .GenericTypeArguments[0];
+
+ Type extensionWrapperType = typeof(FacilityExtensionWrapper<>).MakeGenericType(contractType);
+ object extension = _activator.CreateInstance(extensionType);
+
+ return (IFacilityExtension)System.Activator.CreateInstance(extensionWrapperType, extension);
+ }
+
///
IEnumerable> IFacilityExtensionResolver.Resolve(Type facilityType)
{
@@ -129,8 +141,6 @@ IEnumerable> IFacilityExtensionResolver.Resolve(Ty
scanner.Filters.Add(filter);
return scanner.ScanAssemblies()
- .Select(
- facilityExtensionType =>
- (IFacilityExtension)_activator.CreateInstance(facilityExtensionType));
+ .Select(CreateExtension);
}
}
\ No newline at end of file
diff --git a/DependencyInjection/src/AppCore.Extensions.DependencyInjection.AssemblyExtensions/Facilities/FacilityExtensionWrapper.cs b/DependencyInjection/src/AppCore.Extensions.DependencyInjection.AssemblyExtensions/Facilities/FacilityExtensionWrapper.cs
new file mode 100644
index 0000000..08f18dc
--- /dev/null
+++ b/DependencyInjection/src/AppCore.Extensions.DependencyInjection.AssemblyExtensions/Facilities/FacilityExtensionWrapper.cs
@@ -0,0 +1,22 @@
+// Licensed under the MIT License.
+// Copyright (c) 2018-2022 the AppCore .NET project.
+
+using Microsoft.Extensions.DependencyInjection;
+
+namespace AppCore.Extensions.DependencyInjection.Facilities;
+
+internal sealed class FacilityExtensionWrapper : IFacilityExtension
+ where TContract : IFacility
+{
+ internal IFacilityExtension Extension { get; }
+
+ public FacilityExtensionWrapper(IFacilityExtension extension)
+ {
+ Extension = extension;
+ }
+
+ public void ConfigureServices(IServiceCollection services)
+ {
+ Extension.ConfigureServices(services);
+ }
+}
\ No newline at end of file
diff --git a/DependencyInjection/test/AppCore.Extensions.DependencyInjection.AssemblyExtensions.Tests/AssemblyResolverTests.cs b/DependencyInjection/test/AppCore.Extensions.DependencyInjection.AssemblyExtensions.Tests/AssemblyResolverTests.cs
index 127b021..b215303 100644
--- a/DependencyInjection/test/AppCore.Extensions.DependencyInjection.AssemblyExtensions.Tests/AssemblyResolverTests.cs
+++ b/DependencyInjection/test/AppCore.Extensions.DependencyInjection.AssemblyExtensions.Tests/AssemblyResolverTests.cs
@@ -49,8 +49,12 @@ public void ResolvesAllFacilityExtensions()
IEnumerable> facilityExtensions =
((IFacilityExtensionResolver)resolver).Resolve(typeof(Facility1));
- facilityExtensions.Select(f => f.GetType())
+ facilityExtensions.Should()
+ .AllBeOfType>();
+
+ facilityExtensions.OfType>()
+ .Select(e => e.Extension.GetType())
.Should()
- .BeEquivalentTo(new [] { typeof(Facility1Extension1), typeof(Facility1Extension2) });
+ .BeEquivalentTo(new[] { typeof(Facility1Extension1), typeof(Facility1Extension2) });
}
}
\ No newline at end of file
diff --git a/DependencyInjection/test/AppCore.Extensions.DependencyInjection.Tests/Facilities/FacilityBuilderTests.cs b/DependencyInjection/test/AppCore.Extensions.DependencyInjection.Tests/Facilities/FacilityBuilderTests.cs
index a9c96be..d069e37 100644
--- a/DependencyInjection/test/AppCore.Extensions.DependencyInjection.Tests/Facilities/FacilityBuilderTests.cs
+++ b/DependencyInjection/test/AppCore.Extensions.DependencyInjection.Tests/Facilities/FacilityBuilderTests.cs
@@ -2,6 +2,7 @@
// Copyright (c) 2018-2022 the AppCore .NET project.
using System;
+using System.Linq;
using AppCore.Extensions.DependencyInjection.Activator;
using FluentAssertions;
using Microsoft.Extensions.DependencyInjection;
@@ -30,8 +31,19 @@ public void AddExtensionGenericTypeRegistersServices()
{
var builder = new FacilityBuilder(_services, _activator);
builder.AddExtension();
+ builder.AddExtension();
+ _services.Select(sd => sd.ServiceType)
+ .Should()
+ .BeEquivalentTo(new [] { typeof(FacilityExtensionTestService), typeof(FacilityExtensionTestService) });
+ }
+
+ [Fact]
+ public void AddExtensionForContractGenericTypeRegistersServices()
+ {
+ var builder = new FacilityBuilder(_services, _activator);
+ builder.AddExtension();
_services.Should()
- .ContainSingle(sd => sd.ServiceType == typeof(FacilityExtensionTestService));
+ .Contain(sd => sd.ServiceType == typeof(FacilityExtensionTestService));
}
[Fact]
@@ -39,8 +51,10 @@ public void AddExtensionTypeRegistersServices()
{
var builder = new FacilityBuilder(_services, _activator);
builder.AddExtension(typeof(TestFacilityExtension));
- _services.Should()
- .ContainSingle(sd => sd.ServiceType == typeof(FacilityExtensionTestService));
+ builder.AddExtension(typeof(TestFacilityContractExtension));
+ _services.Select(sd => sd.ServiceType)
+ .Should()
+ .BeEquivalentTo(new [] { typeof(FacilityExtensionTestService), typeof(FacilityExtensionTestService) });
}
[Fact]
@@ -48,20 +62,24 @@ public void AddExtensionRegistersServices()
{
var builder = new FacilityBuilder(_services, _activator);
builder.AddExtension(new TestFacilityExtension());
- _services.Should()
- .ContainSingle(sd => sd.ServiceType == typeof(FacilityExtensionTestService));
+ builder.AddExtension(new TestFacilityContractExtension());
+
+ _services.Select(sd => sd.ServiceType)
+ .Should()
+ .BeEquivalentTo(new [] { typeof(FacilityExtensionTestService), typeof(FacilityExtensionTestService) });
}
[Fact]
- public void AddExtensionsFromRegistersServices()
+ public void AddExtensionsFromInvokesResolver()
{
var resolver = Substitute.For();
- resolver.Resolve(Arg.Is(typeof(TestFacility)))
- .Returns(new[] { new TestFacilityExtension() });
+ resolver.Resolve(Arg.Any())
+ .Returns(Array.Empty>());
var builder = new FacilityBuilder(_services, _activator);
builder.AddExtensionsFrom(r => r.AddResolver(resolver));
- _services.Should()
- .ContainSingle(sd => sd.ServiceType == typeof(FacilityExtensionTestService));
+
+ resolver.Received()
+ .Resolve(typeof(TestFacility));
}
}
\ No newline at end of file
diff --git a/DependencyInjection/test/AppCore.Extensions.DependencyInjection.Tests/Facilities/FacilityServiceCollectionExtensionsTests.cs b/DependencyInjection/test/AppCore.Extensions.DependencyInjection.Tests/Facilities/FacilityServiceCollectionExtensionsTests.cs
index a9a98f2..81ec1c7 100644
--- a/DependencyInjection/test/AppCore.Extensions.DependencyInjection.Tests/Facilities/FacilityServiceCollectionExtensionsTests.cs
+++ b/DependencyInjection/test/AppCore.Extensions.DependencyInjection.Tests/Facilities/FacilityServiceCollectionExtensionsTests.cs
@@ -35,6 +35,14 @@ public void AddFacilityTypeRegistersServices()
.ContainSingle(sd => sd.ServiceType == typeof(FacilityTestService));
}
+ [Fact]
+ public void AddFacilityTypeWithContractRegistersServices()
+ {
+ _services.AddFacility(typeof(TestFacility));
+
+ _services.Should()
+ .ContainSingle(sd => sd.ServiceType == typeof(FacilityTestService));
+ }
[Fact]
public void AddFacilitiesFromRegistersServices()
diff --git a/DependencyInjection/test/AppCore.Extensions.DependencyInjection.Tests/Facilities/ITestFacility.cs b/DependencyInjection/test/AppCore.Extensions.DependencyInjection.Tests/Facilities/ITestFacility.cs
new file mode 100644
index 0000000..3889798
--- /dev/null
+++ b/DependencyInjection/test/AppCore.Extensions.DependencyInjection.Tests/Facilities/ITestFacility.cs
@@ -0,0 +1,8 @@
+// Licensed under the MIT License.
+// Copyright (c) 2018-2022 the AppCore .NET project.
+
+namespace AppCore.Extensions.DependencyInjection.Facilities;
+
+public interface ITestFacility : IFacility
+{
+}
\ No newline at end of file
diff --git a/DependencyInjection/test/AppCore.Extensions.DependencyInjection.Tests/Facilities/TestFacility.cs b/DependencyInjection/test/AppCore.Extensions.DependencyInjection.Tests/Facilities/TestFacility.cs
index 828f49e..ef4cc41 100644
--- a/DependencyInjection/test/AppCore.Extensions.DependencyInjection.Tests/Facilities/TestFacility.cs
+++ b/DependencyInjection/test/AppCore.Extensions.DependencyInjection.Tests/Facilities/TestFacility.cs
@@ -5,7 +5,7 @@
namespace AppCore.Extensions.DependencyInjection.Facilities;
-public class TestFacility : IFacility
+public class TestFacility : ITestFacility
{
public void ConfigureServices(IServiceCollection services)
{
diff --git a/DependencyInjection/test/AppCore.Extensions.DependencyInjection.Tests/Facilities/TestFacilityContractExtension.cs b/DependencyInjection/test/AppCore.Extensions.DependencyInjection.Tests/Facilities/TestFacilityContractExtension.cs
new file mode 100644
index 0000000..e61631f
--- /dev/null
+++ b/DependencyInjection/test/AppCore.Extensions.DependencyInjection.Tests/Facilities/TestFacilityContractExtension.cs
@@ -0,0 +1,12 @@
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.DependencyInjection.Extensions;
+
+namespace AppCore.Extensions.DependencyInjection.Facilities;
+
+public class TestFacilityContractExtension : IFacilityExtension
+{
+ public void ConfigureServices(IServiceCollection services)
+ {
+ services.AddTransient();
+ }
+}
\ No newline at end of file
diff --git a/DependencyInjection/test/AppCore.Extensions.DependencyInjection.Tests/Facilities/TestFacilityExtension.cs b/DependencyInjection/test/AppCore.Extensions.DependencyInjection.Tests/Facilities/TestFacilityExtension.cs
index 5f55ff9..d89e32c 100644
--- a/DependencyInjection/test/AppCore.Extensions.DependencyInjection.Tests/Facilities/TestFacilityExtension.cs
+++ b/DependencyInjection/test/AppCore.Extensions.DependencyInjection.Tests/Facilities/TestFacilityExtension.cs
@@ -10,6 +10,6 @@ public class TestFacilityExtension : IFacilityExtension
{
public void ConfigureServices(IServiceCollection services)
{
- services.TryAddTransient();
+ services.AddTransient();
}
}
\ No newline at end of file
diff --git a/Hosting/src/AppCore.Extensions.Hosting.Plugins/DependencyInjection/FacilityExtensionWrapper.cs b/Hosting/src/AppCore.Extensions.Hosting.Plugins/DependencyInjection/FacilityExtensionWrapper.cs
new file mode 100644
index 0000000..0dc235e
--- /dev/null
+++ b/Hosting/src/AppCore.Extensions.Hosting.Plugins/DependencyInjection/FacilityExtensionWrapper.cs
@@ -0,0 +1,23 @@
+// Licensed under the MIT License.
+// Copyright (c) 2018-2022 the AppCore .NET project.
+
+using Microsoft.Extensions.DependencyInjection;
+
+// ReSharper disable once CheckNamespace
+namespace AppCore.Extensions.DependencyInjection.Facilities;
+
+internal sealed class FacilityExtensionWrapper : IFacilityExtension
+ where TContract : IFacility
+{
+ private readonly IFacilityExtension _extension;
+
+ public FacilityExtensionWrapper(IFacilityExtension extension)
+ {
+ _extension = extension;
+ }
+
+ public void ConfigureServices(IServiceCollection services)
+ {
+ _extension.ConfigureServices(services);
+ }
+}
\ No newline at end of file
diff --git a/Hosting/src/AppCore.Extensions.Hosting.Plugins/DependencyInjection/PluginFacilityResolver.cs b/Hosting/src/AppCore.Extensions.Hosting.Plugins/DependencyInjection/PluginFacilityResolver.cs
index daf7bae..9fd0659 100644
--- a/Hosting/src/AppCore.Extensions.Hosting.Plugins/DependencyInjection/PluginFacilityResolver.cs
+++ b/Hosting/src/AppCore.Extensions.Hosting.Plugins/DependencyInjection/PluginFacilityResolver.cs
@@ -3,6 +3,8 @@
using System;
using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
using AppCore.Diagnostics;
using AppCore.Extensions.Hosting.Plugins;
@@ -35,14 +37,30 @@ IEnumerable IFacilityResolver.Resolve()
}
}
+ private IFacilityExtension CreateExtension(IPluginService