Skip to content

Commit 2abda05

Browse files
committed
Added FacilityBuilder.
1 parent 225592c commit 2abda05

File tree

4 files changed

+163
-39
lines changed

4 files changed

+163
-39
lines changed
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
// Licensed under the MIT License.
2+
// Copyright (c) 2018-2022 the AppCore .NET project.
3+
4+
using System;
5+
using AppCore.Diagnostics;
6+
using AppCore.Extensions.DependencyInjection.Activator;
7+
using AppCore.Extensions.DependencyInjection.Facilities;
8+
using Microsoft.Extensions.DependencyInjection;
9+
10+
namespace AppCore.Extensions.DependencyInjection;
11+
12+
/// <summary>
13+
/// Provides a builder for facilities.
14+
/// </summary>
15+
public abstract class FacilityBuilder
16+
{
17+
/// <summary>
18+
/// Gets the <see cref="IServiceCollection"/>.
19+
/// </summary>
20+
public IServiceCollection Services { get; }
21+
22+
/// <summary>
23+
/// Gets the <see cref="IActivator"/>.
24+
/// </summary>
25+
public IActivator Activator { get; }
26+
27+
/// <summary>
28+
/// Gets the type of the facility.
29+
/// </summary>
30+
public Type FacilityType { get; }
31+
32+
internal FacilityBuilder(IServiceCollection services, IActivator activator, Type facilityType)
33+
{
34+
Services = services;
35+
Activator = activator;
36+
FacilityType = facilityType;
37+
}
38+
39+
/// <summary>
40+
/// Must be implemented to add an extension to the facility.
41+
/// </summary>
42+
/// <param name="extensionType">The type of the extension.</param>
43+
protected abstract void AddExtensionCore(Type extensionType);
44+
45+
/// <summary>
46+
/// Adds an extension to the facility.
47+
/// </summary>
48+
/// <remarks>
49+
/// The type <paramref name="extensionType"/> must implement <see cref="IFacilityExtension{T}"/> with the
50+
/// type of the facility.
51+
/// </remarks>
52+
/// <param name="extensionType">The type of the extension.</param>
53+
/// <returns>The <see cref="FacilityBuilder"/> to allow chaining.</returns>
54+
public FacilityBuilder AddExtension(Type extensionType)
55+
{
56+
AddExtensionCore(extensionType);
57+
return this;
58+
}
59+
}
60+
61+
/// <summary>
62+
/// Provides a builder for facilities.
63+
/// </summary>
64+
public sealed class FacilityBuilder<T> : FacilityBuilder
65+
where T : IFacility
66+
{
67+
internal FacilityBuilder(IServiceCollection services, IActivator activator)
68+
: base(services, activator, typeof(T))
69+
{
70+
}
71+
72+
/// <inheritdoc />
73+
protected override void AddExtensionCore(Type extensionType)
74+
{
75+
Ensure.Arg.NotNull(extensionType);
76+
Ensure.Arg.OfType(extensionType, typeof(IFacilityExtension<T>));
77+
78+
var extension = (IFacilityExtension<T>)Activator.CreateInstance(extensionType);
79+
extension.ConfigureServices(Services);
80+
}
81+
82+
/// <summary>
83+
/// Adds an extension to the facility.
84+
/// </summary>
85+
/// <remarks>
86+
/// The type <paramref name="extensionType"/> must implement <see cref="IFacilityExtension{T}"/> with the
87+
/// type of the facility.
88+
/// </remarks>
89+
/// <param name="extensionType">The type of the extension.</param>
90+
/// <returns>The <see cref="FacilityBuilder{T}"/> to allow chaining.</returns>
91+
public new FacilityBuilder<T> AddExtension(Type extensionType)
92+
{
93+
AddExtensionCore(extensionType);
94+
return this;
95+
}
96+
97+
/// <summary>
98+
/// Adds an extension to the facility.
99+
/// </summary>
100+
/// <typeparam name="TExtension">The type of the extension.</typeparam>
101+
/// <returns>The <see cref="FacilityBuilder{T}"/> to allow chaining.</returns>
102+
public FacilityBuilder<T> AddExtension<TExtension>()
103+
where TExtension : IFacilityExtension<T>
104+
{
105+
return AddExtension(typeof(TExtension));
106+
}
107+
}

DependencyInjection/src/AppCore.Extensions.DependencyInjection.Abstractions/FacilityServiceCollectionExtensions.cs

Lines changed: 52 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,25 @@ public static class FacilityServiceCollectionExtensions
2323
/// <param name="services">The <see cref="IServiceCollection"/>.</param>
2424
/// <param name="configure">The delegate to configure the facility.</param>
2525
/// <returns>The <see cref="IServiceCollection"/>.</returns>
26-
public static IServiceCollection AddFacility<T>(this IServiceCollection services, Action<T>? configure = null)
26+
public static IServiceCollection AddFacility<T>(this IServiceCollection services, Action<FacilityBuilder<T>>? configure = null)
2727
where T : IFacility
2828
{
29-
return AddFacility(services, typeof(T), f => configure?.Invoke((T) f));
29+
Ensure.Arg.NotNull(services);
30+
31+
services.TryAddTransient<IActivator, ServiceProviderActivator>();
32+
33+
var serviceProvider = new ServiceCollectionServiceProvider(services);
34+
var activator = serviceProvider.GetRequiredService<IActivator>();
35+
36+
var facility = activator.CreateInstance<T>();
37+
if (configure != null)
38+
{
39+
var builder = new FacilityBuilder<T>(services, activator);
40+
configure(builder);
41+
}
42+
43+
facility.ConfigureServices(services);
44+
return services;
3045
}
3146

3247
/// <summary>
@@ -39,7 +54,7 @@ public static IServiceCollection AddFacility<T>(this IServiceCollection services
3954
public static IServiceCollection AddFacility(
4055
this IServiceCollection services,
4156
Type facilityType,
42-
Action<IFacility>? configure = null)
57+
Action<FacilityBuilder>? configure = null)
4358
{
4459
Ensure.Arg.NotNull(services);
4560
Ensure.Arg.NotNull(facilityType);
@@ -51,8 +66,41 @@ public static IServiceCollection AddFacility(
5166
var activator = serviceProvider.GetRequiredService<IActivator>();
5267

5368
var facility = (IFacility)activator.CreateInstance(facilityType);
54-
configure?.Invoke(facility);
69+
if (configure != null)
70+
{
71+
Type builderType = typeof(FacilityBuilder<>).MakeGenericType(facilityType);
72+
var builder = (FacilityBuilder)Activator.CreateInstance(builderType, services, activator);
73+
configure(builder);
74+
}
75+
5576
facility.ConfigureServices(services);
77+
return services;
78+
}
79+
80+
/// <summary>
81+
/// Adds facilities using a <see cref="IFacilityReflectionBuilder"/> to the <see cref="IServiceCollection"/>.
82+
/// </summary>
83+
/// <param name="services">The <see cref="IServiceCollection"/>.</param>
84+
/// <param name="configure">The delegate used to configure the facility resolvers.</param>
85+
/// <returns>The <see cref="IServiceCollection"/>.</returns>
86+
public static IServiceCollection AddFacilitiesFrom(
87+
this IServiceCollection services,
88+
Action<IFacilityReflectionBuilder> configure)
89+
{
90+
Ensure.Arg.NotNull(services);
91+
Ensure.Arg.NotNull(configure);
92+
93+
services.TryAddTransient<IActivator, ServiceProviderActivator>();
94+
var serviceProvider = new ServiceCollectionServiceProvider(services);
95+
var activator = serviceProvider.GetRequiredService<IActivator>();
96+
var builder = new FacilityReflectionBuilder(activator);
97+
98+
configure(builder);
99+
100+
foreach (IFacility facility in builder.Resolve())
101+
{
102+
facility.ConfigureServices(services);
103+
}
56104

57105
return services;
58106
}

DependencyInjection/src/AppCore.Extensions.DependencyInjection.Abstractions/ReflectionServiceCollectionExtensions.cs

Lines changed: 3 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ public static class ReflectionServiceCollectionExtensions
1818
{
1919
private static ServiceDescriptorReflectionBuilder CreateBuilder(this IServiceCollection services, Type serviceType)
2020
{
21+
Ensure.Arg.NotNull(services);
22+
Ensure.Arg.NotNull(serviceType);
23+
2124
services.TryAddTransient<IActivator, ServiceProviderActivator>();
2225
var serviceProvider = new ServiceCollectionServiceProvider(services);
2326
var builder = new ServiceDescriptorReflectionBuilder(
@@ -39,9 +42,7 @@ public static IServiceCollection AddFrom(
3942
Type serviceType,
4043
Action<IServiceDescriptorReflectionBuilder> configure)
4144
{
42-
Ensure.Arg.NotNull(services);
4345
Ensure.Arg.NotNull(configure);
44-
4546
ServiceDescriptorReflectionBuilder sources = services.CreateBuilder(serviceType);
4647
configure(sources);
4748
return services.Add(sources.Resolve());
@@ -73,9 +74,7 @@ Action<IServiceDescriptorReflectionBuilder> configure
7374
/// <returns>The <see cref="IServiceCollection"/>.</returns>
7475
public static IServiceCollection TryAddFrom(this IServiceCollection services, Type serviceType, Action<IServiceDescriptorReflectionBuilder> configure)
7576
{
76-
Ensure.Arg.NotNull(services);
7777
Ensure.Arg.NotNull(configure);
78-
7978
ServiceDescriptorReflectionBuilder sources = services.CreateBuilder(serviceType);
8079
configure(sources);
8180
services.TryAdd(sources.Resolve());
@@ -112,9 +111,7 @@ public static IServiceCollection TryAddEnumerableFrom(
112111
Type serviceType,
113112
Action<IServiceDescriptorReflectionBuilder> configure)
114113
{
115-
Ensure.Arg.NotNull(services);
116114
Ensure.Arg.NotNull(configure);
117-
118115
ServiceDescriptorReflectionBuilder sources = services.CreateBuilder(serviceType);
119116
configure(sources);
120117
services.TryAddEnumerable(sources.Resolve());
@@ -137,32 +134,4 @@ Action<IServiceDescriptorReflectionBuilder> configure
137134
{
138135
return TryAddEnumerableFrom(services, typeof(TService), configure);
139136
}
140-
141-
/// <summary>
142-
/// Adds facilities using a <see cref="IFacilityReflectionBuilder"/> to the <see cref="IServiceCollection"/>.
143-
/// </summary>
144-
/// <param name="services">The <see cref="IServiceCollection"/>.</param>
145-
/// <param name="configure">The delegate used to configure the facility resolvers.</param>
146-
/// <returns>The <see cref="IServiceCollection"/>.</returns>
147-
public static IServiceCollection AddFacilitiesFrom(
148-
this IServiceCollection services,
149-
Action<IFacilityReflectionBuilder> configure)
150-
{
151-
Ensure.Arg.NotNull(services);
152-
Ensure.Arg.NotNull(configure);
153-
154-
services.TryAddTransient<IActivator, ServiceProviderActivator>();
155-
var serviceProvider = new ServiceCollectionServiceProvider(services);
156-
var activator = serviceProvider.GetRequiredService<IActivator>();
157-
var builder = new FacilityReflectionBuilder(activator);
158-
159-
configure(builder);
160-
161-
foreach (IFacility facility in builder.Resolve())
162-
{
163-
facility.ConfigureServices(services);
164-
}
165-
166-
return services;
167-
}
168137
}

DependencyInjection/src/AppCore.Extensions.DependencyInjection.Abstractions/ServiceCollectionServiceProvider.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
namespace AppCore.Extensions.DependencyInjection;
1111

12-
internal class ServiceCollectionServiceProvider : IServiceProvider
12+
internal sealed class ServiceCollectionServiceProvider : IServiceProvider
1313
{
1414
private readonly IServiceCollection _services;
1515
private readonly Dictionary<Type, object> _additionalServices = new();

0 commit comments

Comments
 (0)