Skip to content

Commit 9834575

Browse files
authoredOct 12, 2024··
feat: strategies return null on invalid context type (#885)
BREAKING CHANGE: Included strategies for ASP.NET Core would throw an exception if the passed context was not an `HttpContext` type. Now they will return null indicating no identifier was found.
1 parent 3263eff commit 9834575

12 files changed

+226
-212
lines changed
 

‎src/Finbuckle.MultiTenant.AspNetCore/Strategies/BasePathStrategy.cs

+10-11
Original file line numberDiff line numberDiff line change
@@ -12,20 +12,19 @@ public class BasePathStrategy : IMultiTenantStrategy
1212
{
1313
public Task<string?> GetIdentifierAsync(object context)
1414
{
15-
if (!(context is HttpContext httpContext))
16-
throw new MultiTenantException(null,
17-
new ArgumentException($"\"{nameof(context)}\" type must be of type HttpContext", nameof(context)));
15+
if (context is not HttpContext httpContext)
16+
return Task.FromResult<string?>(null);
1817

19-
var path = httpContext.Request.Path;
18+
var path = httpContext.Request.Path;
2019

21-
var pathSegments =
22-
path.Value?.Split('/', 2, StringSplitOptions.RemoveEmptyEntries);
20+
var pathSegments =
21+
path.Value?.Split('/', 2, StringSplitOptions.RemoveEmptyEntries);
2322

24-
if (pathSegments is null || pathSegments.Length == 0)
25-
return Task.FromResult<string?>(null);
23+
if (pathSegments is null || pathSegments.Length == 0)
24+
return Task.FromResult<string?>(null);
2625

27-
string identifier = pathSegments[0];
26+
string identifier = pathSegments[0];
2827

29-
return Task.FromResult<string?>(identifier);
30-
}
28+
return Task.FromResult<string?>(identifier);
29+
}
3130
}

‎src/Finbuckle.MultiTenant.AspNetCore/Strategies/ClaimStrategy.cs

+43-40
Original file line numberDiff line numberDiff line change
@@ -15,53 +15,56 @@ namespace Finbuckle.MultiTenant.AspNetCore.Strategies;
1515
// ReSharper disable once ClassNeverInstantiated.Global
1616
public class ClaimStrategy : IMultiTenantStrategy
1717
{
18-
private readonly string _tenantKey;
19-
private readonly string? _authenticationScheme;
18+
private readonly string _tenantKey;
19+
private readonly string? _authenticationScheme;
2020

21-
public ClaimStrategy(string template) : this(template, null)
22-
{
23-
}
21+
public ClaimStrategy(string template) : this(template, null)
22+
{
23+
}
2424

25-
public ClaimStrategy(string template, string? authenticationScheme)
26-
{
27-
if (string.IsNullOrWhiteSpace(template))
28-
throw new ArgumentException(nameof(template));
25+
public ClaimStrategy(string template, string? authenticationScheme)
26+
{
27+
if (string.IsNullOrWhiteSpace(template))
28+
throw new ArgumentException(nameof(template));
2929

30-
_tenantKey = template;
31-
_authenticationScheme = authenticationScheme;
32-
}
30+
_tenantKey = template;
31+
_authenticationScheme = authenticationScheme;
32+
}
3333

34-
public async Task<string?> GetIdentifierAsync(object context)
35-
{
36-
if (!(context is HttpContext httpContext))
37-
throw new MultiTenantException(null, new ArgumentException($@"""{nameof(context)}"" type must be of type HttpContext", nameof(context)));
34+
public async Task<string?> GetIdentifierAsync(object context)
35+
{
36+
if (context is not HttpContext httpContext)
37+
return null;
3838

39-
if (httpContext.User.Identity is { IsAuthenticated: true })
40-
return httpContext.User.FindFirst(_tenantKey)?.Value;
39+
if (httpContext.User.Identity is { IsAuthenticated: true })
40+
return httpContext.User.FindFirst(_tenantKey)?.Value;
4141

42-
AuthenticationScheme? authScheme;
43-
var schemeProvider = httpContext.RequestServices.GetRequiredService<IAuthenticationSchemeProvider>();
44-
if (_authenticationScheme is null)
45-
{
46-
authScheme = await schemeProvider.GetDefaultAuthenticateSchemeAsync();
47-
}
48-
else
49-
{
50-
authScheme = (await schemeProvider.GetAllSchemesAsync()).FirstOrDefault(x => x.Name == _authenticationScheme);
51-
}
42+
AuthenticationScheme? authScheme;
43+
var schemeProvider = httpContext.RequestServices.GetRequiredService<IAuthenticationSchemeProvider>();
44+
if (_authenticationScheme is null)
45+
{
46+
authScheme = await schemeProvider.GetDefaultAuthenticateSchemeAsync();
47+
}
48+
else
49+
{
50+
authScheme =
51+
(await schemeProvider.GetAllSchemesAsync()).FirstOrDefault(x => x.Name == _authenticationScheme);
52+
}
5253

53-
if (authScheme is null)
54-
{
55-
return null;
56-
}
54+
if (authScheme is null)
55+
{
56+
return null;
57+
}
5758

58-
var handler = (IAuthenticationHandler)ActivatorUtilities.CreateInstance(httpContext.RequestServices, authScheme.HandlerType);
59-
await handler.InitializeAsync(authScheme, httpContext);
60-
httpContext.Items[$"{Constants.TenantToken}__bypass_validate_principal__"] = "true"; // Value doesn't matter.
61-
var handlerResult = await handler.AuthenticateAsync();
62-
httpContext.Items.Remove($"{Constants.TenantToken}__bypass_validate_principal__");
59+
var handler =
60+
(IAuthenticationHandler)ActivatorUtilities.CreateInstance(httpContext.RequestServices,
61+
authScheme.HandlerType);
62+
await handler.InitializeAsync(authScheme, httpContext);
63+
httpContext.Items[$"{Constants.TenantToken}__bypass_validate_principal__"] = "true"; // Value doesn't matter.
64+
var handlerResult = await handler.AuthenticateAsync();
65+
httpContext.Items.Remove($"{Constants.TenantToken}__bypass_validate_principal__");
6366

64-
var identifier = handlerResult.Principal?.FindFirst(_tenantKey)?.Value;
65-
return identifier;
66-
}
67+
var identifier = handlerResult.Principal?.FindFirst(_tenantKey)?.Value;
68+
return identifier;
69+
}
6770
}

‎src/Finbuckle.MultiTenant.AspNetCore/Strategies/HeaderStrategy.cs

+2-3
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,8 @@ public HeaderStrategy(string headerKey)
2121

2222
public Task<string?> GetIdentifierAsync(object context)
2323
{
24-
if (!(context is HttpContext httpContext))
25-
throw new MultiTenantException(null,
26-
new ArgumentException($"\"{nameof(context)}\" type must be of type HttpContext", nameof(context)));
24+
if (context is not HttpContext httpContext)
25+
return Task.FromResult<string?>(null);
2726

2827
return Task.FromResult(httpContext?.Request.Headers[_headerKey].FirstOrDefault());
2928
}

‎src/Finbuckle.MultiTenant.AspNetCore/Strategies/HostStrategy.cs

+57-55
Original file line numberDiff line numberDiff line change
@@ -16,74 +16,76 @@ public class HostStrategy : IMultiTenantStrategy
1616

1717
public HostStrategy(string template)
1818
{
19-
// New in 2.1, match whole domain if just "__tenant__".
20-
if (template == Constants.TenantToken)
19+
// match whole domain if just "__tenant__".
20+
if (template == Constants.TenantToken)
21+
{
22+
template = template.Replace(Constants.TenantToken, "(?<identifier>.+)");
23+
}
24+
else
25+
{
26+
// Check for valid template.
27+
// Template cannot be null or whitespace.
28+
if (string.IsNullOrWhiteSpace(template))
29+
{
30+
throw new MultiTenantException("Template cannot be null or whitespace.");
31+
}
32+
33+
// Wildcard "*" must be only occur once in template.
34+
if (Regex.Match(template, @"\*(?=.*\*)").Success)
35+
{
36+
throw new MultiTenantException("Wildcard \"*\" must be only occur once in template.");
37+
}
38+
39+
// Wildcard "*" must be only token in template segment.
40+
if (Regex.Match(template, @"\*[^\.]|[^\.]\*").Success)
41+
{
42+
throw new MultiTenantException("\"*\" wildcard must be only token in template segment.");
43+
}
44+
45+
// Wildcard "?" must be only token in template segment.
46+
if (Regex.Match(template, @"\?[^\.]|[^\.]\?").Success)
2147
{
22-
template = template.Replace(Constants.TenantToken, "(?<identifier>.+)");
48+
throw new MultiTenantException("\"?\" wildcard must be only token in template segment.");
2349
}
24-
else
50+
51+
template = template.Trim().Replace(".", @"\.");
52+
string wildcardSegmentsPattern = @"(\.[^\.]+)*";
53+
string singleSegmentPattern = @"[^\.]+";
54+
if (template.Substring(template.Length - 3, 3) == @"\.*")
2555
{
26-
// Check for valid template.
27-
// Template cannot be null or whitespace.
28-
if (string.IsNullOrWhiteSpace(template))
29-
{
30-
throw new MultiTenantException("Template cannot be null or whitespace.");
31-
}
32-
// Wildcard "*" must be only occur once in template.
33-
if (Regex.Match(template, @"\*(?=.*\*)").Success)
34-
{
35-
throw new MultiTenantException("Wildcard \"*\" must be only occur once in template.");
36-
}
37-
// Wildcard "*" must be only token in template segment.
38-
if (Regex.Match(template, @"\*[^\.]|[^\.]\*").Success)
39-
{
40-
throw new MultiTenantException("\"*\" wildcard must be only token in template segment.");
41-
}
42-
// Wildcard "?" must be only token in template segment.
43-
if (Regex.Match(template, @"\?[^\.]|[^\.]\?").Success)
44-
{
45-
throw new MultiTenantException("\"?\" wildcard must be only token in template segment.");
46-
}
47-
48-
template = template.Trim().Replace(".", @"\.");
49-
string wildcardSegmentsPattern = @"(\.[^\.]+)*";
50-
string singleSegmentPattern = @"[^\.]+";
51-
if (template.Substring(template.Length - 3, 3) == @"\.*")
52-
{
53-
template = template.Substring(0, template.Length - 3) + wildcardSegmentsPattern;
54-
}
55-
56-
wildcardSegmentsPattern = @"([^\.]+\.)*";
57-
template = template.Replace(@"*\.", wildcardSegmentsPattern);
58-
template = template.Replace("?", singleSegmentPattern);
59-
template = template.Replace(Constants.TenantToken, @"(?<identifier>[^\.]+)");
56+
template = template.Substring(0, template.Length - 3) + wildcardSegmentsPattern;
6057
}
6158

62-
this.regex = $"^{template}$";
59+
wildcardSegmentsPattern = @"([^\.]+\.)*";
60+
template = template.Replace(@"*\.", wildcardSegmentsPattern);
61+
template = template.Replace("?", singleSegmentPattern);
62+
template = template.Replace(Constants.TenantToken, @"(?<identifier>[^\.]+)");
6363
}
6464

65+
this.regex = $"^{template}$";
66+
}
67+
6568
public Task<string?> GetIdentifierAsync(object context)
6669
{
67-
if (!(context is HttpContext httpContext))
68-
throw new MultiTenantException(null,
69-
new ArgumentException($"\"{nameof(context)}\" type must be of type HttpContext", nameof(context)));
70+
if (context is not HttpContext httpContext)
71+
return Task.FromResult<string?>(null);
7072

71-
var host = httpContext.Request.Host;
73+
var host = httpContext.Request.Host;
7274

73-
if (host.HasValue == false)
74-
return Task.FromResult<string?>(null);
75+
if (host.HasValue == false)
76+
return Task.FromResult<string?>(null);
7577

76-
string? identifier = null;
78+
string? identifier = null;
7779

78-
var match = Regex.Match(host.Host, regex,
79-
RegexOptions.ExplicitCapture,
80-
TimeSpan.FromMilliseconds(100));
80+
var match = Regex.Match(host.Host, regex,
81+
RegexOptions.ExplicitCapture,
82+
TimeSpan.FromMilliseconds(100));
8183

82-
if (match.Success)
83-
{
84-
identifier = match.Groups["identifier"].Value;
85-
}
86-
87-
return Task.FromResult(identifier);
84+
if (match.Success)
85+
{
86+
identifier = match.Groups["identifier"].Value;
8887
}
88+
89+
return Task.FromResult(identifier);
90+
}
8991
}

‎src/Finbuckle.MultiTenant.AspNetCore/Strategies/RemoteAuthenticationCallbackStrategy.cs

+71-64
Original file line numberDiff line numberDiff line change
@@ -19,89 +19,96 @@ public class RemoteAuthenticationCallbackStrategy : IMultiTenantStrategy
1919
{
2020
private readonly ILogger<RemoteAuthenticationCallbackStrategy> logger;
2121

22-
public int Priority { get => -900; }
22+
public int Priority
23+
{
24+
get => -900;
25+
}
2326

2427
public RemoteAuthenticationCallbackStrategy(ILogger<RemoteAuthenticationCallbackStrategy> logger)
2528
{
26-
this.logger = logger;
27-
}
29+
this.logger = logger;
30+
}
2831

2932
public async virtual Task<string?> GetIdentifierAsync(object context)
3033
{
31-
if (!(context is HttpContext httpContext))
32-
throw new MultiTenantException(null,
33-
new ArgumentException($"\"{nameof(context)}\" type must be of type HttpContext", nameof(context)));
34+
if (context is not HttpContext httpContext)
35+
return null;
3436

35-
var schemes = httpContext.RequestServices.GetRequiredService<IAuthenticationSchemeProvider>();
37+
var schemes = httpContext.RequestServices.GetRequiredService<IAuthenticationSchemeProvider>();
3638

37-
foreach (var scheme in (await schemes.GetRequestHandlerSchemesAsync()).
38-
Where(s => typeof(IAuthenticationRequestHandler).IsAssignableFrom(s.HandlerType)))
39-
// Where(s => s.HandlerType.ImplementsOrInheritsUnboundGeneric(typeof(RemoteAuthenticationHandler<>))))
40-
{
41-
// TODO verify this comment
42-
// Unfortunately we can't rely on the ShouldHandleAsync method since OpenId Connect handler doesn't use it.
43-
// Instead we'll get the paths to check from the options.
44-
var optionsType = scheme.HandlerType.GetProperty("Options")?.PropertyType;
39+
foreach (var scheme in (await schemes.GetRequestHandlerSchemesAsync()).Where(s =>
40+
typeof(IAuthenticationRequestHandler).IsAssignableFrom(s.HandlerType)))
41+
{
42+
// TODO verify this comment (still true as of net8.0)
43+
// Unfortunately we can't rely on the ShouldHandleAsync method since OpenId Connect handler doesn't use it.
44+
// Instead we'll get the paths to check from the options.
45+
var optionsType = scheme.HandlerType.GetProperty("Options")?.PropertyType;
4546

46-
if (optionsType is null)
47-
{
48-
continue;
49-
}
47+
if (optionsType is null)
48+
{
49+
continue;
50+
}
5051

51-
var optionsMonitorType = typeof(IOptionsMonitor<>).MakeGenericType(optionsType);
52-
var optionsMonitor = httpContext.RequestServices.GetRequiredService(optionsMonitorType);
53-
var options = optionsMonitorType?.GetMethod("Get")?.Invoke(optionsMonitor, new[] { scheme.Name }) as RemoteAuthenticationOptions;
52+
var optionsMonitorType = typeof(IOptionsMonitor<>).MakeGenericType(optionsType);
53+
var optionsMonitor = httpContext.RequestServices.GetRequiredService(optionsMonitorType);
54+
var options =
55+
optionsMonitorType?.GetMethod("Get")?.Invoke(optionsMonitor, new[] { scheme.Name }) as
56+
RemoteAuthenticationOptions;
5457

55-
if (options is null)
56-
{
57-
continue;
58-
}
58+
if (options is null)
59+
{
60+
continue;
61+
}
5962

60-
var callbackPath = (PathString)(optionsType.GetProperty("CallbackPath")?.GetValue(options) ?? PathString.Empty);
61-
var signedOutCallbackPath = (PathString)(optionsType.GetProperty("SignedOutCallbackPath")?.GetValue(options) ?? PathString.Empty);
63+
var callbackPath =
64+
(PathString)(optionsType.GetProperty("CallbackPath")?.GetValue(options) ?? PathString.Empty);
65+
var signedOutCallbackPath =
66+
(PathString)(optionsType.GetProperty("SignedOutCallbackPath")?.GetValue(options) ?? PathString.Empty);
6267

63-
if (callbackPath.HasValue && callbackPath == httpContext.Request.Path ||
64-
signedOutCallbackPath.HasValue && signedOutCallbackPath == httpContext.Request.Path)
68+
if (callbackPath.HasValue && callbackPath == httpContext.Request.Path ||
69+
signedOutCallbackPath.HasValue && signedOutCallbackPath == httpContext.Request.Path)
70+
{
71+
try
6572
{
66-
try
73+
string? state = null;
74+
75+
if (string.Equals(httpContext.Request.Method, "GET", StringComparison.OrdinalIgnoreCase))
6776
{
68-
string? state = null;
69-
70-
if (string.Equals(httpContext.Request.Method, "GET", StringComparison.OrdinalIgnoreCase))
71-
{
72-
state = httpContext.Request.Query["state"];
73-
}
74-
// Assumption: it is safe to read the form, limit to 1MB form size.
75-
else if (string.Equals(httpContext.Request.Method, "POST", StringComparison.OrdinalIgnoreCase)
76-
&& httpContext.Request.HasFormContentType
77-
&& httpContext.Request.Body.CanRead)
78-
{
79-
var formOptions = new FormOptions { BufferBody = true, MemoryBufferThreshold = 1048576 };
80-
81-
var form = await httpContext.Request.ReadFormAsync(formOptions);
82-
state = form.Single(i => string.Equals(i.Key, "state", StringComparison.OrdinalIgnoreCase)).Value;
83-
}
84-
85-
var properties = ((dynamic)options).StateDataFormat.Unprotect(state) as AuthenticationProperties;
86-
87-
if (properties == null)
88-
{
89-
if (logger != null)
90-
logger.LogWarning("A tenant could not be determined because no state parameter passed with the remote authentication callback.");
91-
return null;
92-
}
93-
94-
properties.Items.TryGetValue(Constants.TenantToken, out var identifier);
95-
96-
return identifier;
77+
state = httpContext.Request.Query["state"];
9778
}
98-
catch (Exception e)
79+
// Assumption: it is safe to read the form, limit to 1MB form size.
80+
else if (string.Equals(httpContext.Request.Method, "POST", StringComparison.OrdinalIgnoreCase)
81+
&& httpContext.Request.HasFormContentType
82+
&& httpContext.Request.Body.CanRead)
9983
{
100-
throw new MultiTenantException("Error occurred resolving tenant for remote authentication.", e);
84+
var formOptions = new FormOptions { BufferBody = true, MemoryBufferThreshold = 1048576 };
85+
86+
var form = await httpContext.Request.ReadFormAsync(formOptions);
87+
state = form.Single(i => string.Equals(i.Key, "state", StringComparison.OrdinalIgnoreCase))
88+
.Value;
10189
}
90+
91+
var properties = ((dynamic)options).StateDataFormat.Unprotect(state) as AuthenticationProperties;
92+
93+
if (properties == null)
94+
{
95+
if (logger != null)
96+
logger.LogWarning(
97+
"A tenant could not be determined because no state parameter passed with the remote authentication callback.");
98+
return null;
99+
}
100+
101+
properties.Items.TryGetValue(Constants.TenantToken, out var identifier);
102+
103+
return identifier;
104+
}
105+
catch (Exception e)
106+
{
107+
throw new MultiTenantException("Error occurred resolving tenant for remote authentication.", e);
102108
}
103109
}
104-
105-
return null;
106110
}
111+
112+
return null;
113+
}
107114
}

‎src/Finbuckle.MultiTenant.AspNetCore/Strategies/RouteStrategy.cs

+3-5
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,10 @@ public RouteStrategy(string tenantParam)
2525
public Task<string?> GetIdentifierAsync(object context)
2626
{
2727

28-
if (!(context is HttpContext httpContext))
29-
throw new MultiTenantException(null,
30-
new ArgumentException($"\"{nameof(context)}\" type must be of type HttpContext", nameof(context)));
28+
if (context is not HttpContext httpContext)
29+
return Task.FromResult<string?>(null);
3130

32-
object? identifier;
33-
httpContext.Request.RouteValues.TryGetValue(TenantParam, out identifier);
31+
httpContext.Request.RouteValues.TryGetValue(TenantParam, out var identifier);
3432

3533
return Task.FromResult(identifier as string);
3634
}

‎src/Finbuckle.MultiTenant.AspNetCore/Strategies/SessionStrategy.cs

+11-12
Original file line numberDiff line numberDiff line change
@@ -14,21 +14,20 @@ public class SessionStrategy : IMultiTenantStrategy
1414

1515
public SessionStrategy(string tenantKey)
1616
{
17-
if (string.IsNullOrWhiteSpace(tenantKey))
18-
{
19-
throw new ArgumentException("message", nameof(tenantKey));
20-
}
21-
22-
this.tenantKey = tenantKey;
17+
if (string.IsNullOrWhiteSpace(tenantKey))
18+
{
19+
throw new ArgumentException("message", nameof(tenantKey));
2320
}
2421

22+
this.tenantKey = tenantKey;
23+
}
24+
2525
public Task<string?> GetIdentifierAsync(object context)
2626
{
27-
if(!(context is HttpContext httpContext))
28-
throw new MultiTenantException(null,
29-
new ArgumentException($"\"{nameof(context)}\" type must be of type HttpContext", nameof(context)));
27+
if (context is not HttpContext httpContext)
28+
return Task.FromResult<string?>(null);
3029

31-
var identifier = httpContext.Session.GetString(tenantKey);
32-
return Task.FromResult<string?>(identifier); // Prevent the compiler warning that no await exists.
33-
}
30+
var identifier = httpContext.Session.GetString(tenantKey);
31+
return Task.FromResult(identifier);
32+
}
3433
}

‎test/Finbuckle.MultiTenant.AspNetCore.Test/Strategies/BasePathStrategyShould.cs

+3-3
Original file line numberDiff line numberDiff line change
@@ -98,12 +98,12 @@ public async void ReturnExpectedIdentifier(string path, string? expected)
9898
}
9999

100100
[Fact]
101-
public async void ThrowIfContextIsNotHttpContext()
101+
public async void ReturnNullIfContextIsNotHttpContext()
102102
{
103-
var context = new Object();
103+
var context = new object();
104104
var strategy = new BasePathStrategy();
105105

106-
await Assert.ThrowsAsync<MultiTenantException>(() => strategy.GetIdentifierAsync(context));
106+
Assert.Null(await strategy.GetIdentifierAsync(context));
107107
}
108108

109109
[Fact]

‎test/Finbuckle.MultiTenant.AspNetCore.Test/Strategies/HostStrategyShould.cs

+3-3
Original file line numberDiff line numberDiff line change
@@ -69,11 +69,11 @@ public void ThrowIfInvalidTemplate(string? template)
6969
}
7070

7171
[Fact]
72-
public async void ThrowIfContextIsNotHttpContext()
72+
public async void ReturnNullIfContextIsNotHttpContext()
7373
{
74-
var context = new Object();
74+
var context = new object();
7575
var strategy = new HostStrategy("__tenant__.*");
7676

77-
await Assert.ThrowsAsync<MultiTenantException>(() => strategy.GetIdentifierAsync(context));
77+
Assert.Null(await strategy.GetIdentifierAsync(context));
7878
}
7979
}

‎test/Finbuckle.MultiTenant.AspNetCore.Test/Strategies/RemoteAuthenticationCallbackStrategyShould.cs

+12-3
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,16 @@ public class RemoteAuthenticationCallbackStrategyShould
1313
[Fact]
1414
public void HavePriorityNeg900()
1515
{
16-
var strategy = new RemoteAuthenticationCallbackStrategy(null!);
17-
Assert.Equal(-900, strategy.Priority);
18-
}
16+
var strategy = new RemoteAuthenticationCallbackStrategy(null!);
17+
Assert.Equal(-900, strategy.Priority);
18+
}
19+
20+
[Fact]
21+
public async void ReturnNullIfContextIsNotHttpContext()
22+
{
23+
var context = new object();
24+
var strategy = new RemoteAuthenticationCallbackStrategy(null!);
25+
26+
Assert.Null(await strategy.GetIdentifierAsync(context));
27+
}
1928
}

‎test/Finbuckle.MultiTenant.AspNetCore.Test/Strategies/RouteStrategyShould.cs

+3-3
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,12 @@ public async Task ReturnExpectedIdentifier(string path, string identifier, strin
3232
}
3333

3434
[Fact]
35-
public async void ThrowIfContextIsNotHttpContext()
35+
public async void ReturnNullIfContextIsNotHttpContext()
3636
{
37-
var context = new Object();
37+
var context = new object();
3838
var strategy = new RouteStrategy("__tenant__");
3939

40-
await Assert.ThrowsAsync<MultiTenantException>(() => strategy.GetIdentifierAsync(context));
40+
Assert.Null(await strategy.GetIdentifierAsync(context));
4141
}
4242

4343
[Fact]

‎test/Finbuckle.MultiTenant.AspNetCore.Test/Strategies/SessionStrategyShould.cs

+8-10
Original file line numberDiff line numberDiff line change
@@ -53,25 +53,23 @@ private static IWebHostBuilder GetTestHostBuilder(string identifier, string sess
5353
}
5454

5555
[Fact]
56-
public async void ThrowIfContextIsNotHttpContext()
56+
public async void ReturnNullIfContextIsNotHttpContext()
5757
{
58-
var context = new Object();
58+
var context = new object();
5959
var strategy = new SessionStrategy("__tenant__");
60-
61-
await Assert.ThrowsAsync<MultiTenantException>(() => strategy.GetIdentifierAsync(context));
60+
61+
Assert.Null(await strategy.GetIdentifierAsync(context));
6262
}
6363

6464
[Fact]
6565
public async Task ReturnNullIfNoSessionValue()
6666
{
6767
var hostBuilder = GetTestHostBuilder("test_tenant", "__tenant__");
6868

69-
using (var server = new TestServer(hostBuilder))
70-
{
71-
var client = server.CreateClient();
72-
var response = await client.GetStringAsync("/test_tenant");
73-
Assert.Equal("", response);
74-
}
69+
using var server = new TestServer(hostBuilder);
70+
var client = server.CreateClient();
71+
var response = await client.GetStringAsync("/test_tenant");
72+
Assert.Equal("", response);
7573
}
7674

7775
// TODO: Figure out how to test this

0 commit comments

Comments
 (0)
Please sign in to comment.