-
-
Notifications
You must be signed in to change notification settings - Fork 253
/
MultiTenantBuilder.cs
150 lines (132 loc) · 7.88 KB
/
MultiTenantBuilder.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
// Copyright Finbuckle LLC, Andrew White, and Contributors.
// Refer to the solution LICENSE file for more inforation.
using System;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Options;
using Finbuckle.MultiTenant;
using Finbuckle.MultiTenant.Options;
namespace Microsoft.Extensions.DependencyInjection
{
public partial class FinbuckleMultiTenantBuilder<TTenantInfo> where TTenantInfo : class, ITenantInfo, new()
{
public IServiceCollection Services { get; set; }
public FinbuckleMultiTenantBuilder(IServiceCollection services)
{
Services = services;
}
/// <summary>
/// Adds per-tenant configuration for an options class.
/// </summary>
/// <param name="tenantConfigureOptions">The configuration action to be run for each tenant.</param>
/// <returns>The same MultiTenantBuilder passed into the method.</returns>
/// <remarks>This is similar to `ConfigureAll` in that it applies to all named and unnamed options of the type.</remarks>
public FinbuckleMultiTenantBuilder<TTenantInfo> WithPerTenantOptions<TOptions>(
Action<TOptions, TTenantInfo> tenantConfigureOptions) where TOptions : class, new()
{
// if (tenantConfigureOptions == null)
// {
// throw new ArgumentNullException(nameof(tenantConfigureOptions));
// }
//
// // Handles multiplexing cached options.
// Services.TryAddSingleton<IOptionsMonitorCache<TOptions>, MultiTenantOptionsCache<TOptions, TTenantInfo>>();
//
// // Necessary to apply tenant options in between configuration and postconfiguration
// Services
// .AddSingleton<ITenantConfigureOptions<TOptions, TTenantInfo>,
// TenantConfigureOptions<TOptions, TTenantInfo>>(sp =>
// new TenantConfigureOptions<TOptions, TTenantInfo>(tenantConfigureOptions));
// Services.TryAddTransient<IOptionsFactory<TOptions>, MultiTenantOptionsFactory<TOptions, TTenantInfo>>();
// Services.TryAddScoped<IOptionsSnapshot<TOptions>>(sp => BuildOptionsManager<TOptions>(sp));
// Services.TryAddSingleton<IOptions<TOptions>>(sp => BuildOptionsManager<TOptions>(sp));
return WithPerTenantNamedOptions(null, tenantConfigureOptions);
}
/// <summary>
/// Adds per-tenant configuration for an named options class.
/// </summary>
/// <param name="name">The option name.</param>
/// <param name="tenantConfigureNamedOptions">The configuration action to be run for each tenant.</param>
/// <returns>The same MultiTenantBuilder passed into the method.</returns>
public FinbuckleMultiTenantBuilder<TTenantInfo> WithPerTenantNamedOptions<TOptions>(string? name,
Action<TOptions, TTenantInfo> tenantConfigureNamedOptions) where TOptions : class, new()
{
if (tenantConfigureNamedOptions == null)
{
throw new ArgumentNullException(nameof(tenantConfigureNamedOptions));
}
// Handles multiplexing cached options.
Services.TryAddSingleton<IOptionsMonitorCache<TOptions>, MultiTenantOptionsCache<TOptions, TTenantInfo>>();
// Necessary to apply tenant named options in between configuration and post configuration
Services.AddSingleton<ITenantConfigureNamedOptions<TOptions, TTenantInfo>,
TenantConfigureNamedOptions<TOptions, TTenantInfo>>(sp => new TenantConfigureNamedOptions<TOptions,
TTenantInfo>(name, tenantConfigureNamedOptions));
Services.TryAddTransient<IOptionsFactory<TOptions>, MultiTenantOptionsFactory<TOptions, TTenantInfo>>();
Services.TryAddScoped<IOptionsSnapshot<TOptions>>(sp => BuildOptionsManager<TOptions>(sp));
Services.TryAddSingleton<IOptions<TOptions>>(sp => BuildOptionsManager<TOptions>(sp));
return this;
}
private static MultiTenantOptionsManager<TOptions> BuildOptionsManager<TOptions>(IServiceProvider sp)
where TOptions : class, new()
{
var cache = (IOptionsMonitorCache<TOptions>)ActivatorUtilities.CreateInstance(sp, typeof(MultiTenantOptionsCache<TOptions, TTenantInfo>));
return (MultiTenantOptionsManager<TOptions>)
ActivatorUtilities.CreateInstance(sp, typeof(MultiTenantOptionsManager<TOptions>), cache);
}
/// <summary>
/// Adds and configures a IMultiTenantStore to the application using default dependency injection.
/// </summary>>
/// <param name="lifetime">The service lifetime.</param>
/// <param name="parameters">a parameter list for any constructor parameters not covered by dependency injection.</param>
/// <returns>The same MultiTenantBuilder passed into the method.</returns>
public FinbuckleMultiTenantBuilder<TTenantInfo> WithStore<TStore>(ServiceLifetime lifetime,
params object[] parameters)
where TStore : IMultiTenantStore<TTenantInfo>
=> WithStore<TStore>(lifetime, sp => ActivatorUtilities.CreateInstance<TStore>(sp, parameters));
/// <summary>
/// Adds and configures a IMultiTenantStore to the application using a factory method.
/// </summary>
/// <param name="lifetime">The service lifetime.</param>
/// <param name="factory">A delegate that will create and configure the store.</param>
/// <returns>The same MultiTenantBuilder passed into the method.</returns>
public FinbuckleMultiTenantBuilder<TTenantInfo> WithStore<TStore>(ServiceLifetime lifetime,
Func<IServiceProvider, TStore> factory)
where TStore : IMultiTenantStore<TTenantInfo>
{
if (factory == null)
{
throw new ArgumentNullException(nameof(factory));
}
// Note: can't use TryAddEnumerable here because ServiceDescriptor.Describe with a factory can't set implementation type.
Services.Add(
ServiceDescriptor.Describe(typeof(IMultiTenantStore<TTenantInfo>), sp => factory(sp), lifetime));
return this;
}
/// <summary>
/// Adds and configures a IMultiTenantStrategy to the application using default dependency injection.
/// </summary>
/// <param name="lifetime">The service lifetime.</param>
/// <param name="parameters">a parameter list for any constructor parameters not covered by dependency injection.</param>
/// <returns>The same MultiTenantBuilder passed into the method.</returns>
public FinbuckleMultiTenantBuilder<TTenantInfo> WithStrategy<TStrategy>(ServiceLifetime lifetime,
params object[] parameters) where TStrategy : IMultiTenantStrategy
=> WithStrategy(lifetime, sp => ActivatorUtilities.CreateInstance<TStrategy>(sp, parameters));
/// <summary>
/// Adds and configures a IMultiTenantStrategy to the application using a factory method.
/// </summary>
/// <param name="lifetime">The service lifetime.</param>
/// <param name="factory">A delegate that will create and configure the strategy.</param>
/// <returns>The same MultiTenantBuilder passed into the method.</returns>
public FinbuckleMultiTenantBuilder<TTenantInfo> WithStrategy<TStrategy>(ServiceLifetime lifetime,
Func<IServiceProvider, TStrategy> factory)
where TStrategy : IMultiTenantStrategy
{
if (factory == null)
{
throw new ArgumentNullException(nameof(factory));
}
// Potential for multiple entries per service is intended.
Services.Add(ServiceDescriptor.Describe(typeof(IMultiTenantStrategy), sp => factory(sp), lifetime));
return this;
}
}
}