Skip to content

Commit e6aeb7c

Browse files
feat: add WithHttpContextStrategy (#934)
1 parent a18a935 commit e6aeb7c

File tree

3 files changed

+75
-20
lines changed

3 files changed

+75
-20
lines changed

docs/ConfigurationAndUsage.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ in the order registered. See [MultiTenant Strategies](Strategies) for more infor
6161
- `WithDelegateStrategy<TContext, TTenantInfo>`
6262
- `WithHeaderStrategy`
6363
- `WithHostStrategy`
64+
- `WithHttpContextStrategy`
6465
- `WithRouteStrategy`
6566
- `WithSessionStrategy`
6667
- `WithStaticStrategy`

docs/Strategies.md

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,8 @@ builder.Services.AddMultiTenant<TenantInfo>()
6161
6262
Uses a provided `Func<object, Task<string>>` to determine the tenant. For example the lambda
6363
function `async context => "initech"` would use "initech" as the identifier when resolving the tenant for every request.
64-
This strategy is good to use for testing or simple logic. This strategy is configured multiple times and will run in the
65-
order configured.
64+
This strategy is good to use for testing or simple logic. This strategy can be used multiple times and will run
65+
in the order configured.
6666

6767
Configure by calling `WithDelegateStrategy` after `AddMultiTenant<TTenantInfo>` A `Func<object, Task<string?>>`is passed
6868
in which will be used with each request to resolve the tenant. A lambda or async lambda can be used as the parameter.
@@ -91,6 +91,30 @@ builder.Services.AddMultiTenant<TenantInfo>()
9191
})...
9292
```
9393

94+
## HttpContext Strategy
95+
96+
> NuGet package: Finbuckle.MultiTenant.AspNetCore
97+
98+
Uses a delegate that takes an `HttpContext` parameter to determine the tenant identifier. When used with the ASP.NET
99+
Core middleware each request's`HttpConeext` is passed to the strategy. This strategy can be used multiple times and will
100+
run in the order configured. Tenant resolution will ignore this strategy if the context is not of the correct type.
101+
102+
Configure by calling `WithHttpContextStrategy` after `AddMultiTenant<TTenantInfo>`:
103+
104+
```csharp
105+
builder.Services.AddMultiTenant<TenantInfo>()
106+
.WithHttpContextStrategy(async httpContext =>
107+
{
108+
var identifier = httpContext.Request.Query["tenant"];
109+
110+
// query value will be empty if the value didn't exist in the request
111+
if(identifier == string.Empty)
112+
return null;
113+
114+
return identifier;
115+
})...
116+
```
117+
94118
## Base Path Strategy
95119

96120
> NuGet package: Finbuckle.MultiTenant.AspNetCore
@@ -244,7 +268,8 @@ builder.Services.AddMultiTenant<TenantInfo>()
244268

245269
> NuGet package: Finbuckle.MultiTenant.AspNetCore
246270
247-
Uses an HTTP request header to determine the tenant identifier. By default, the header with key `__tenant__` is used, but
271+
Uses an HTTP request header to determine the tenant identifier. By default, the header with key `__tenant__` is used,
272+
but
248273
a custom key can also be used.
249274

250275
Configure by calling `WithHeaderStrategy` after `AddMultiTenant<TTenantInfo>`. An overload to accept a custom claim type

src/Finbuckle.MultiTenant.AspNetCore/Extensions/MultiTenantBuilderExtensions.cs

Lines changed: 46 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@ public static class MultiTenantBuilderExtensions
2828
/// <summary>
2929
/// Configures authentication options to enable per-tenant behavior.
3030
/// </summary>
31-
/// <returns>The same MultiTenantBuilder passed into the method.</returns>
31+
/// <typeparam name="TTenantInfo">The ITenantInfo implementation type.</typeparam>
32+
/// <returns>The <see cref="MultiTenantBuilder&lt;TTenantInfo&gt;"/> so that additional calls can be chained.</returns>
3233
public static MultiTenantBuilder<TTenantInfo> WithPerTenantAuthentication<TTenantInfo>(
3334
this MultiTenantBuilder<TTenantInfo> builder)
3435
where TTenantInfo : class, ITenantInfo, new()
@@ -39,9 +40,10 @@ public static MultiTenantBuilder<TTenantInfo> WithPerTenantAuthentication<TTenan
3940
/// <summary>
4041
/// Configures per-tenant authentication behavior.
4142
/// </summary>
43+
/// <typeparam name="TTenantInfo">The ITenantInfo implementation type.</typeparam>
4244
/// <param name="builder">MultiTenantBuilder instance.</param>
4345
/// <param name="config">Authentication options config.</param>
44-
/// <returns>The same MultiTenantBuilder passed into the method.</returns>
46+
/// <returns>The <see cref="MultiTenantBuilder&lt;TTenantInfo&gt;"/> so that additional calls can be chained.</returns>
4547
// ReSharper disable once MemberCanBePrivate.Global
4648
public static MultiTenantBuilder<TTenantInfo> WithPerTenantAuthentication<TTenantInfo>(
4749
this MultiTenantBuilder<TTenantInfo> builder, Action<MultiTenantAuthenticationOptions> config)
@@ -57,7 +59,8 @@ public static MultiTenantBuilder<TTenantInfo> WithPerTenantAuthentication<TTenan
5759
/// <summary>
5860
/// Configures conventional functionality for per-tenant authentication.
5961
/// </summary>
60-
/// <returns>The same MultiTenantBuilder passed into the method.</returns>
62+
/// <typeparam name="TTenantInfo">The ITenantInfo implementation type.</typeparam>
63+
/// <returns>The <see cref="MultiTenantBuilder&lt;TTenantInfo&gt;"/> so that additional calls can be chained.</returns>
6164
public static MultiTenantBuilder<TTenantInfo> WithPerTenantAuthenticationConventions<TTenantInfo>(
6265
this MultiTenantBuilder<TTenantInfo> builder)
6366
where TTenantInfo : class, ITenantInfo, new()
@@ -139,9 +142,10 @@ public static MultiTenantBuilder<TTenantInfo> WithPerTenantAuthenticationConvent
139142
/// <summary>
140143
/// Configures core functionality for per-tenant authentication.
141144
/// </summary>
145+
/// <typeparam name="TTenantInfo">The ITenantInfo implementation type.</typeparam>
142146
/// <param name="builder">MultiTenantBuilder instance.</param>
143147
/// <param name="config">Authentication options config</param>
144-
/// <returns>The same MultiTenantBuilder passed into the method.</returns>
148+
/// <returns>The <see cref="MultiTenantBuilder&lt;TTenantInfo&gt;"/> so that additional calls can be chained.</returns>
145149
public static MultiTenantBuilder<TTenantInfo> WithPerTenantAuthenticationCore<TTenantInfo>(
146150
this MultiTenantBuilder<TTenantInfo> builder, Action<MultiTenantAuthenticationOptions>? config =
147151
null)
@@ -167,8 +171,9 @@ public static MultiTenantBuilder<TTenantInfo> WithPerTenantAuthenticationCore<TT
167171
/// <summary>
168172
/// Adds and configures a SessionStrategy to the application.
169173
/// </summary>
174+
/// <typeparam name="TTenantInfo">The ITenantInfo implementation type.</typeparam>
170175
/// <param name="builder">MultiTenantBuilder instance.</param>
171-
/// <returns>The same MultiTenantBuilder passed into the method.</returns>
176+
/// <returns>The <see cref="MultiTenantBuilder&lt;TTenantInfo&gt;"/> so that additional calls can be chained.</returns>
172177
public static MultiTenantBuilder<TTenantInfo> WithSessionStrategy<TTenantInfo>(
173178
this MultiTenantBuilder<TTenantInfo> builder)
174179
where TTenantInfo : class, ITenantInfo, new()
@@ -177,9 +182,10 @@ public static MultiTenantBuilder<TTenantInfo> WithSessionStrategy<TTenantInfo>(
177182
/// <summary>
178183
/// Adds and configures a SessionStrategy to the application.
179184
/// </summary>
185+
/// <typeparam name="TTenantInfo">The ITenantInfo implementation type.</typeparam>
180186
/// <param name="builder">MultiTenantBuilder instance.</param>
181187
/// <param name="tenantKey">The session key to use.</param>
182-
/// <returns>The same MultiTenantBuilder passed into the method.</returns>
188+
/// <returns>The <see cref="MultiTenantBuilder&lt;TTenantInfo&gt;"/> so that additional calls can be chained.</returns>
183189
public static MultiTenantBuilder<TTenantInfo> WithSessionStrategy<TTenantInfo>(
184190
this MultiTenantBuilder<TTenantInfo> builder, string tenantKey)
185191
where TTenantInfo : class, ITenantInfo, new()
@@ -188,7 +194,8 @@ public static MultiTenantBuilder<TTenantInfo> WithSessionStrategy<TTenantInfo>(
188194
/// <summary>
189195
/// Adds and configures a RemoteAuthenticationCallbackStrategy to the application.
190196
/// </summary>
191-
/// <returns>The same MultiTenantBuilder passed into the method.</returns>
197+
/// <typeparam name="TTenantInfo">The ITenantInfo implementation type.</typeparam>
198+
/// <returns>The <see cref="MultiTenantBuilder&lt;TTenantInfo&gt;"/> so that additional calls can be chained.</returns>
192199
public static MultiTenantBuilder<TTenantInfo> WithRemoteAuthenticationCallbackStrategy<TTenantInfo>(
193200
this MultiTenantBuilder<TTenantInfo> builder)
194201
where TTenantInfo : class, ITenantInfo, new()
@@ -199,6 +206,7 @@ public static MultiTenantBuilder<TTenantInfo> WithRemoteAuthenticationCallbackSt
199206
/// <summary>
200207
/// Adds and configures a BasePathStrategy to the application.
201208
/// </summary>
209+
/// <typeparam name="TTenantInfo">The ITenantInfo implementation type.</typeparam>
202210
/// <returns>The same MultiTenantBuilder passed into the method.></returns>
203211
public static MultiTenantBuilder<TTenantInfo> WithBasePathStrategy<TTenantInfo>(
204212
this MultiTenantBuilder<TTenantInfo> builder)
@@ -208,6 +216,7 @@ public static MultiTenantBuilder<TTenantInfo> WithBasePathStrategy<TTenantInfo>(
208216
/// <summary>
209217
/// Adds and configures a BasePathStrategy to the application.
210218
/// </summary>
219+
/// <typeparam name="TTenantInfo">The ITenantInfo implementation type.</typeparam>
211220
/// <returns>The same MultiTenantBuilder passed into the method.></returns>
212221
public static MultiTenantBuilder<TTenantInfo> WithBasePathStrategy<TTenantInfo>(
213222
this MultiTenantBuilder<TTenantInfo> builder, Action<BasePathStrategyOptions> configureOptions)
@@ -241,7 +250,8 @@ resolutionCompletedContext.Context is HttpContext httpContext &&
241250
/// <summary>
242251
/// Adds and configures a RouteStrategy with a route parameter Constants.TenantToken to the application.
243252
/// </summary>
244-
/// <returns>The same MultiTenantBuilder passed into the method.</returns>
253+
/// <typeparam name="TTenantInfo">The ITenantInfo implementation type.</typeparam>
254+
/// <returns>The <see cref="MultiTenantBuilder&lt;TTenantInfo&gt;"/> so that additional calls can be chained.</returns>
245255
public static MultiTenantBuilder<TTenantInfo> WithRouteStrategy<TTenantInfo>(
246256
this MultiTenantBuilder<TTenantInfo> builder)
247257
where TTenantInfo : class, ITenantInfo, new()
@@ -250,9 +260,10 @@ public static MultiTenantBuilder<TTenantInfo> WithRouteStrategy<TTenantInfo>(
250260
/// <summary>
251261
/// Adds and configures a RouteStrategy to the application.
252262
/// </summary>
263+
/// <typeparam name="TTenantInfo">The ITenantInfo implementation type.</typeparam>
253264
/// <param name="builder">MultiTenantBuilder instance.</param>
254265
/// <param name="tenantParam">The name of the route parameter used to determine the tenant identifier.</param>
255-
/// <returns>The same MultiTenantBuilder passed into the method.</returns>
266+
/// <returns>The <see cref="MultiTenantBuilder&lt;TTenantInfo&gt;"/> so that additional calls can be chained.</returns>
256267
public static MultiTenantBuilder<TTenantInfo> WithRouteStrategy<TTenantInfo>(
257268
this MultiTenantBuilder<TTenantInfo> builder, string tenantParam)
258269
where TTenantInfo : class, ITenantInfo, new()
@@ -264,12 +275,12 @@ public static MultiTenantBuilder<TTenantInfo> WithRouteStrategy<TTenantInfo>(
264275

265276
return builder.WithStrategy<RouteStrategy>(ServiceLifetime.Singleton, tenantParam);
266277
}
267-
// #endif
268278

269279
/// <summary>
270280
/// Adds and configures a HostStrategy with template "__tenant__.*" to the application.
271281
/// </summary>
272-
/// <returns>The same MultiTenantBuilder passed into the method.</returns>
282+
/// <typeparam name="TTenantInfo">The ITenantInfo implementation type.</typeparam>
283+
/// <returns>The <see cref="MultiTenantBuilder&lt;TTenantInfo&gt;"/> so that additional calls can be chained.</returns>
273284
public static MultiTenantBuilder<TTenantInfo> WithHostStrategy<TTenantInfo>(
274285
this MultiTenantBuilder<TTenantInfo> builder)
275286
where TTenantInfo : class, ITenantInfo, new()
@@ -278,9 +289,10 @@ public static MultiTenantBuilder<TTenantInfo> WithHostStrategy<TTenantInfo>(
278289
/// <summary>
279290
/// Adds and configures a HostStrategy to the application.
280291
/// </summary>
292+
/// <typeparam name="TTenantInfo">The ITenantInfo implementation type.</typeparam>
281293
/// <param name="builder">MultiTenantBuilder instance.</param>
282294
/// <param name="template">The template for determining the tenant identifier in the host.</param>
283-
/// <returns>The same MultiTenantBuilder passed into the method.</returns>
295+
/// <returns>The <see cref="MultiTenantBuilder&lt;TTenantInfo&gt;"/> so that additional calls can be chained.</returns>
284296
public static MultiTenantBuilder<TTenantInfo> WithHostStrategy<TTenantInfo>(
285297
this MultiTenantBuilder<TTenantInfo> builder, string template)
286298
where TTenantInfo : class, ITenantInfo, new()
@@ -296,7 +308,8 @@ public static MultiTenantBuilder<TTenantInfo> WithHostStrategy<TTenantInfo>(
296308
/// <summary>
297309
/// Adds and configures a ClaimStrategy for claim name "__tenant__" to the application. Uses the default authentication handler scheme.
298310
/// </summary>
299-
/// <returns>The same MultiTenantBuilder passed into the method.</returns>
311+
/// <typeparam name="TTenantInfo">The ITenantInfo implementation type.</typeparam>
312+
/// <returns>The <see cref="MultiTenantBuilder&lt;TTenantInfo&gt;"/> so that additional calls can be chained.</returns>
300313
public static MultiTenantBuilder<TTenantInfo> WithClaimStrategy<TTenantInfo>(
301314
this MultiTenantBuilder<TTenantInfo> builder) where TTenantInfo : class, ITenantInfo, new()
302315
{
@@ -306,9 +319,10 @@ public static MultiTenantBuilder<TTenantInfo> WithClaimStrategy<TTenantInfo>(
306319
/// <summary>
307320
/// Adds and configures a ClaimStrategy to the application. Uses the default authentication handler scheme.
308321
/// </summary>
322+
/// <typeparam name="TTenantInfo">The ITenantInfo implementation type.</typeparam>
309323
/// <param name="builder">MultiTenantBuilder instance.</param>
310324
/// <param name="tenantKey">Claim name for determining the tenant identifier.</param>
311-
/// <returns>The same MultiTenantBuilder passed into the method.</returns>
325+
/// <returns>The <see cref="MultiTenantBuilder&lt;TTenantInfo&gt;"/> so that additional calls can be chained.</returns>
312326
// ReSharper disable once MemberCanBePrivate.Global
313327
public static MultiTenantBuilder<TTenantInfo> WithClaimStrategy<TTenantInfo>(
314328
this MultiTenantBuilder<TTenantInfo> builder, string tenantKey)
@@ -321,17 +335,32 @@ public static MultiTenantBuilder<TTenantInfo> WithClaimStrategy<TTenantInfo>(
321335
/// <summary>
322336
/// Adds and configures a ClaimStrategy to the application.
323337
/// </summary>
338+
/// <typeparam name="TTenantInfo">The ITenantInfo implementation type.</typeparam>
324339
/// <param name="builder">MultiTenantBuilder instance.</param>
325340
/// <param name="tenantKey">Claim name for determining the tenant identifier.</param>
326341
/// <param name="authenticationScheme">The authentication scheme to check for claims.</param>
327-
/// <returns>The same MultiTenantBuilder passed into the method.</returns>
342+
/// <returns>The <see cref="MultiTenantBuilder&lt;TTenantInfo&gt;"/> so that additional calls can be chained.</returns>
328343
public static MultiTenantBuilder<TTenantInfo> WithClaimStrategy<TTenantInfo>(
329344
this MultiTenantBuilder<TTenantInfo> builder, string tenantKey, string authenticationScheme)
330345
where TTenantInfo : class, ITenantInfo, new()
331346
{
332347
BypassSessionPrincipalValidation(builder);
333348
return builder.WithStrategy<ClaimStrategy>(ServiceLifetime.Singleton, tenantKey, authenticationScheme);
334349
}
350+
351+
/// <summary>
352+
/// Adds and configures an HttpContext delegate strategy to the application.
353+
/// </summary>
354+
/// <typeparam name="TTenantInfo">The ITenantInfo implementation type.</typeparam>
355+
/// <param name="builder">MultiTenantBuilder instance.</param>
356+
/// <param name="doStrategy">The delegate to execute to determine the tenant identifier.</param>
357+
/// <returns>The <see cref="MultiTenantBuilder&lt;TTenantInfo&gt;"/> so that additional calls can be chained.</returns>
358+
public static MultiTenantBuilder<TTenantInfo> WithHttpContextStrategy<TTenantInfo>(
359+
this MultiTenantBuilder<TTenantInfo> builder, Func<HttpContext, Task<string?>> doStrategy)
360+
where TTenantInfo : class, ITenantInfo, new()
361+
{
362+
return builder.WithDelegateStrategy<HttpContext, TTenantInfo>(doStrategy);
363+
}
335364

336365
private static void BypassSessionPrincipalValidation<TTenantInfo>(
337366
MultiTenantBuilder<TTenantInfo> builder)
@@ -355,7 +384,7 @@ private static void BypassSessionPrincipalValidation<TTenantInfo>(
355384
/// <summary>
356385
/// Adds and configures a HeaderStrategy with using HTTP header key "__tenant__" to the application.
357386
/// </summary>
358-
/// <returns>The same MultiTenantBuilder passed into the method.</returns>
387+
/// <returns>The <see cref="MultiTenantBuilder&lt;TTenantInfo&gt;"/> so that additional calls can be chained.</returns>
359388
public static MultiTenantBuilder<TTenantInfo> WithHeaderStrategy<TTenantInfo>(
360389
this MultiTenantBuilder<TTenantInfo> builder) where TTenantInfo : class, ITenantInfo, new()
361390
{
@@ -367,7 +396,7 @@ public static MultiTenantBuilder<TTenantInfo> WithHeaderStrategy<TTenantInfo>(
367396
/// </summary>
368397
/// <param name="builder">MultiTenantBuilder instance.</param>
369398
/// <param name="tenantKey">The HTTP header key for determining the tenant identifier in the request.</param>
370-
/// <returns>The same MultiTenantBuilder passed into the method.</returns>
399+
/// <returns>The <see cref="MultiTenantBuilder&lt;TTenantInfo&gt;"/> so that additional calls can be chained.</returns>
371400
public static MultiTenantBuilder<TTenantInfo> WithHeaderStrategy<TTenantInfo>(
372401
this MultiTenantBuilder<TTenantInfo> builder, string tenantKey)
373402
where TTenantInfo : class, ITenantInfo, new()

0 commit comments

Comments
 (0)