diff --git a/src/Http/Authentication.Abstractions/ref/Microsoft.AspNetCore.Authentication.Abstractions.netcoreapp.cs b/src/Http/Authentication.Abstractions/ref/Microsoft.AspNetCore.Authentication.Abstractions.netcoreapp.cs index dd9628c89a..00d49aba92 100644 --- a/src/Http/Authentication.Abstractions/ref/Microsoft.AspNetCore.Authentication.Abstractions.netcoreapp.cs +++ b/src/Http/Authentication.Abstractions/ref/Microsoft.AspNetCore.Authentication.Abstractions.netcoreapp.cs @@ -149,6 +149,7 @@ namespace Microsoft.AspNetCore.Authentication System.Threading.Tasks.Task> GetRequestHandlerSchemesAsync(); System.Threading.Tasks.Task GetSchemeAsync(string name); void RemoveScheme(string name); + bool TryAddScheme(Microsoft.AspNetCore.Authentication.AuthenticationScheme scheme) { throw null; } } public partial interface IAuthenticationService { diff --git a/src/Http/Authentication.Abstractions/src/IAuthenticationSchemeProvider.cs b/src/Http/Authentication.Abstractions/src/IAuthenticationSchemeProvider.cs index 3d2584fca8..d0f54d74d0 100644 --- a/src/Http/Authentication.Abstractions/src/IAuthenticationSchemeProvider.cs +++ b/src/Http/Authentication.Abstractions/src/IAuthenticationSchemeProvider.cs @@ -71,6 +71,23 @@ namespace Microsoft.AspNetCore.Authentication /// The scheme. void AddScheme(AuthenticationScheme scheme); + /// + /// Registers a scheme for use by . + /// + /// The scheme. + /// true if the scheme was added successfully. + bool TryAddScheme(AuthenticationScheme scheme) + { + try + { + AddScheme(scheme); + return true; + } + catch { + return false; + } + } + /// /// Removes a scheme, preventing it from being used by . /// diff --git a/src/Http/Authentication.Core/ref/Microsoft.AspNetCore.Authentication.Core.netcoreapp.cs b/src/Http/Authentication.Core/ref/Microsoft.AspNetCore.Authentication.Core.netcoreapp.cs index f12e27bcf2..0267014059 100644 --- a/src/Http/Authentication.Core/ref/Microsoft.AspNetCore.Authentication.Core.netcoreapp.cs +++ b/src/Http/Authentication.Core/ref/Microsoft.AspNetCore.Authentication.Core.netcoreapp.cs @@ -30,6 +30,7 @@ namespace Microsoft.AspNetCore.Authentication public virtual System.Threading.Tasks.Task> GetRequestHandlerSchemesAsync() { throw null; } public virtual System.Threading.Tasks.Task GetSchemeAsync(string name) { throw null; } public virtual void RemoveScheme(string name) { } + public virtual bool TryAddScheme(Microsoft.AspNetCore.Authentication.AuthenticationScheme scheme) { throw null; } } public partial class AuthenticationService : Microsoft.AspNetCore.Authentication.IAuthenticationService { diff --git a/src/Http/Authentication.Core/src/AuthenticationSchemeProvider.cs b/src/Http/Authentication.Core/src/AuthenticationSchemeProvider.cs index a7b913b1b2..4f181081f2 100644 --- a/src/Http/Authentication.Core/src/AuthenticationSchemeProvider.cs +++ b/src/Http/Authentication.Core/src/AuthenticationSchemeProvider.cs @@ -133,17 +133,18 @@ namespace Microsoft.AspNetCore.Authentication /// Registers a scheme for use by . /// /// The scheme. - public virtual void AddScheme(AuthenticationScheme scheme) + /// true if the scheme was added successfully. + public virtual bool TryAddScheme(AuthenticationScheme scheme) { if (_schemes.ContainsKey(scheme.Name)) { - throw new InvalidOperationException("Scheme already exists: " + scheme.Name); + return false; } lock (_lock) { if (_schemes.ContainsKey(scheme.Name)) { - throw new InvalidOperationException("Scheme already exists: " + scheme.Name); + return false; } if (typeof(IAuthenticationRequestHandler).IsAssignableFrom(scheme.HandlerType)) { @@ -152,6 +153,26 @@ namespace Microsoft.AspNetCore.Authentication } _schemes[scheme.Name] = scheme; _schemesCopy = _schemes.Values.ToArray(); + return true; + } + } + + /// + /// Registers a scheme for use by . + /// + /// The scheme. + public virtual void AddScheme(AuthenticationScheme scheme) + { + if (_schemes.ContainsKey(scheme.Name)) + { + throw new InvalidOperationException("Scheme already exists: " + scheme.Name); + } + lock (_lock) + { + if (!TryAddScheme(scheme)) + { + throw new InvalidOperationException("Scheme already exists: " + scheme.Name); + } } } diff --git a/src/Http/Authentication.Core/test/AuthenticationSchemeProviderTests.cs b/src/Http/Authentication.Core/test/AuthenticationSchemeProviderTests.cs index 82602000aa..8ef2f9d347 100644 --- a/src/Http/Authentication.Core/test/AuthenticationSchemeProviderTests.cs +++ b/src/Http/Authentication.Core/test/AuthenticationSchemeProviderTests.cs @@ -133,6 +133,23 @@ namespace Microsoft.AspNetCore.Authentication Assert.Contains("Scheme already exists: signin", error.Message); } + [Fact] + public void CanSafelyTryAddSchemes() + { + var services = new ServiceCollection().AddOptions().AddAuthenticationCore(o => + { + }).BuildServiceProvider(); + + var o = services.GetRequiredService(); + Assert.True(o.TryAddScheme(new AuthenticationScheme("signin", "whatever", typeof(Handler)))); + Assert.True(o.TryAddScheme(new AuthenticationScheme("signin2", "whatever", typeof(Handler)))); + Assert.False(o.TryAddScheme(new AuthenticationScheme("signin", "whatever", typeof(Handler)))); + Assert.True(o.TryAddScheme(new AuthenticationScheme("signin3", "whatever", typeof(Handler)))); + Assert.False(o.TryAddScheme(new AuthenticationScheme("signin2", "whatever", typeof(Handler)))); + o.RemoveScheme("signin2"); + Assert.True(o.TryAddScheme(new AuthenticationScheme("signin2", "whatever", typeof(Handler)))); + } + [Fact] public async Task LookupUsesProvidedStringComparer() {