From bef75c4f56b1d6571a41a4ddcd0fea67fcb07d23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Chalet?= Date: Wed, 19 Mar 2025 19:36:12 +0100 Subject: [PATCH] Use the CreateAsyncScope() helper to avoid having to manually cast IServiceProvider to IAsyncDisposable --- .../Worker.cs | 28 +- .../Worker.cs | 32 +- .../Worker.cs | 2 +- .../Worker.cs | 2 +- .../OpenIddict.Sandbox.Wpf.Client/Worker.cs | 2 +- ...penIddictClientSystemIntegrationService.cs | 56 +- .../OpenIddictClientService.cs | 2572 +++++++---------- src/OpenIddict.Quartz/OpenIddictQuartzJob.cs | 168 +- .../OpenIddictValidationService.cs | 560 ++-- .../OpenIddictServerOwinIntegrationTests.cs | 2 +- ...penIddictValidationOwinIntegrationTests.cs | 2 +- 11 files changed, 1474 insertions(+), 1952 deletions(-) diff --git a/sandbox/OpenIddict.Sandbox.AspNetCore.Client/Worker.cs b/sandbox/OpenIddict.Sandbox.AspNetCore.Client/Worker.cs index c13e41bf..62108875 100644 --- a/sandbox/OpenIddict.Sandbox.AspNetCore.Client/Worker.cs +++ b/sandbox/OpenIddict.Sandbox.AspNetCore.Client/Worker.cs @@ -4,33 +4,17 @@ namespace OpenIddict.Sandbox.AspNetCore.Client; public class Worker : IHostedService { - private readonly IServiceProvider _serviceProvider; + private readonly IServiceProvider _provider; - public Worker(IServiceProvider serviceProvider) - => _serviceProvider = serviceProvider; + public Worker(IServiceProvider provider) + => _provider = provider; public async Task StartAsync(CancellationToken cancellationToken) { - var scope = _serviceProvider.CreateScope(); + await using var scope = _provider.CreateAsyncScope(); - try - { - var context = scope.ServiceProvider.GetRequiredService(); - await context.Database.EnsureCreatedAsync(cancellationToken); - } - - finally - { - if (scope is IAsyncDisposable disposable) - { - await disposable.DisposeAsync(); - } - - else - { - scope.Dispose(); - } - } + var context = scope.ServiceProvider.GetRequiredService(); + await context.Database.EnsureCreatedAsync(cancellationToken); } public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask; diff --git a/sandbox/OpenIddict.Sandbox.AspNetCore.Server/Worker.cs b/sandbox/OpenIddict.Sandbox.AspNetCore.Server/Worker.cs index 7d79458c..c8b5ec0a 100644 --- a/sandbox/OpenIddict.Sandbox.AspNetCore.Server/Worker.cs +++ b/sandbox/OpenIddict.Sandbox.AspNetCore.Server/Worker.cs @@ -9,36 +9,20 @@ namespace OpenIddict.Sandbox.AspNetCore.Server; public class Worker : IHostedService { - private readonly IServiceProvider _serviceProvider; + private readonly IServiceProvider _provider; - public Worker(IServiceProvider serviceProvider) - => _serviceProvider = serviceProvider; + public Worker(IServiceProvider provider) + => _provider = provider; public async Task StartAsync(CancellationToken cancellationToken) { - var scope = _serviceProvider.CreateScope(); + await using var scope = _provider.CreateAsyncScope(); - try - { - var context = scope.ServiceProvider.GetRequiredService(); - await context.Database.EnsureCreatedAsync(cancellationToken); - - await RegisterApplicationsAsync(scope.ServiceProvider); - await RegisterScopesAsync(scope.ServiceProvider); - } - - finally - { - if (scope is IAsyncDisposable disposable) - { - await disposable.DisposeAsync(); - } + var context = scope.ServiceProvider.GetRequiredService(); + await context.Database.EnsureCreatedAsync(cancellationToken); - else - { - scope.Dispose(); - } - } + await RegisterApplicationsAsync(scope.ServiceProvider); + await RegisterScopesAsync(scope.ServiceProvider); static async Task RegisterApplicationsAsync(IServiceProvider provider) { diff --git a/sandbox/OpenIddict.Sandbox.Console.Client/Worker.cs b/sandbox/OpenIddict.Sandbox.Console.Client/Worker.cs index fc054ee5..00df826d 100644 --- a/sandbox/OpenIddict.Sandbox.Console.Client/Worker.cs +++ b/sandbox/OpenIddict.Sandbox.Console.Client/Worker.cs @@ -13,7 +13,7 @@ public class Worker : IHostedService public async Task StartAsync(CancellationToken cancellationToken) { - using var scope = _provider.CreateScope(); + await using var scope = _provider.CreateAsyncScope(); var context = scope.ServiceProvider.GetRequiredService(); await context.Database.EnsureCreatedAsync(cancellationToken); diff --git a/sandbox/OpenIddict.Sandbox.WinForms.Client/Worker.cs b/sandbox/OpenIddict.Sandbox.WinForms.Client/Worker.cs index 10aed3f9..6bfca1b3 100644 --- a/sandbox/OpenIddict.Sandbox.WinForms.Client/Worker.cs +++ b/sandbox/OpenIddict.Sandbox.WinForms.Client/Worker.cs @@ -15,7 +15,7 @@ public class Worker : IHostedService public async Task StartAsync(CancellationToken cancellationToken) { - using var scope = _provider.CreateScope(); + await using var scope = _provider.CreateAsyncScope(); var context = scope.ServiceProvider.GetRequiredService(); await context.Database.EnsureCreatedAsync(cancellationToken); diff --git a/sandbox/OpenIddict.Sandbox.Wpf.Client/Worker.cs b/sandbox/OpenIddict.Sandbox.Wpf.Client/Worker.cs index 027cc21e..0f65a8d5 100644 --- a/sandbox/OpenIddict.Sandbox.Wpf.Client/Worker.cs +++ b/sandbox/OpenIddict.Sandbox.Wpf.Client/Worker.cs @@ -15,7 +15,7 @@ public class Worker : IHostedService public async Task StartAsync(CancellationToken cancellationToken) { - using var scope = _provider.CreateScope(); + await using var scope = _provider.CreateAsyncScope(); var context = scope.ServiceProvider.GetRequiredService(); await context.Database.EnsureCreatedAsync(cancellationToken); diff --git a/src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationService.cs b/src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationService.cs index 1548d3a4..c3c2bf59 100644 --- a/src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationService.cs +++ b/src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationService.cs @@ -146,49 +146,33 @@ public sealed class OpenIddictClientSystemIntegrationService cancellationToken.ThrowIfCancellationRequested(); - var scope = _provider.CreateScope(); + await using var scope = _provider.CreateAsyncScope(); - try - { - var dispatcher = scope.ServiceProvider.GetRequiredService(); - var factory = scope.ServiceProvider.GetRequiredService(); - - // Create a client transaction and store the specified instance so - // it can be retrieved by the event handlers that need to access it. - var transaction = await factory.CreateTransactionAsync(); - transaction.SetProperty(typeof(TProperty).FullName!, property); + var dispatcher = scope.ServiceProvider.GetRequiredService(); + var factory = scope.ServiceProvider.GetRequiredService(); - var context = new ProcessRequestContext(transaction) - { - CancellationToken = cancellationToken - }; + // Create a client transaction and store the specified instance so + // it can be retrieved by the event handlers that need to access it. + var transaction = await factory.CreateTransactionAsync(); + transaction.SetProperty(typeof(TProperty).FullName!, property); - await dispatcher.DispatchAsync(context); + var context = new ProcessRequestContext(transaction) + { + CancellationToken = cancellationToken + }; - if (context.IsRejected) - { - await dispatcher.DispatchAsync(new ProcessErrorContext(transaction) - { - CancellationToken = cancellationToken, - Error = context.Error ?? Errors.InvalidRequest, - ErrorDescription = context.ErrorDescription, - ErrorUri = context.ErrorUri, - Response = new OpenIddictResponse() - }); - } - } + await dispatcher.DispatchAsync(context); - finally + if (context.IsRejected) { - if (scope is IAsyncDisposable disposable) - { - await disposable.DisposeAsync(); - } - - else + await dispatcher.DispatchAsync(new ProcessErrorContext(transaction) { - scope.Dispose(); - } + CancellationToken = cancellationToken, + Error = context.Error ?? Errors.InvalidRequest, + ErrorDescription = context.ErrorDescription, + ErrorUri = context.ErrorUri, + Response = new OpenIddictResponse() + }); } } diff --git a/src/OpenIddict.Client/OpenIddictClientService.cs b/src/OpenIddict.Client/OpenIddictClientService.cs index d0ebfcaf..5af6b082 100644 --- a/src/OpenIddict.Client/OpenIddictClientService.cs +++ b/src/OpenIddict.Client/OpenIddictClientService.cs @@ -282,77 +282,59 @@ public class OpenIddictClientService // Note: this service is registered as a singleton service. As such, it cannot // directly depend on scoped services like the validation provider. To work around // this limitation, a scope is manually created for each method to this service. - var scope = _provider.CreateScope(); + await using var scope = _provider.CreateAsyncScope(); - // Note: a try/finally block is deliberately used here to ensure the service scope - // can be disposed of asynchronously if it implements IAsyncDisposable. - try - { - var dispatcher = scope.ServiceProvider.GetRequiredService(); - var factory = scope.ServiceProvider.GetRequiredService(); - - var transaction = await factory.CreateTransactionAsync(); - - var context = new ProcessAuthenticationContext(transaction) - { - CancellationToken = request.CancellationToken, - Nonce = request.Nonce - }; + var dispatcher = scope.ServiceProvider.GetRequiredService(); + var factory = scope.ServiceProvider.GetRequiredService(); - if (request.Properties is { Count: > 0 }) - { - foreach (var property in request.Properties) - { - context.Properties[property.Key] = property.Value; - } - } + var transaction = await factory.CreateTransactionAsync(); - await dispatcher.DispatchAsync(context); + var context = new ProcessAuthenticationContext(transaction) + { + CancellationToken = request.CancellationToken, + Nonce = request.Nonce + }; - if (context.IsRejected) + if (request.Properties is { Count: > 0 }) + { + foreach (var property in request.Properties) { - throw new ProtocolException( - SR.FormatID0374(context.Error, context.ErrorDescription, context.ErrorUri), - context.Error, context.ErrorDescription, context.ErrorUri); + context.Properties[property.Key] = property.Value; } + } - else - { - Debug.Assert(context.Registration.Issuer is { IsAbsoluteUri: true }, SR.GetResourceString(SR.ID4013)); + await dispatcher.DispatchAsync(context); - return new() - { - AuthorizationCode = context.AuthorizationCode, - AuthorizationResponse = context.Request is not null ? new(context.Request.GetParameters()) : new(), - BackchannelAccessToken = context.BackchannelAccessToken, - BackchannelAccessTokenExpirationDate = context.BackchannelAccessTokenExpirationDate, - BackchannelIdentityToken = context.BackchannelIdentityToken, - BackchannelIdentityTokenPrincipal = context.BackchannelIdentityTokenPrincipal, - FrontchannelAccessToken = context.FrontchannelAccessToken, - FrontchannelAccessTokenExpirationDate = context.FrontchannelAccessTokenExpirationDate, - FrontchannelIdentityToken = context.FrontchannelIdentityToken, - FrontchannelIdentityTokenPrincipal = context.FrontchannelIdentityTokenPrincipal, - Principal = context.MergedPrincipal, - Properties = context.Properties, - RefreshToken = context.RefreshToken, - StateTokenPrincipal = context.StateTokenPrincipal, - TokenResponse = context.TokenResponse ?? new(), - UserInfoTokenPrincipal = context.UserInfoTokenPrincipal - }; - } + if (context.IsRejected) + { + throw new ProtocolException( + SR.FormatID0374(context.Error, context.ErrorDescription, context.ErrorUri), + context.Error, context.ErrorDescription, context.ErrorUri); } - finally + else { - if (scope is IAsyncDisposable disposable) - { - await disposable.DisposeAsync(); - } + Debug.Assert(context.Registration.Issuer is { IsAbsoluteUri: true }, SR.GetResourceString(SR.ID4013)); - else + return new() { - scope.Dispose(); - } + AuthorizationCode = context.AuthorizationCode, + AuthorizationResponse = context.Request is not null ? new(context.Request.GetParameters()) : new(), + BackchannelAccessToken = context.BackchannelAccessToken, + BackchannelAccessTokenExpirationDate = context.BackchannelAccessTokenExpirationDate, + BackchannelIdentityToken = context.BackchannelIdentityToken, + BackchannelIdentityTokenPrincipal = context.BackchannelIdentityTokenPrincipal, + FrontchannelAccessToken = context.FrontchannelAccessToken, + FrontchannelAccessTokenExpirationDate = context.FrontchannelAccessTokenExpirationDate, + FrontchannelIdentityToken = context.FrontchannelIdentityToken, + FrontchannelIdentityTokenPrincipal = context.FrontchannelIdentityTokenPrincipal, + Principal = context.MergedPrincipal, + Properties = context.Properties, + RefreshToken = context.RefreshToken, + StateTokenPrincipal = context.StateTokenPrincipal, + TokenResponse = context.TokenResponse ?? new(), + UserInfoTokenPrincipal = context.UserInfoTokenPrincipal + }; } } @@ -373,80 +355,62 @@ public class OpenIddictClientService // Note: this service is registered as a singleton service. As such, it cannot // directly depend on scoped services like the validation provider. To work around // this limitation, a scope is manually created for each method to this service. - var scope = _provider.CreateScope(); - - // Note: a try/finally block is deliberately used here to ensure the service scope - // can be disposed of asynchronously if it implements IAsyncDisposable. - try - { - var dispatcher = scope.ServiceProvider.GetRequiredService(); - var factory = scope.ServiceProvider.GetRequiredService(); - - var transaction = await factory.CreateTransactionAsync(); - - var context = new ProcessChallengeContext(transaction) - { - CancellationToken = request.CancellationToken, - CodeChallengeMethod = request.CodeChallengeMethod, - GrantType = request.GrantType, - IdentityTokenHint = request.IdentityTokenHint, - Issuer = request.Issuer, - LoginHint = request.LoginHint, - Principal = new ClaimsPrincipal(new ClaimsIdentity()), - ProviderName = request.ProviderName, - RegistrationId = request.RegistrationId, - Request = request.AdditionalAuthorizationRequestParameters - is Dictionary parameters ? new(parameters) : new(), - ResponseMode = request.ResponseMode, - ResponseType = request.ResponseType - }; - - if (request.Scopes is { Count: > 0 }) - { - context.Scopes.UnionWith(request.Scopes); - } - - if (request.Properties is { Count: > 0 }) - { - foreach (var property in request.Properties) - { - context.Properties[property.Key] = property.Value; - } - } + await using var scope = _provider.CreateAsyncScope(); + + var dispatcher = scope.ServiceProvider.GetRequiredService(); + var factory = scope.ServiceProvider.GetRequiredService(); + + var transaction = await factory.CreateTransactionAsync(); + + var context = new ProcessChallengeContext(transaction) + { + CancellationToken = request.CancellationToken, + CodeChallengeMethod = request.CodeChallengeMethod, + GrantType = request.GrantType, + IdentityTokenHint = request.IdentityTokenHint, + Issuer = request.Issuer, + LoginHint = request.LoginHint, + Principal = new ClaimsPrincipal(new ClaimsIdentity()), + ProviderName = request.ProviderName, + RegistrationId = request.RegistrationId, + Request = request.AdditionalAuthorizationRequestParameters + is Dictionary parameters ? new(parameters) : new(), + ResponseMode = request.ResponseMode, + ResponseType = request.ResponseType + }; - await dispatcher.DispatchAsync(context); + if (request.Scopes is { Count: > 0 }) + { + context.Scopes.UnionWith(request.Scopes); + } - if (context.IsRejected) + if (request.Properties is { Count: > 0 }) + { + foreach (var property in request.Properties) { - throw new ProtocolException( - SR.FormatID0374(context.Error, context.ErrorDescription, context.ErrorUri), - context.Error, context.ErrorDescription, context.ErrorUri); + context.Properties[property.Key] = property.Value; } + } - if (string.IsNullOrEmpty(context.Nonce)) - { - throw new InvalidOperationException(SR.GetResourceString(SR.ID0352)); - } + await dispatcher.DispatchAsync(context); - return new() - { - Nonce = context.Nonce, - Properties = context.Properties - }; + if (context.IsRejected) + { + throw new ProtocolException( + SR.FormatID0374(context.Error, context.ErrorDescription, context.ErrorUri), + context.Error, context.ErrorDescription, context.ErrorUri); } - finally + if (string.IsNullOrEmpty(context.Nonce)) { - if (scope is IAsyncDisposable disposable) - { - await disposable.DisposeAsync(); - } - - else - { - scope.Dispose(); - } + throw new InvalidOperationException(SR.GetResourceString(SR.ID0352)); } + + return new() + { + Nonce = context.Nonce, + Properties = context.Properties + }; } /// @@ -467,79 +431,61 @@ public class OpenIddictClientService // Note: this service is registered as a singleton service. As such, it cannot // directly depend on scoped services like the validation provider. To work around // this limitation, a scope is manually created for each method to this service. - var scope = _provider.CreateScope(); + await using var scope = _provider.CreateAsyncScope(); - // Note: a try/finally block is deliberately used here to ensure the service scope - // can be disposed of asynchronously if it implements IAsyncDisposable. - try - { - var dispatcher = scope.ServiceProvider.GetRequiredService(); - var factory = scope.ServiceProvider.GetRequiredService(); - var transaction = await factory.CreateTransactionAsync(); - - var context = new ProcessAuthenticationContext(transaction) - { - CancellationToken = request.CancellationToken, - GrantType = GrantTypes.ClientCredentials, - Issuer = request.Issuer, - ProviderName = request.ProviderName, - RegistrationId = request.RegistrationId, - TokenRequest = request.AdditionalTokenRequestParameters - is Dictionary parameters ? new(parameters) : new(), - }; + var dispatcher = scope.ServiceProvider.GetRequiredService(); + var factory = scope.ServiceProvider.GetRequiredService(); + var transaction = await factory.CreateTransactionAsync(); - if (request.Scopes is { Count: > 0 }) - { - context.Scopes.UnionWith(request.Scopes); - } - - if (request.Properties is { Count: > 0 }) - { - foreach (var property in request.Properties) - { - context.Properties[property.Key] = property.Value; - } - } + var context = new ProcessAuthenticationContext(transaction) + { + CancellationToken = request.CancellationToken, + GrantType = GrantTypes.ClientCredentials, + Issuer = request.Issuer, + ProviderName = request.ProviderName, + RegistrationId = request.RegistrationId, + TokenRequest = request.AdditionalTokenRequestParameters + is Dictionary parameters ? new(parameters) : new(), + }; - await dispatcher.DispatchAsync(context); + if (request.Scopes is { Count: > 0 }) + { + context.Scopes.UnionWith(request.Scopes); + } - if (context.IsRejected) + if (request.Properties is { Count: > 0 }) + { + foreach (var property in request.Properties) { - throw new ProtocolException( - SR.FormatID0435(context.Error, context.ErrorDescription, context.ErrorUri), - context.Error, context.ErrorDescription, context.ErrorUri); + context.Properties[property.Key] = property.Value; } + } - Debug.Assert(context.Registration.Issuer is { IsAbsoluteUri: true }, SR.GetResourceString(SR.ID4013)); - Debug.Assert(context.TokenResponse is not null, SR.GetResourceString(SR.ID4007)); + await dispatcher.DispatchAsync(context); - return new() - { - AccessToken = context.BackchannelAccessToken!, - AccessTokenExpirationDate = context.BackchannelAccessTokenExpirationDate, - IdentityToken = context.BackchannelIdentityToken, - IdentityTokenPrincipal = context.BackchannelIdentityTokenPrincipal, - Principal = context.MergedPrincipal, - Properties = context.Properties, - RefreshToken = context.RefreshToken, - TokenResponse = context.TokenResponse, - UserInfoToken = context.UserInfoToken, - UserInfoTokenPrincipal = context.UserInfoTokenPrincipal - }; + if (context.IsRejected) + { + throw new ProtocolException( + SR.FormatID0435(context.Error, context.ErrorDescription, context.ErrorUri), + context.Error, context.ErrorDescription, context.ErrorUri); } - finally - { - if (scope is IAsyncDisposable disposable) - { - await disposable.DisposeAsync(); - } + Debug.Assert(context.Registration.Issuer is { IsAbsoluteUri: true }, SR.GetResourceString(SR.ID4013)); + Debug.Assert(context.TokenResponse is not null, SR.GetResourceString(SR.ID4007)); - else - { - scope.Dispose(); - } - } + return new() + { + AccessToken = context.BackchannelAccessToken!, + AccessTokenExpirationDate = context.BackchannelAccessTokenExpirationDate, + IdentityToken = context.BackchannelIdentityToken, + IdentityTokenPrincipal = context.BackchannelIdentityTokenPrincipal, + Principal = context.MergedPrincipal, + Properties = context.Properties, + RefreshToken = context.RefreshToken, + TokenResponse = context.TokenResponse, + UserInfoToken = context.UserInfoToken, + UserInfoTokenPrincipal = context.UserInfoTokenPrincipal + }; } /// @@ -568,80 +514,62 @@ public class OpenIddictClientService // Note: this service is registered as a singleton service. As such, it cannot // directly depend on scoped services like the validation provider. To work around // this limitation, a scope is manually created for each method to this service. - var scope = _provider.CreateScope(); - - // Note: a try/finally block is deliberately used here to ensure the service scope - // can be disposed of asynchronously if it implements IAsyncDisposable. - try - { - var dispatcher = scope.ServiceProvider.GetRequiredService(); - var factory = scope.ServiceProvider.GetRequiredService(); - var transaction = await factory.CreateTransactionAsync(); - - var context = new ProcessAuthenticationContext(transaction) - { - CancellationToken = request.CancellationToken, - DisableUserInfoRetrieval = request.DisableUserInfo, - DisableUserInfoValidation = request.DisableUserInfo, - GrantType = request.GrantType, - ProviderName = request.ProviderName, - RegistrationId = request.RegistrationId, - TokenRequest = request.AdditionalTokenRequestParameters - is Dictionary parameters ? new(parameters) : new() - }; - - if (request.Scopes is { Count: > 0 }) - { - context.Scopes.UnionWith(request.Scopes); - } - - if (request.Properties is { Count: > 0 }) - { - foreach (var property in request.Properties) - { - context.Properties[property.Key] = property.Value; - } - } + await using var scope = _provider.CreateAsyncScope(); + + var dispatcher = scope.ServiceProvider.GetRequiredService(); + var factory = scope.ServiceProvider.GetRequiredService(); + var transaction = await factory.CreateTransactionAsync(); + + var context = new ProcessAuthenticationContext(transaction) + { + CancellationToken = request.CancellationToken, + DisableUserInfoRetrieval = request.DisableUserInfo, + DisableUserInfoValidation = request.DisableUserInfo, + GrantType = request.GrantType, + ProviderName = request.ProviderName, + RegistrationId = request.RegistrationId, + TokenRequest = request.AdditionalTokenRequestParameters + is Dictionary parameters ? new(parameters) : new() + }; - await dispatcher.DispatchAsync(context); + if (request.Scopes is { Count: > 0 }) + { + context.Scopes.UnionWith(request.Scopes); + } - if (context.IsRejected) + if (request.Properties is { Count: > 0 }) + { + foreach (var property in request.Properties) { - throw new ProtocolException( - SR.FormatID0374(context.Error, context.ErrorDescription, context.ErrorUri), - context.Error, context.ErrorDescription, context.ErrorUri); + context.Properties[property.Key] = property.Value; } + } - Debug.Assert(context.Registration.Issuer is { IsAbsoluteUri: true }, SR.GetResourceString(SR.ID4013)); - Debug.Assert(context.TokenResponse is not null, SR.GetResourceString(SR.ID4007)); + await dispatcher.DispatchAsync(context); - return new() - { - AccessToken = context.BackchannelAccessToken!, - AccessTokenExpirationDate = context.BackchannelAccessTokenExpirationDate, - IdentityToken = context.BackchannelIdentityToken, - IdentityTokenPrincipal = context.BackchannelIdentityTokenPrincipal, - Principal = context.MergedPrincipal, - Properties = context.Properties, - RefreshToken = context.RefreshToken, - TokenResponse = context.TokenResponse, - UserInfoToken = context.UserInfoToken, - UserInfoTokenPrincipal = context.UserInfoTokenPrincipal - }; + if (context.IsRejected) + { + throw new ProtocolException( + SR.FormatID0374(context.Error, context.ErrorDescription, context.ErrorUri), + context.Error, context.ErrorDescription, context.ErrorUri); } - finally - { - if (scope is IAsyncDisposable disposable) - { - await disposable.DisposeAsync(); - } + Debug.Assert(context.Registration.Issuer is { IsAbsoluteUri: true }, SR.GetResourceString(SR.ID4013)); + Debug.Assert(context.TokenResponse is not null, SR.GetResourceString(SR.ID4007)); - else - { - scope.Dispose(); - } - } + return new() + { + AccessToken = context.BackchannelAccessToken!, + AccessTokenExpirationDate = context.BackchannelAccessTokenExpirationDate, + IdentityToken = context.BackchannelIdentityToken, + IdentityTokenPrincipal = context.BackchannelIdentityTokenPrincipal, + Principal = context.MergedPrincipal, + Properties = context.Properties, + RefreshToken = context.RefreshToken, + TokenResponse = context.TokenResponse, + UserInfoToken = context.UserInfoToken, + UserInfoTokenPrincipal = context.UserInfoTokenPrincipal + }; } /// @@ -670,84 +598,66 @@ public class OpenIddictClientService // Note: this service is registered as a singleton service. As such, it cannot // directly depend on scoped services like the validation provider. To work around // this limitation, a scope is manually created for each method to this service. - var scope = _provider.CreateScope(); + await using var scope = _provider.CreateAsyncScope(); - // Note: a try/finally block is deliberately used here to ensure the service scope - // can be disposed of asynchronously if it implements IAsyncDisposable. - try - { - var dispatcher = scope.ServiceProvider.GetRequiredService(); - var factory = scope.ServiceProvider.GetRequiredService(); + var dispatcher = scope.ServiceProvider.GetRequiredService(); + var factory = scope.ServiceProvider.GetRequiredService(); - var transaction = await factory.CreateTransactionAsync(); + var transaction = await factory.CreateTransactionAsync(); - var context = new ProcessAuthenticationContext(transaction) - { - CancellationToken = source.Token, - DeviceCode = request.DeviceCode, - DisableUserInfoRetrieval = request.DisableUserInfo, - DisableUserInfoValidation = request.DisableUserInfo, - GrantType = GrantTypes.DeviceCode, - Issuer = request.Issuer, - ProviderName = request.ProviderName, - RegistrationId = request.RegistrationId, - TokenRequest = request.AdditionalTokenRequestParameters - is Dictionary parameters ? new(parameters) : new(), - }; + var context = new ProcessAuthenticationContext(transaction) + { + CancellationToken = source.Token, + DeviceCode = request.DeviceCode, + DisableUserInfoRetrieval = request.DisableUserInfo, + DisableUserInfoValidation = request.DisableUserInfo, + GrantType = GrantTypes.DeviceCode, + Issuer = request.Issuer, + ProviderName = request.ProviderName, + RegistrationId = request.RegistrationId, + TokenRequest = request.AdditionalTokenRequestParameters + is Dictionary parameters ? new(parameters) : new(), + }; - if (request.Scopes is { Count: > 0 }) - { - context.Scopes.UnionWith(request.Scopes); - } + if (request.Scopes is { Count: > 0 }) + { + context.Scopes.UnionWith(request.Scopes); + } - if (request.Properties is { Count: > 0 }) + if (request.Properties is { Count: > 0 }) + { + foreach (var property in request.Properties) { - foreach (var property in request.Properties) - { - context.Properties[property.Key] = property.Value; - } + context.Properties[property.Key] = property.Value; } + } - await dispatcher.DispatchAsync(context); - - if (context.IsRejected) - { - throw new ProtocolException( - SR.FormatID0374(context.Error, context.ErrorDescription, context.ErrorUri), - context.Error, context.ErrorDescription, context.ErrorUri); - } + await dispatcher.DispatchAsync(context); - else - { - Debug.Assert(context.Registration.Issuer is { IsAbsoluteUri: true }, SR.GetResourceString(SR.ID4013)); - - return new() - { - AccessToken = context.BackchannelAccessToken!, - AccessTokenExpirationDate = context.BackchannelAccessTokenExpirationDate, - IdentityToken = context.BackchannelIdentityToken, - IdentityTokenPrincipal = context.BackchannelIdentityTokenPrincipal, - Principal = context.MergedPrincipal, - Properties = context.Properties, - RefreshToken = context.RefreshToken, - TokenResponse = context.TokenResponse ?? new(), - UserInfoToken = context.UserInfoToken, - UserInfoTokenPrincipal = context.UserInfoTokenPrincipal - }; - } + if (context.IsRejected) + { + throw new ProtocolException( + SR.FormatID0374(context.Error, context.ErrorDescription, context.ErrorUri), + context.Error, context.ErrorDescription, context.ErrorUri); } - finally + else { - if (scope is IAsyncDisposable disposable) - { - await disposable.DisposeAsync(); - } + Debug.Assert(context.Registration.Issuer is { IsAbsoluteUri: true }, SR.GetResourceString(SR.ID4013)); - else + return new() { - scope.Dispose(); - } + AccessToken = context.BackchannelAccessToken!, + AccessTokenExpirationDate = context.BackchannelAccessTokenExpirationDate, + IdentityToken = context.BackchannelIdentityToken, + IdentityTokenPrincipal = context.BackchannelIdentityTokenPrincipal, + Principal = context.MergedPrincipal, + Properties = context.Properties, + RefreshToken = context.RefreshToken, + TokenResponse = context.TokenResponse ?? new(), + UserInfoToken = context.UserInfoToken, + UserInfoTokenPrincipal = context.UserInfoTokenPrincipal + }; } } @@ -786,78 +696,60 @@ public class OpenIddictClientService // Note: this service is registered as a singleton service. As such, it cannot // directly depend on scoped services like the validation provider. To work around // this limitation, a scope is manually created for each method to this service. - var scope = _provider.CreateScope(); + await using var scope = _provider.CreateAsyncScope(); - // Note: a try/finally block is deliberately used here to ensure the service scope - // can be disposed of asynchronously if it implements IAsyncDisposable. - try - { - var dispatcher = scope.ServiceProvider.GetRequiredService(); - var factory = scope.ServiceProvider.GetRequiredService(); + var dispatcher = scope.ServiceProvider.GetRequiredService(); + var factory = scope.ServiceProvider.GetRequiredService(); - var transaction = await factory.CreateTransactionAsync(); + var transaction = await factory.CreateTransactionAsync(); - var context = new ProcessChallengeContext(transaction) - { - CancellationToken = request.CancellationToken, - DeviceAuthorizationRequest = request.AdditionalDeviceAuthorizationRequestParameters - is Dictionary parameters ? new(parameters) : new(), - GrantType = GrantTypes.DeviceCode, - Issuer = request.Issuer, - Principal = new ClaimsPrincipal(new ClaimsIdentity()), - ProviderName = request.ProviderName, - RegistrationId = request.RegistrationId, - Request = new() - }; + var context = new ProcessChallengeContext(transaction) + { + CancellationToken = request.CancellationToken, + DeviceAuthorizationRequest = request.AdditionalDeviceAuthorizationRequestParameters + is Dictionary parameters ? new(parameters) : new(), + GrantType = GrantTypes.DeviceCode, + Issuer = request.Issuer, + Principal = new ClaimsPrincipal(new ClaimsIdentity()), + ProviderName = request.ProviderName, + RegistrationId = request.RegistrationId, + Request = new() + }; - if (request.Scopes is { Count: > 0 }) - { - context.Scopes.UnionWith(request.Scopes); - } + if (request.Scopes is { Count: > 0 }) + { + context.Scopes.UnionWith(request.Scopes); + } - if (request.Properties is { Count: > 0 }) + if (request.Properties is { Count: > 0 }) + { + foreach (var property in request.Properties) { - foreach (var property in request.Properties) - { - context.Properties[property.Key] = property.Value; - } + context.Properties[property.Key] = property.Value; } + } - await dispatcher.DispatchAsync(context); - - if (context.IsRejected) - { - throw new ProtocolException( - SR.FormatID0374(context.Error, context.ErrorDescription, context.ErrorUri), - context.Error, context.ErrorDescription, context.ErrorUri); - } + await dispatcher.DispatchAsync(context); - return new() - { - DeviceAuthorizationResponse = context.DeviceAuthorizationResponse ?? new(), - DeviceCode = context.DeviceCode!, - ExpiresIn = TimeSpan.FromSeconds((double) context.DeviceAuthorizationResponse?.ExpiresIn!), - Interval = TimeSpan.FromSeconds((long?) context.DeviceAuthorizationResponse[Parameters.Interval] ?? 5), - Properties = context.Properties, - UserCode = context.UserCode!, - VerificationUri = new Uri(context.DeviceAuthorizationResponse?.VerificationUri!, UriKind.Absolute), - VerificationUriComplete = context.DeviceAuthorizationResponse?.VerificationUriComplete - is string value ? new Uri(value, UriKind.Absolute) : null - }; + if (context.IsRejected) + { + throw new ProtocolException( + SR.FormatID0374(context.Error, context.ErrorDescription, context.ErrorUri), + context.Error, context.ErrorDescription, context.ErrorUri); } - finally + return new() { - if (scope is IAsyncDisposable disposable) - { - await disposable.DisposeAsync(); - } - - else - { - scope.Dispose(); - } - } + DeviceAuthorizationResponse = context.DeviceAuthorizationResponse ?? new(), + DeviceCode = context.DeviceCode!, + ExpiresIn = TimeSpan.FromSeconds((double) context.DeviceAuthorizationResponse?.ExpiresIn!), + Interval = TimeSpan.FromSeconds((long?) context.DeviceAuthorizationResponse[Parameters.Interval] ?? 5), + Properties = context.Properties, + UserCode = context.UserCode!, + VerificationUri = new Uri(context.DeviceAuthorizationResponse?.VerificationUri!, UriKind.Absolute), + VerificationUriComplete = context.DeviceAuthorizationResponse?.VerificationUriComplete + is string value ? new Uri(value, UriKind.Absolute) : null + }; } /// @@ -877,83 +769,65 @@ public class OpenIddictClientService // Note: this service is registered as a singleton service. As such, it cannot // directly depend on scoped services like the validation provider. To work around // this limitation, a scope is manually created for each method to this service. - var scope = _provider.CreateScope(); - - // Note: a try/finally block is deliberately used here to ensure the service scope - // can be disposed of asynchronously if it implements IAsyncDisposable. - try - { - var dispatcher = scope.ServiceProvider.GetRequiredService(); - var factory = scope.ServiceProvider.GetRequiredService(); - var transaction = await factory.CreateTransactionAsync(); - - var context = new ProcessAuthenticationContext(transaction) - { - CancellationToken = request.CancellationToken, - DisableUserInfoRetrieval = request.DisableUserInfo, - DisableUserInfoValidation = request.DisableUserInfo, - GrantType = GrantTypes.Password, - Issuer = request.Issuer, - Password = request.Password, - ProviderName = request.ProviderName, - RegistrationId = request.RegistrationId, - TokenRequest = request.AdditionalTokenRequestParameters - is Dictionary parameters ? new(parameters) : new(), - Username = request.Username - }; - - if (request.Scopes is { Count: > 0 }) - { - context.Scopes.UnionWith(request.Scopes); - } - - if (request.Properties is { Count: > 0 }) - { - foreach (var property in request.Properties) - { - context.Properties[property.Key] = property.Value; - } - } + await using var scope = _provider.CreateAsyncScope(); + + var dispatcher = scope.ServiceProvider.GetRequiredService(); + var factory = scope.ServiceProvider.GetRequiredService(); + var transaction = await factory.CreateTransactionAsync(); + + var context = new ProcessAuthenticationContext(transaction) + { + CancellationToken = request.CancellationToken, + DisableUserInfoRetrieval = request.DisableUserInfo, + DisableUserInfoValidation = request.DisableUserInfo, + GrantType = GrantTypes.Password, + Issuer = request.Issuer, + Password = request.Password, + ProviderName = request.ProviderName, + RegistrationId = request.RegistrationId, + TokenRequest = request.AdditionalTokenRequestParameters + is Dictionary parameters ? new(parameters) : new(), + Username = request.Username + }; - await dispatcher.DispatchAsync(context); + if (request.Scopes is { Count: > 0 }) + { + context.Scopes.UnionWith(request.Scopes); + } - if (context.IsRejected) + if (request.Properties is { Count: > 0 }) + { + foreach (var property in request.Properties) { - throw new ProtocolException( - SR.FormatID0374(context.Error, context.ErrorDescription, context.ErrorUri), - context.Error, context.ErrorDescription, context.ErrorUri); + context.Properties[property.Key] = property.Value; } + } - Debug.Assert(context.Registration.Issuer is { IsAbsoluteUri: true }, SR.GetResourceString(SR.ID4013)); - Debug.Assert(context.TokenResponse is not null, SR.GetResourceString(SR.ID4007)); + await dispatcher.DispatchAsync(context); - return new() - { - AccessToken = context.BackchannelAccessToken!, - AccessTokenExpirationDate = context.BackchannelAccessTokenExpirationDate, - IdentityToken = context.BackchannelIdentityToken, - IdentityTokenPrincipal = context.BackchannelIdentityTokenPrincipal, - Principal = context.MergedPrincipal, - Properties = context.Properties, - RefreshToken = context.RefreshToken, - TokenResponse = context.TokenResponse, - UserInfoToken = context.UserInfoToken, - UserInfoTokenPrincipal = context.UserInfoTokenPrincipal - }; + if (context.IsRejected) + { + throw new ProtocolException( + SR.FormatID0374(context.Error, context.ErrorDescription, context.ErrorUri), + context.Error, context.ErrorDescription, context.ErrorUri); } - finally - { - if (scope is IAsyncDisposable disposable) - { - await disposable.DisposeAsync(); - } + Debug.Assert(context.Registration.Issuer is { IsAbsoluteUri: true }, SR.GetResourceString(SR.ID4013)); + Debug.Assert(context.TokenResponse is not null, SR.GetResourceString(SR.ID4007)); - else - { - scope.Dispose(); - } - } + return new() + { + AccessToken = context.BackchannelAccessToken!, + AccessTokenExpirationDate = context.BackchannelAccessTokenExpirationDate, + IdentityToken = context.BackchannelIdentityToken, + IdentityTokenPrincipal = context.BackchannelIdentityTokenPrincipal, + Principal = context.MergedPrincipal, + Properties = context.Properties, + RefreshToken = context.RefreshToken, + TokenResponse = context.TokenResponse, + UserInfoToken = context.UserInfoToken, + UserInfoTokenPrincipal = context.UserInfoTokenPrincipal + }; } /// @@ -974,82 +848,64 @@ public class OpenIddictClientService // Note: this service is registered as a singleton service. As such, it cannot // directly depend on scoped services like the validation provider. To work around // this limitation, a scope is manually created for each method to this service. - var scope = _provider.CreateScope(); - - // Note: a try/finally block is deliberately used here to ensure the service scope - // can be disposed of asynchronously if it implements IAsyncDisposable. - try - { - var dispatcher = scope.ServiceProvider.GetRequiredService(); - var factory = scope.ServiceProvider.GetRequiredService(); - var transaction = await factory.CreateTransactionAsync(); - - var context = new ProcessAuthenticationContext(transaction) - { - CancellationToken = request.CancellationToken, - DisableUserInfoRetrieval = request.DisableUserInfo, - DisableUserInfoValidation = request.DisableUserInfo, - GrantType = GrantTypes.RefreshToken, - Issuer = request.Issuer, - ProviderName = request.ProviderName, - RefreshToken = request.RefreshToken, - RegistrationId = request.RegistrationId, - TokenRequest = request.AdditionalTokenRequestParameters - is Dictionary parameters ? new(parameters) : new(), - }; - - if (request.Scopes is { Count: > 0 }) - { - context.Scopes.UnionWith(request.Scopes); - } - - if (request.Properties is { Count: > 0 }) - { - foreach (var property in request.Properties) - { - context.Properties[property.Key] = property.Value; - } - } + await using var scope = _provider.CreateAsyncScope(); + + var dispatcher = scope.ServiceProvider.GetRequiredService(); + var factory = scope.ServiceProvider.GetRequiredService(); + var transaction = await factory.CreateTransactionAsync(); + + var context = new ProcessAuthenticationContext(transaction) + { + CancellationToken = request.CancellationToken, + DisableUserInfoRetrieval = request.DisableUserInfo, + DisableUserInfoValidation = request.DisableUserInfo, + GrantType = GrantTypes.RefreshToken, + Issuer = request.Issuer, + ProviderName = request.ProviderName, + RefreshToken = request.RefreshToken, + RegistrationId = request.RegistrationId, + TokenRequest = request.AdditionalTokenRequestParameters + is Dictionary parameters ? new(parameters) : new(), + }; - await dispatcher.DispatchAsync(context); + if (request.Scopes is { Count: > 0 }) + { + context.Scopes.UnionWith(request.Scopes); + } - if (context.IsRejected) + if (request.Properties is { Count: > 0 }) + { + foreach (var property in request.Properties) { - throw new ProtocolException( - SR.FormatID0319(context.Error, context.ErrorDescription, context.ErrorUri), - context.Error, context.ErrorDescription, context.ErrorUri); + context.Properties[property.Key] = property.Value; } + } - Debug.Assert(context.Registration.Issuer is { IsAbsoluteUri: true }, SR.GetResourceString(SR.ID4013)); - Debug.Assert(context.TokenResponse is not null, SR.GetResourceString(SR.ID4007)); + await dispatcher.DispatchAsync(context); - return new() - { - AccessToken = context.BackchannelAccessToken!, - AccessTokenExpirationDate = context.BackchannelAccessTokenExpirationDate, - IdentityToken = context.BackchannelIdentityToken, - IdentityTokenPrincipal = context.BackchannelIdentityTokenPrincipal, - Principal = context.MergedPrincipal, - Properties = context.Properties, - RefreshToken = context.RefreshToken, - TokenResponse = context.TokenResponse, - UserInfoToken = context.UserInfoToken, - UserInfoTokenPrincipal = context.UserInfoTokenPrincipal - }; + if (context.IsRejected) + { + throw new ProtocolException( + SR.FormatID0319(context.Error, context.ErrorDescription, context.ErrorUri), + context.Error, context.ErrorDescription, context.ErrorUri); } - finally - { - if (scope is IAsyncDisposable disposable) - { - await disposable.DisposeAsync(); - } + Debug.Assert(context.Registration.Issuer is { IsAbsoluteUri: true }, SR.GetResourceString(SR.ID4013)); + Debug.Assert(context.TokenResponse is not null, SR.GetResourceString(SR.ID4007)); - else - { - scope.Dispose(); - } - } + return new() + { + AccessToken = context.BackchannelAccessToken!, + AccessTokenExpirationDate = context.BackchannelAccessTokenExpirationDate, + IdentityToken = context.BackchannelIdentityToken, + IdentityTokenPrincipal = context.BackchannelIdentityTokenPrincipal, + Principal = context.MergedPrincipal, + Properties = context.Properties, + RefreshToken = context.RefreshToken, + TokenResponse = context.TokenResponse, + UserInfoToken = context.UserInfoToken, + UserInfoTokenPrincipal = context.UserInfoTokenPrincipal + }; } /// @@ -1069,68 +925,50 @@ public class OpenIddictClientService // Note: this service is registered as a singleton service. As such, it cannot // directly depend on scoped services like the validation provider. To work around // this limitation, a scope is manually created for each method to this service. - var scope = _provider.CreateScope(); - - // Note: a try/finally block is deliberately used here to ensure the service scope - // can be disposed of asynchronously if it implements IAsyncDisposable. - try - { - var dispatcher = scope.ServiceProvider.GetRequiredService(); - var factory = scope.ServiceProvider.GetRequiredService(); - var transaction = await factory.CreateTransactionAsync(); - - var context = new ProcessIntrospectionContext(transaction) - { - CancellationToken = request.CancellationToken, - IntrospectionRequest = request.AdditionalIntrospectionRequestParameters - is Dictionary parameters ? new(parameters) : new(), - Issuer = request.Issuer, - ProviderName = request.ProviderName, - RegistrationId = request.RegistrationId, - Token = request.Token, - TokenTypeHint = request.TokenTypeHint - }; - - if (request.Properties is { Count: > 0 }) - { - foreach (var property in request.Properties) - { - context.Properties[property.Key] = property.Value; - } - } - - await dispatcher.DispatchAsync(context); + await using var scope = _provider.CreateAsyncScope(); + + var dispatcher = scope.ServiceProvider.GetRequiredService(); + var factory = scope.ServiceProvider.GetRequiredService(); + var transaction = await factory.CreateTransactionAsync(); + + var context = new ProcessIntrospectionContext(transaction) + { + CancellationToken = request.CancellationToken, + IntrospectionRequest = request.AdditionalIntrospectionRequestParameters + is Dictionary parameters ? new(parameters) : new(), + Issuer = request.Issuer, + ProviderName = request.ProviderName, + RegistrationId = request.RegistrationId, + Token = request.Token, + TokenTypeHint = request.TokenTypeHint + }; - if (context.IsRejected) + if (request.Properties is { Count: > 0 }) + { + foreach (var property in request.Properties) { - throw new ProtocolException( - SR.FormatID0428(context.Error, context.ErrorDescription, context.ErrorUri), - context.Error, context.ErrorDescription, context.ErrorUri); + context.Properties[property.Key] = property.Value; } + } - Debug.Assert(context.Registration.Issuer is { IsAbsoluteUri: true }, SR.GetResourceString(SR.ID4013)); - Debug.Assert(context.IntrospectionResponse is not null, SR.GetResourceString(SR.ID4007)); + await dispatcher.DispatchAsync(context); - return new() - { - IntrospectionResponse = context.IntrospectionResponse, - Principal = context.Principal!, - Properties = context.Properties - }; + if (context.IsRejected) + { + throw new ProtocolException( + SR.FormatID0428(context.Error, context.ErrorDescription, context.ErrorUri), + context.Error, context.ErrorDescription, context.ErrorUri); } - finally - { - if (scope is IAsyncDisposable disposable) - { - await disposable.DisposeAsync(); - } + Debug.Assert(context.Registration.Issuer is { IsAbsoluteUri: true }, SR.GetResourceString(SR.ID4013)); + Debug.Assert(context.IntrospectionResponse is not null, SR.GetResourceString(SR.ID4007)); - else - { - scope.Dispose(); - } - } + return new() + { + IntrospectionResponse = context.IntrospectionResponse, + Principal = context.Principal!, + Properties = context.Properties + }; } /// @@ -1150,67 +988,49 @@ public class OpenIddictClientService // Note: this service is registered as a singleton service. As such, it cannot // directly depend on scoped services like the validation provider. To work around // this limitation, a scope is manually created for each method to this service. - var scope = _provider.CreateScope(); - - // Note: a try/finally block is deliberately used here to ensure the service scope - // can be disposed of asynchronously if it implements IAsyncDisposable. - try - { - var dispatcher = scope.ServiceProvider.GetRequiredService(); - var factory = scope.ServiceProvider.GetRequiredService(); - var transaction = await factory.CreateTransactionAsync(); - - var context = new ProcessRevocationContext(transaction) - { - CancellationToken = request.CancellationToken, - Issuer = request.Issuer, - ProviderName = request.ProviderName, - RegistrationId = request.RegistrationId, - RevocationRequest = request.AdditionalRevocationRequestParameters - is Dictionary parameters ? new(parameters) : new(), - Token = request.Token, - TokenTypeHint = request.TokenTypeHint - }; - - if (request.Properties is { Count: > 0 }) - { - foreach (var property in request.Properties) - { - context.Properties[property.Key] = property.Value; - } - } - - await dispatcher.DispatchAsync(context); + await using var scope = _provider.CreateAsyncScope(); + + var dispatcher = scope.ServiceProvider.GetRequiredService(); + var factory = scope.ServiceProvider.GetRequiredService(); + var transaction = await factory.CreateTransactionAsync(); + + var context = new ProcessRevocationContext(transaction) + { + CancellationToken = request.CancellationToken, + Issuer = request.Issuer, + ProviderName = request.ProviderName, + RegistrationId = request.RegistrationId, + RevocationRequest = request.AdditionalRevocationRequestParameters + is Dictionary parameters ? new(parameters) : new(), + Token = request.Token, + TokenTypeHint = request.TokenTypeHint + }; - if (context.IsRejected) + if (request.Properties is { Count: > 0 }) + { + foreach (var property in request.Properties) { - throw new ProtocolException( - SR.FormatID0429(context.Error, context.ErrorDescription, context.ErrorUri), - context.Error, context.ErrorDescription, context.ErrorUri); + context.Properties[property.Key] = property.Value; } + } - Debug.Assert(context.Registration.Issuer is { IsAbsoluteUri: true }, SR.GetResourceString(SR.ID4013)); - Debug.Assert(context.RevocationResponse is not null, SR.GetResourceString(SR.ID4007)); + await dispatcher.DispatchAsync(context); - return new() - { - Properties = context.Properties, - RevocationResponse = context.RevocationResponse - }; + if (context.IsRejected) + { + throw new ProtocolException( + SR.FormatID0429(context.Error, context.ErrorDescription, context.ErrorUri), + context.Error, context.ErrorDescription, context.ErrorUri); } - finally - { - if (scope is IAsyncDisposable disposable) - { - await disposable.DisposeAsync(); - } + Debug.Assert(context.Registration.Issuer is { IsAbsoluteUri: true }, SR.GetResourceString(SR.ID4013)); + Debug.Assert(context.RevocationResponse is not null, SR.GetResourceString(SR.ID4007)); - else - { - scope.Dispose(); - } - } + return new() + { + Properties = context.Properties, + RevocationResponse = context.RevocationResponse + }; } /// @@ -1243,131 +1063,113 @@ public class OpenIddictClientService // Note: this service is registered as a singleton service. As such, it cannot // directly depend on scoped services like the validation provider. To work around // this limitation, a scope is manually created for each method to this service. - var scope = _provider.CreateScope(); + await using var scope = _provider.CreateAsyncScope(); - // Note: a try/finally block is deliberately used here to ensure the service scope - // can be disposed of asynchronously if it implements IAsyncDisposable. - try - { - var dispatcher = scope.ServiceProvider.GetRequiredService(); - var factory = scope.ServiceProvider.GetRequiredService(); - var transaction = await factory.CreateTransactionAsync(); + var dispatcher = scope.ServiceProvider.GetRequiredService(); + var factory = scope.ServiceProvider.GetRequiredService(); + var transaction = await factory.CreateTransactionAsync(); - var request = new OpenIddictRequest(); - request = await PrepareConfigurationRequestAsync(); - request = await ApplyConfigurationRequestAsync(); - var response = await ExtractConfigurationResponseAsync(); + var request = new OpenIddictRequest(); + request = await PrepareConfigurationRequestAsync(); + request = await ApplyConfigurationRequestAsync(); + var response = await ExtractConfigurationResponseAsync(); - return await HandleConfigurationResponseAsync() ?? - throw new InvalidOperationException(SR.GetResourceString(SR.ID0145)); + return await HandleConfigurationResponseAsync() ?? + throw new InvalidOperationException(SR.GetResourceString(SR.ID0145)); - async ValueTask PrepareConfigurationRequestAsync() + async ValueTask PrepareConfigurationRequestAsync() + { + var context = new PrepareConfigurationRequestContext(transaction) { - var context = new PrepareConfigurationRequestContext(transaction) - { - CancellationToken = cancellationToken, - RemoteUri = uri, - Registration = registration, - Request = request - }; - - await dispatcher.DispatchAsync(context); - - if (context.IsRejected) - { - throw new ProtocolException( - SR.FormatID0148(context.Error, context.ErrorDescription, context.ErrorUri), - context.Error, context.ErrorDescription, context.ErrorUri); - } + CancellationToken = cancellationToken, + RemoteUri = uri, + Registration = registration, + Request = request + }; - return context.Request; - } + await dispatcher.DispatchAsync(context); - async ValueTask ApplyConfigurationRequestAsync() + if (context.IsRejected) { - var context = new ApplyConfigurationRequestContext(transaction) - { - CancellationToken = cancellationToken, - RemoteUri = uri, - Registration = registration, - Request = request - }; - - await dispatcher.DispatchAsync(context); + throw new ProtocolException( + SR.FormatID0148(context.Error, context.ErrorDescription, context.ErrorUri), + context.Error, context.ErrorDescription, context.ErrorUri); + } - if (context.IsRejected) - { - throw new ProtocolException( - SR.FormatID0149(context.Error, context.ErrorDescription, context.ErrorUri), - context.Error, context.ErrorDescription, context.ErrorUri); - } + return context.Request; + } - context.Logger.LogInformation(SR.GetResourceString(SR.ID6186), context.RemoteUri, context.Request); + async ValueTask ApplyConfigurationRequestAsync() + { + var context = new ApplyConfigurationRequestContext(transaction) + { + CancellationToken = cancellationToken, + RemoteUri = uri, + Registration = registration, + Request = request + }; - return context.Request; - } + await dispatcher.DispatchAsync(context); - async ValueTask ExtractConfigurationResponseAsync() + if (context.IsRejected) { - var context = new ExtractConfigurationResponseContext(transaction) - { - CancellationToken = cancellationToken, - RemoteUri = uri, - Registration = registration, - Request = request - }; - - await dispatcher.DispatchAsync(context); + throw new ProtocolException( + SR.FormatID0149(context.Error, context.ErrorDescription, context.ErrorUri), + context.Error, context.ErrorDescription, context.ErrorUri); + } - if (context.IsRejected) - { - throw new ProtocolException( - SR.FormatID0150(context.Error, context.ErrorDescription, context.ErrorUri), - context.Error, context.ErrorDescription, context.ErrorUri); - } + context.Logger.LogInformation(SR.GetResourceString(SR.ID6186), context.RemoteUri, context.Request); - Debug.Assert(context.Response is not null, SR.GetResourceString(SR.ID4007)); + return context.Request; + } - context.Logger.LogInformation(SR.GetResourceString(SR.ID6187), context.RemoteUri, context.Response); + async ValueTask ExtractConfigurationResponseAsync() + { + var context = new ExtractConfigurationResponseContext(transaction) + { + CancellationToken = cancellationToken, + RemoteUri = uri, + Registration = registration, + Request = request + }; - return context.Response; - } + await dispatcher.DispatchAsync(context); - async ValueTask HandleConfigurationResponseAsync() + if (context.IsRejected) { - var context = new HandleConfigurationResponseContext(transaction) - { - CancellationToken = cancellationToken, - RemoteUri = uri, - Registration = registration, - Request = request, - Response = response - }; + throw new ProtocolException( + SR.FormatID0150(context.Error, context.ErrorDescription, context.ErrorUri), + context.Error, context.ErrorDescription, context.ErrorUri); + } - await dispatcher.DispatchAsync(context); + Debug.Assert(context.Response is not null, SR.GetResourceString(SR.ID4007)); - if (context.IsRejected) - { - throw new ProtocolException( - SR.FormatID0151(context.Error, context.ErrorDescription, context.ErrorUri), - context.Error, context.ErrorDescription, context.ErrorUri); - } + context.Logger.LogInformation(SR.GetResourceString(SR.ID6187), context.RemoteUri, context.Response); - return context.Configuration; - } + return context.Response; } - finally + async ValueTask HandleConfigurationResponseAsync() { - if (scope is IAsyncDisposable disposable) + var context = new HandleConfigurationResponseContext(transaction) { - await disposable.DisposeAsync(); - } + CancellationToken = cancellationToken, + RemoteUri = uri, + Registration = registration, + Request = request, + Response = response + }; + + await dispatcher.DispatchAsync(context); - else + if (context.IsRejected) { - scope.Dispose(); + throw new ProtocolException( + SR.FormatID0151(context.Error, context.ErrorDescription, context.ErrorUri), + context.Error, context.ErrorDescription, context.ErrorUri); } + + return context.Configuration; } } @@ -1388,71 +1190,53 @@ public class OpenIddictClientService // Note: this service is registered as a singleton service. As such, it cannot // directly depend on scoped services like the validation provider. To work around // this limitation, a scope is manually created for each method to this service. - var scope = _provider.CreateScope(); - - // Note: a try/finally block is deliberately used here to ensure the service scope - // can be disposed of asynchronously if it implements IAsyncDisposable. - try - { - var dispatcher = scope.ServiceProvider.GetRequiredService(); - var factory = scope.ServiceProvider.GetRequiredService(); - - var transaction = await factory.CreateTransactionAsync(); + await using var scope = _provider.CreateAsyncScope(); - var context = new ProcessSignOutContext(transaction) - { - CancellationToken = request.CancellationToken, - IdentityTokenHint = request.IdentityTokenHint, - Issuer = request.Issuer, - LoginHint = request.LoginHint, - Principal = new ClaimsPrincipal(new ClaimsIdentity()), - ProviderName = request.ProviderName, - RegistrationId = request.RegistrationId, - Request = request.AdditionalEndSessionRequestParameters - is Dictionary parameters ? new(parameters) : new(), - }; + var dispatcher = scope.ServiceProvider.GetRequiredService(); + var factory = scope.ServiceProvider.GetRequiredService(); - if (request.Properties is { Count: > 0 }) - { - foreach (var property in request.Properties) - { - context.Properties[property.Key] = property.Value; - } - } + var transaction = await factory.CreateTransactionAsync(); - await dispatcher.DispatchAsync(context); + var context = new ProcessSignOutContext(transaction) + { + CancellationToken = request.CancellationToken, + IdentityTokenHint = request.IdentityTokenHint, + Issuer = request.Issuer, + LoginHint = request.LoginHint, + Principal = new ClaimsPrincipal(new ClaimsIdentity()), + ProviderName = request.ProviderName, + RegistrationId = request.RegistrationId, + Request = request.AdditionalEndSessionRequestParameters + is Dictionary parameters ? new(parameters) : new(), + }; - if (context.IsRejected) + if (request.Properties is { Count: > 0 }) + { + foreach (var property in request.Properties) { - throw new ProtocolException( - message: SR.GetResourceString(SR.ID0434), - context.Error, context.ErrorDescription, context.ErrorUri); + context.Properties[property.Key] = property.Value; } + } - if (string.IsNullOrEmpty(context.Nonce)) - { - throw new InvalidOperationException(SR.GetResourceString(SR.ID0352)); - } + await dispatcher.DispatchAsync(context); - return new() - { - Nonce = context.Nonce, - Properties = context.Properties - }; + if (context.IsRejected) + { + throw new ProtocolException( + message: SR.GetResourceString(SR.ID0434), + context.Error, context.ErrorDescription, context.ErrorUri); } - finally + if (string.IsNullOrEmpty(context.Nonce)) { - if (scope is IAsyncDisposable disposable) - { - await disposable.DisposeAsync(); - } - - else - { - scope.Dispose(); - } + throw new InvalidOperationException(SR.GetResourceString(SR.ID0352)); } + + return new() + { + Nonce = context.Nonce, + Properties = context.Properties + }; } /// @@ -1485,132 +1269,114 @@ public class OpenIddictClientService // Note: this service is registered as a singleton service. As such, it cannot // directly depend on scoped services like the validation provider. To work around // this limitation, a scope is manually created for each method to this service. - var scope = _provider.CreateScope(); + await using var scope = _provider.CreateAsyncScope(); - // Note: a try/finally block is deliberately used here to ensure the service scope - // can be disposed of asynchronously if it implements IAsyncDisposable. - try - { - var dispatcher = scope.ServiceProvider.GetRequiredService(); - var factory = scope.ServiceProvider.GetRequiredService(); - var transaction = await factory.CreateTransactionAsync(); + var dispatcher = scope.ServiceProvider.GetRequiredService(); + var factory = scope.ServiceProvider.GetRequiredService(); + var transaction = await factory.CreateTransactionAsync(); - var request = new OpenIddictRequest(); - request = await PrepareJsonWebKeySetRequestAsync(); - request = await ApplyJsonWebKeySetRequestAsync(); + var request = new OpenIddictRequest(); + request = await PrepareJsonWebKeySetRequestAsync(); + request = await ApplyJsonWebKeySetRequestAsync(); - var response = await ExtractJsonWebKeySetResponseAsync(); + var response = await ExtractJsonWebKeySetResponseAsync(); - return await HandleJsonWebKeySetResponseAsync() ?? - throw new InvalidOperationException(SR.GetResourceString(SR.ID0147)); + return await HandleJsonWebKeySetResponseAsync() ?? + throw new InvalidOperationException(SR.GetResourceString(SR.ID0147)); - async ValueTask PrepareJsonWebKeySetRequestAsync() + async ValueTask PrepareJsonWebKeySetRequestAsync() + { + var context = new PrepareJsonWebKeySetRequestContext(transaction) { - var context = new PrepareJsonWebKeySetRequestContext(transaction) - { - CancellationToken = cancellationToken, - RemoteUri = uri, - Registration = registration, - Request = request - }; - - await dispatcher.DispatchAsync(context); - - if (context.IsRejected) - { - throw new ProtocolException( - SR.FormatID0152(context.Error, context.ErrorDescription, context.ErrorUri), - context.Error, context.ErrorDescription, context.ErrorUri); - } + CancellationToken = cancellationToken, + RemoteUri = uri, + Registration = registration, + Request = request + }; - return context.Request; - } + await dispatcher.DispatchAsync(context); - async ValueTask ApplyJsonWebKeySetRequestAsync() + if (context.IsRejected) { - var context = new ApplyJsonWebKeySetRequestContext(transaction) - { - CancellationToken = cancellationToken, - RemoteUri = uri, - Registration = registration, - Request = request - }; - - await dispatcher.DispatchAsync(context); + throw new ProtocolException( + SR.FormatID0152(context.Error, context.ErrorDescription, context.ErrorUri), + context.Error, context.ErrorDescription, context.ErrorUri); + } - if (context.IsRejected) - { - throw new ProtocolException( - SR.FormatID0153(context.Error, context.ErrorDescription, context.ErrorUri), - context.Error, context.ErrorDescription, context.ErrorUri); - } + return context.Request; + } - context.Logger.LogInformation(SR.GetResourceString(SR.ID6188), context.RemoteUri, context.Request); + async ValueTask ApplyJsonWebKeySetRequestAsync() + { + var context = new ApplyJsonWebKeySetRequestContext(transaction) + { + CancellationToken = cancellationToken, + RemoteUri = uri, + Registration = registration, + Request = request + }; - return context.Request; - } + await dispatcher.DispatchAsync(context); - async ValueTask ExtractJsonWebKeySetResponseAsync() + if (context.IsRejected) { - var context = new ExtractJsonWebKeySetResponseContext(transaction) - { - CancellationToken = cancellationToken, - RemoteUri = uri, - Registration = registration, - Request = request - }; - - await dispatcher.DispatchAsync(context); + throw new ProtocolException( + SR.FormatID0153(context.Error, context.ErrorDescription, context.ErrorUri), + context.Error, context.ErrorDescription, context.ErrorUri); + } - if (context.IsRejected) - { - throw new ProtocolException( - SR.FormatID0154(context.Error, context.ErrorDescription, context.ErrorUri), - context.Error, context.ErrorDescription, context.ErrorUri); - } + context.Logger.LogInformation(SR.GetResourceString(SR.ID6188), context.RemoteUri, context.Request); - Debug.Assert(context.Response is not null, SR.GetResourceString(SR.ID4007)); + return context.Request; + } - context.Logger.LogInformation(SR.GetResourceString(SR.ID6189), context.RemoteUri, context.Response); + async ValueTask ExtractJsonWebKeySetResponseAsync() + { + var context = new ExtractJsonWebKeySetResponseContext(transaction) + { + CancellationToken = cancellationToken, + RemoteUri = uri, + Registration = registration, + Request = request + }; - return context.Response; - } + await dispatcher.DispatchAsync(context); - async ValueTask HandleJsonWebKeySetResponseAsync() + if (context.IsRejected) { - var context = new HandleJsonWebKeySetResponseContext(transaction) - { - CancellationToken = cancellationToken, - RemoteUri = uri, - Registration = registration, - Request = request, - Response = response - }; + throw new ProtocolException( + SR.FormatID0154(context.Error, context.ErrorDescription, context.ErrorUri), + context.Error, context.ErrorDescription, context.ErrorUri); + } - await dispatcher.DispatchAsync(context); + Debug.Assert(context.Response is not null, SR.GetResourceString(SR.ID4007)); - if (context.IsRejected) - { - throw new ProtocolException( - SR.FormatID0155(context.Error, context.ErrorDescription, context.ErrorUri), - context.Error, context.ErrorDescription, context.ErrorUri); - } + context.Logger.LogInformation(SR.GetResourceString(SR.ID6189), context.RemoteUri, context.Response); - return context.JsonWebKeySet; - } + return context.Response; } - finally + async ValueTask HandleJsonWebKeySetResponseAsync() { - if (scope is IAsyncDisposable disposable) + var context = new HandleJsonWebKeySetResponseContext(transaction) { - await disposable.DisposeAsync(); - } + CancellationToken = cancellationToken, + RemoteUri = uri, + Registration = registration, + Request = request, + Response = response + }; - else + await dispatcher.DispatchAsync(context); + + if (context.IsRejected) { - scope.Dispose(); + throw new ProtocolException( + SR.FormatID0155(context.Error, context.ErrorDescription, context.ErrorUri), + context.Error, context.ErrorDescription, context.ErrorUri); } + + return context.JsonWebKeySet; } } @@ -1658,135 +1424,117 @@ public class OpenIddictClientService // Note: this service is registered as a singleton service. As such, it cannot // directly depend on scoped services like the validation provider. To work around // this limitation, a scope is manually created for each method to this service. - var scope = _provider.CreateScope(); + await using var scope = _provider.CreateAsyncScope(); - // Note: a try/finally block is deliberately used here to ensure the service scope - // can be disposed of asynchronously if it implements IAsyncDisposable. - try - { - var dispatcher = scope.ServiceProvider.GetRequiredService(); - var factory = scope.ServiceProvider.GetRequiredService(); - var transaction = await factory.CreateTransactionAsync(); + var dispatcher = scope.ServiceProvider.GetRequiredService(); + var factory = scope.ServiceProvider.GetRequiredService(); + var transaction = await factory.CreateTransactionAsync(); - request = await PrepareDeviceAuthorizationRequestAsync(); - request = await ApplyDeviceAuthorizationRequestAsync(); + request = await PrepareDeviceAuthorizationRequestAsync(); + request = await ApplyDeviceAuthorizationRequestAsync(); - var response = await ExtractDeviceAuthorizationResponseAsync(); + var response = await ExtractDeviceAuthorizationResponseAsync(); - return await HandleDeviceAuthorizationResponseAsync(); + return await HandleDeviceAuthorizationResponseAsync(); - async ValueTask PrepareDeviceAuthorizationRequestAsync() + async ValueTask PrepareDeviceAuthorizationRequestAsync() + { + var context = new PrepareDeviceAuthorizationRequestContext(transaction) { - var context = new PrepareDeviceAuthorizationRequestContext(transaction) - { - CancellationToken = cancellationToken, - ClientAuthenticationMethod = method, - RemoteUri = uri, - Configuration = configuration, - Registration = registration, - Request = request - }; - - await dispatcher.DispatchAsync(context); + CancellationToken = cancellationToken, + ClientAuthenticationMethod = method, + RemoteUri = uri, + Configuration = configuration, + Registration = registration, + Request = request + }; - if (context.IsRejected) - { - throw new ProtocolException( - SR.FormatID0398(context.Error, context.ErrorDescription, context.ErrorUri), - context.Error, context.ErrorDescription, context.ErrorUri); - } + await dispatcher.DispatchAsync(context); - return context.Request; - } - - async ValueTask ApplyDeviceAuthorizationRequestAsync() + if (context.IsRejected) { - var context = new ApplyDeviceAuthorizationRequestContext(transaction) - { - CancellationToken = cancellationToken, - RemoteUri = uri, - Configuration = configuration, - Registration = registration, - Request = request - }; - - await dispatcher.DispatchAsync(context); + throw new ProtocolException( + SR.FormatID0398(context.Error, context.ErrorDescription, context.ErrorUri), + context.Error, context.ErrorDescription, context.ErrorUri); + } - if (context.IsRejected) - { - throw new ProtocolException( - SR.FormatID0399(context.Error, context.ErrorDescription, context.ErrorUri), - context.Error, context.ErrorDescription, context.ErrorUri); - } + return context.Request; + } - context.Logger.LogInformation(SR.GetResourceString(SR.ID6217), context.RemoteUri, context.Request); + async ValueTask ApplyDeviceAuthorizationRequestAsync() + { + var context = new ApplyDeviceAuthorizationRequestContext(transaction) + { + CancellationToken = cancellationToken, + RemoteUri = uri, + Configuration = configuration, + Registration = registration, + Request = request + }; - return context.Request; - } + await dispatcher.DispatchAsync(context); - async ValueTask ExtractDeviceAuthorizationResponseAsync() + if (context.IsRejected) { - var context = new ExtractDeviceAuthorizationResponseContext(transaction) - { - CancellationToken = cancellationToken, - RemoteUri = uri, - Configuration = configuration, - Registration = registration, - Request = request - }; - - await dispatcher.DispatchAsync(context); + throw new ProtocolException( + SR.FormatID0399(context.Error, context.ErrorDescription, context.ErrorUri), + context.Error, context.ErrorDescription, context.ErrorUri); + } - if (context.IsRejected) - { - throw new ProtocolException( - SR.FormatID0400(context.Error, context.ErrorDescription, context.ErrorUri), - context.Error, context.ErrorDescription, context.ErrorUri); - } + context.Logger.LogInformation(SR.GetResourceString(SR.ID6217), context.RemoteUri, context.Request); - Debug.Assert(context.Response is not null, SR.GetResourceString(SR.ID4007)); + return context.Request; + } - context.Logger.LogInformation(SR.GetResourceString(SR.ID6218), context.RemoteUri, context.Response); + async ValueTask ExtractDeviceAuthorizationResponseAsync() + { + var context = new ExtractDeviceAuthorizationResponseContext(transaction) + { + CancellationToken = cancellationToken, + RemoteUri = uri, + Configuration = configuration, + Registration = registration, + Request = request + }; - return context.Response; - } + await dispatcher.DispatchAsync(context); - async ValueTask HandleDeviceAuthorizationResponseAsync() + if (context.IsRejected) { - var context = new HandleDeviceAuthorizationResponseContext(transaction) - { - CancellationToken = cancellationToken, - RemoteUri = uri, - Configuration = configuration, - Registration = registration, - Request = request, - Response = response - }; + throw new ProtocolException( + SR.FormatID0400(context.Error, context.ErrorDescription, context.ErrorUri), + context.Error, context.ErrorDescription, context.ErrorUri); + } - await dispatcher.DispatchAsync(context); + Debug.Assert(context.Response is not null, SR.GetResourceString(SR.ID4007)); - if (context.IsRejected) - { - throw new ProtocolException( - SR.FormatID0401(context.Error, context.ErrorDescription, context.ErrorUri), - context.Error, context.ErrorDescription, context.ErrorUri); - } + context.Logger.LogInformation(SR.GetResourceString(SR.ID6218), context.RemoteUri, context.Response); - return context.Response; - } + return context.Response; } - finally + async ValueTask HandleDeviceAuthorizationResponseAsync() { - if (scope is IAsyncDisposable disposable) + var context = new HandleDeviceAuthorizationResponseContext(transaction) { - await disposable.DisposeAsync(); - } + CancellationToken = cancellationToken, + RemoteUri = uri, + Configuration = configuration, + Registration = registration, + Request = request, + Response = response + }; - else + await dispatcher.DispatchAsync(context); + + if (context.IsRejected) { - scope.Dispose(); + throw new ProtocolException( + SR.FormatID0401(context.Error, context.ErrorDescription, context.ErrorUri), + context.Error, context.ErrorDescription, context.ErrorUri); } + + return context.Response; } } @@ -1829,137 +1577,119 @@ public class OpenIddictClientService // Note: this service is registered as a singleton service. As such, it cannot // directly depend on scoped services like the validation provider. To work around // this limitation, a scope is manually created for each method to this service. - var scope = _provider.CreateScope(); + await using var scope = _provider.CreateAsyncScope(); - // Note: a try/finally block is deliberately used here to ensure the service scope - // can be disposed of asynchronously if it implements IAsyncDisposable. - try - { - var dispatcher = scope.ServiceProvider.GetRequiredService(); - var factory = scope.ServiceProvider.GetRequiredService(); - var transaction = await factory.CreateTransactionAsync(); + var dispatcher = scope.ServiceProvider.GetRequiredService(); + var factory = scope.ServiceProvider.GetRequiredService(); + var transaction = await factory.CreateTransactionAsync(); - request = await PrepareIntrospectionRequestAsync(); - request = await ApplyIntrospectionRequestAsync(); + request = await PrepareIntrospectionRequestAsync(); + request = await ApplyIntrospectionRequestAsync(); - var response = await ExtractIntrospectionResponseAsync(); + var response = await ExtractIntrospectionResponseAsync(); - return await HandleIntrospectionResponseAsync(); + return await HandleIntrospectionResponseAsync(); - async ValueTask PrepareIntrospectionRequestAsync() + async ValueTask PrepareIntrospectionRequestAsync() + { + var context = new PrepareIntrospectionRequestContext(transaction) { - var context = new PrepareIntrospectionRequestContext(transaction) - { - CancellationToken = cancellationToken, - ClientAuthenticationMethod = method, - Configuration = configuration, - Registration = registration, - RemoteUri = uri, - Request = request - }; - - await dispatcher.DispatchAsync(context); - - if (context.IsRejected) - { - throw new ProtocolException( - SR.FormatID0158(context.Error, context.ErrorDescription, context.ErrorUri), - context.Error, context.ErrorDescription, context.ErrorUri); - } + CancellationToken = cancellationToken, + ClientAuthenticationMethod = method, + Configuration = configuration, + Registration = registration, + RemoteUri = uri, + Request = request + }; - return context.Request; - } + await dispatcher.DispatchAsync(context); - async ValueTask ApplyIntrospectionRequestAsync() + if (context.IsRejected) { - var context = new ApplyIntrospectionRequestContext(transaction) - { - CancellationToken = cancellationToken, - Configuration = configuration, - Registration = registration, - RemoteUri = uri, - Request = request - }; - - await dispatcher.DispatchAsync(context); + throw new ProtocolException( + SR.FormatID0158(context.Error, context.ErrorDescription, context.ErrorUri), + context.Error, context.ErrorDescription, context.ErrorUri); + } - if (context.IsRejected) - { - throw new ProtocolException( - SR.FormatID0159(context.Error, context.ErrorDescription, context.ErrorUri), - context.Error, context.ErrorDescription, context.ErrorUri); - } + return context.Request; + } - context.Logger.LogInformation(SR.GetResourceString(SR.ID6192), context.RemoteUri, context.Request); + async ValueTask ApplyIntrospectionRequestAsync() + { + var context = new ApplyIntrospectionRequestContext(transaction) + { + CancellationToken = cancellationToken, + Configuration = configuration, + Registration = registration, + RemoteUri = uri, + Request = request + }; - return context.Request; - } + await dispatcher.DispatchAsync(context); - async ValueTask ExtractIntrospectionResponseAsync() + if (context.IsRejected) { - var context = new ExtractIntrospectionResponseContext(transaction) - { - CancellationToken = cancellationToken, - Configuration = configuration, - Registration = registration, - RemoteUri = uri, - Request = request - }; + throw new ProtocolException( + SR.FormatID0159(context.Error, context.ErrorDescription, context.ErrorUri), + context.Error, context.ErrorDescription, context.ErrorUri); + } - await dispatcher.DispatchAsync(context); + context.Logger.LogInformation(SR.GetResourceString(SR.ID6192), context.RemoteUri, context.Request); - if (context.IsRejected) - { - throw new ProtocolException( - SR.FormatID0160(context.Error, context.ErrorDescription, context.ErrorUri), - context.Error, context.ErrorDescription, context.ErrorUri); - } - - Debug.Assert(context.Response is not null, SR.GetResourceString(SR.ID4007)); + return context.Request; + } - context.Logger.LogInformation(SR.GetResourceString(SR.ID6193), context.RemoteUri, context.Response); + async ValueTask ExtractIntrospectionResponseAsync() + { + var context = new ExtractIntrospectionResponseContext(transaction) + { + CancellationToken = cancellationToken, + Configuration = configuration, + Registration = registration, + RemoteUri = uri, + Request = request + }; - return context.Response; - } + await dispatcher.DispatchAsync(context); - async ValueTask<(OpenIddictResponse, ClaimsPrincipal)> HandleIntrospectionResponseAsync() + if (context.IsRejected) { - var context = new HandleIntrospectionResponseContext(transaction) - { - CancellationToken = cancellationToken, - Configuration = configuration, - Registration = registration, - RemoteUri = uri, - Request = request, - Response = response - }; + throw new ProtocolException( + SR.FormatID0160(context.Error, context.ErrorDescription, context.ErrorUri), + context.Error, context.ErrorDescription, context.ErrorUri); + } - await dispatcher.DispatchAsync(context); + Debug.Assert(context.Response is not null, SR.GetResourceString(SR.ID4007)); - if (context.IsRejected) - { - throw new ProtocolException( - SR.FormatID0161(context.Error, context.ErrorDescription, context.ErrorUri), - context.Error, context.ErrorDescription, context.ErrorUri); - } - - Debug.Assert(context.Principal is { Identity: ClaimsIdentity }, SR.GetResourceString(SR.ID4006)); + context.Logger.LogInformation(SR.GetResourceString(SR.ID6193), context.RemoteUri, context.Response); - return (context.Response, context.Principal); - } + return context.Response; } - finally + async ValueTask<(OpenIddictResponse, ClaimsPrincipal)> HandleIntrospectionResponseAsync() { - if (scope is IAsyncDisposable disposable) + var context = new HandleIntrospectionResponseContext(transaction) { - await disposable.DisposeAsync(); - } + CancellationToken = cancellationToken, + Configuration = configuration, + Registration = registration, + RemoteUri = uri, + Request = request, + Response = response + }; - else + await dispatcher.DispatchAsync(context); + + if (context.IsRejected) { - scope.Dispose(); + throw new ProtocolException( + SR.FormatID0161(context.Error, context.ErrorDescription, context.ErrorUri), + context.Error, context.ErrorDescription, context.ErrorUri); } + + Debug.Assert(context.Principal is { Identity: ClaimsIdentity }, SR.GetResourceString(SR.ID4006)); + + return (context.Response, context.Principal); } } @@ -2007,135 +1737,117 @@ public class OpenIddictClientService // Note: this service is registered as a singleton service. As such, it cannot // directly depend on scoped services like the validation provider. To work around // this limitation, a scope is manually created for each method to this service. - var scope = _provider.CreateScope(); + await using var scope = _provider.CreateAsyncScope(); - // Note: a try/finally block is deliberately used here to ensure the service scope - // can be disposed of asynchronously if it implements IAsyncDisposable. - try - { - var dispatcher = scope.ServiceProvider.GetRequiredService(); - var factory = scope.ServiceProvider.GetRequiredService(); - var transaction = await factory.CreateTransactionAsync(); + var dispatcher = scope.ServiceProvider.GetRequiredService(); + var factory = scope.ServiceProvider.GetRequiredService(); + var transaction = await factory.CreateTransactionAsync(); - request = await PreparePushedAuthorizationRequestAsync(); - request = await ApplyPushedAuthorizationRequestAsync(); + request = await PreparePushedAuthorizationRequestAsync(); + request = await ApplyPushedAuthorizationRequestAsync(); - var response = await ExtractPushedAuthorizationResponseAsync(); + var response = await ExtractPushedAuthorizationResponseAsync(); - return await HandlePushedAuthorizationResponseAsync(); + return await HandlePushedAuthorizationResponseAsync(); - async ValueTask PreparePushedAuthorizationRequestAsync() + async ValueTask PreparePushedAuthorizationRequestAsync() + { + var context = new PreparePushedAuthorizationRequestContext(transaction) { - var context = new PreparePushedAuthorizationRequestContext(transaction) - { - CancellationToken = cancellationToken, - ClientAuthenticationMethod = method, - RemoteUri = uri, - Configuration = configuration, - Registration = registration, - Request = request - }; - - await dispatcher.DispatchAsync(context); - - if (context.IsRejected) - { - throw new ProtocolException( - SR.FormatID0461(context.Error, context.ErrorDescription, context.ErrorUri), - context.Error, context.ErrorDescription, context.ErrorUri); - } + CancellationToken = cancellationToken, + ClientAuthenticationMethod = method, + RemoteUri = uri, + Configuration = configuration, + Registration = registration, + Request = request + }; - return context.Request; - } + await dispatcher.DispatchAsync(context); - async ValueTask ApplyPushedAuthorizationRequestAsync() + if (context.IsRejected) { - var context = new ApplyPushedAuthorizationRequestContext(transaction) - { - CancellationToken = cancellationToken, - RemoteUri = uri, - Configuration = configuration, - Registration = registration, - Request = request - }; - - await dispatcher.DispatchAsync(context); + throw new ProtocolException( + SR.FormatID0461(context.Error, context.ErrorDescription, context.ErrorUri), + context.Error, context.ErrorDescription, context.ErrorUri); + } - if (context.IsRejected) - { - throw new ProtocolException( - SR.FormatID0462(context.Error, context.ErrorDescription, context.ErrorUri), - context.Error, context.ErrorDescription, context.ErrorUri); - } + return context.Request; + } - context.Logger.LogInformation(SR.GetResourceString(SR.ID6235), context.RemoteUri, context.Request); + async ValueTask ApplyPushedAuthorizationRequestAsync() + { + var context = new ApplyPushedAuthorizationRequestContext(transaction) + { + CancellationToken = cancellationToken, + RemoteUri = uri, + Configuration = configuration, + Registration = registration, + Request = request + }; - return context.Request; - } + await dispatcher.DispatchAsync(context); - async ValueTask ExtractPushedAuthorizationResponseAsync() + if (context.IsRejected) { - var context = new ExtractPushedAuthorizationResponseContext(transaction) - { - CancellationToken = cancellationToken, - RemoteUri = uri, - Configuration = configuration, - Registration = registration, - Request = request - }; - - await dispatcher.DispatchAsync(context); + throw new ProtocolException( + SR.FormatID0462(context.Error, context.ErrorDescription, context.ErrorUri), + context.Error, context.ErrorDescription, context.ErrorUri); + } - if (context.IsRejected) - { - throw new ProtocolException( - SR.FormatID0463(context.Error, context.ErrorDescription, context.ErrorUri), - context.Error, context.ErrorDescription, context.ErrorUri); - } + context.Logger.LogInformation(SR.GetResourceString(SR.ID6235), context.RemoteUri, context.Request); - Debug.Assert(context.Response is not null, SR.GetResourceString(SR.ID4007)); + return context.Request; + } - context.Logger.LogInformation(SR.GetResourceString(SR.ID6236), context.RemoteUri, context.Response); + async ValueTask ExtractPushedAuthorizationResponseAsync() + { + var context = new ExtractPushedAuthorizationResponseContext(transaction) + { + CancellationToken = cancellationToken, + RemoteUri = uri, + Configuration = configuration, + Registration = registration, + Request = request + }; - return context.Response; - } + await dispatcher.DispatchAsync(context); - async ValueTask HandlePushedAuthorizationResponseAsync() + if (context.IsRejected) { - var context = new HandlePushedAuthorizationResponseContext(transaction) - { - CancellationToken = cancellationToken, - RemoteUri = uri, - Configuration = configuration, - Registration = registration, - Request = request, - Response = response - }; + throw new ProtocolException( + SR.FormatID0463(context.Error, context.ErrorDescription, context.ErrorUri), + context.Error, context.ErrorDescription, context.ErrorUri); + } - await dispatcher.DispatchAsync(context); + Debug.Assert(context.Response is not null, SR.GetResourceString(SR.ID4007)); - if (context.IsRejected) - { - throw new ProtocolException( - SR.FormatID0464(context.Error, context.ErrorDescription, context.ErrorUri), - context.Error, context.ErrorDescription, context.ErrorUri); - } + context.Logger.LogInformation(SR.GetResourceString(SR.ID6236), context.RemoteUri, context.Response); - return context.Response; - } + return context.Response; } - finally + async ValueTask HandlePushedAuthorizationResponseAsync() { - if (scope is IAsyncDisposable disposable) + var context = new HandlePushedAuthorizationResponseContext(transaction) { - await disposable.DisposeAsync(); - } + CancellationToken = cancellationToken, + RemoteUri = uri, + Configuration = configuration, + Registration = registration, + Request = request, + Response = response + }; + + await dispatcher.DispatchAsync(context); - else + if (context.IsRejected) { - scope.Dispose(); + throw new ProtocolException( + SR.FormatID0464(context.Error, context.ErrorDescription, context.ErrorUri), + context.Error, context.ErrorDescription, context.ErrorUri); } + + return context.Response; } } @@ -2178,135 +1890,117 @@ public class OpenIddictClientService // Note: this service is registered as a singleton service. As such, it cannot // directly depend on scoped services like the validation provider. To work around // this limitation, a scope is manually created for each method to this service. - var scope = _provider.CreateScope(); + await using var scope = _provider.CreateAsyncScope(); - // Note: a try/finally block is deliberately used here to ensure the service scope - // can be disposed of asynchronously if it implements IAsyncDisposable. - try - { - var dispatcher = scope.ServiceProvider.GetRequiredService(); - var factory = scope.ServiceProvider.GetRequiredService(); - var transaction = await factory.CreateTransactionAsync(); + var dispatcher = scope.ServiceProvider.GetRequiredService(); + var factory = scope.ServiceProvider.GetRequiredService(); + var transaction = await factory.CreateTransactionAsync(); - request = await PrepareRevocationRequestAsync(); - request = await ApplyRevocationRequestAsync(); + request = await PrepareRevocationRequestAsync(); + request = await ApplyRevocationRequestAsync(); - var response = await ExtractRevocationResponseAsync(); + var response = await ExtractRevocationResponseAsync(); - return await HandleRevocationResponseAsync(); + return await HandleRevocationResponseAsync(); - async ValueTask PrepareRevocationRequestAsync() + async ValueTask PrepareRevocationRequestAsync() + { + var context = new PrepareRevocationRequestContext(transaction) { - var context = new PrepareRevocationRequestContext(transaction) - { - CancellationToken = cancellationToken, - ClientAuthenticationMethod = method, - Configuration = configuration, - Registration = registration, - RemoteUri = uri, - Request = request - }; - - await dispatcher.DispatchAsync(context); - - if (context.IsRejected) - { - throw new ProtocolException( - SR.FormatID0430(context.Error, context.ErrorDescription, context.ErrorUri), - context.Error, context.ErrorDescription, context.ErrorUri); - } + CancellationToken = cancellationToken, + ClientAuthenticationMethod = method, + Configuration = configuration, + Registration = registration, + RemoteUri = uri, + Request = request + }; - return context.Request; - } + await dispatcher.DispatchAsync(context); - async ValueTask ApplyRevocationRequestAsync() + if (context.IsRejected) { - var context = new ApplyRevocationRequestContext(transaction) - { - CancellationToken = cancellationToken, - Configuration = configuration, - Registration = registration, - RemoteUri = uri, - Request = request - }; - - await dispatcher.DispatchAsync(context); + throw new ProtocolException( + SR.FormatID0430(context.Error, context.ErrorDescription, context.ErrorUri), + context.Error, context.ErrorDescription, context.ErrorUri); + } - if (context.IsRejected) - { - throw new ProtocolException( - SR.FormatID0431(context.Error, context.ErrorDescription, context.ErrorUri), - context.Error, context.ErrorDescription, context.ErrorUri); - } + return context.Request; + } - context.Logger.LogInformation(SR.GetResourceString(SR.ID6192), context.RemoteUri, context.Request); + async ValueTask ApplyRevocationRequestAsync() + { + var context = new ApplyRevocationRequestContext(transaction) + { + CancellationToken = cancellationToken, + Configuration = configuration, + Registration = registration, + RemoteUri = uri, + Request = request + }; - return context.Request; - } + await dispatcher.DispatchAsync(context); - async ValueTask ExtractRevocationResponseAsync() + if (context.IsRejected) { - var context = new ExtractRevocationResponseContext(transaction) - { - CancellationToken = cancellationToken, - Configuration = configuration, - Registration = registration, - RemoteUri = uri, - Request = request - }; - - await dispatcher.DispatchAsync(context); + throw new ProtocolException( + SR.FormatID0431(context.Error, context.ErrorDescription, context.ErrorUri), + context.Error, context.ErrorDescription, context.ErrorUri); + } - if (context.IsRejected) - { - throw new ProtocolException( - SR.FormatID0432(context.Error, context.ErrorDescription, context.ErrorUri), - context.Error, context.ErrorDescription, context.ErrorUri); - } + context.Logger.LogInformation(SR.GetResourceString(SR.ID6192), context.RemoteUri, context.Request); - Debug.Assert(context.Response is not null, SR.GetResourceString(SR.ID4007)); + return context.Request; + } - context.Logger.LogInformation(SR.GetResourceString(SR.ID6193), context.RemoteUri, context.Response); + async ValueTask ExtractRevocationResponseAsync() + { + var context = new ExtractRevocationResponseContext(transaction) + { + CancellationToken = cancellationToken, + Configuration = configuration, + Registration = registration, + RemoteUri = uri, + Request = request + }; - return context.Response; - } + await dispatcher.DispatchAsync(context); - async ValueTask HandleRevocationResponseAsync() + if (context.IsRejected) { - var context = new HandleRevocationResponseContext(transaction) - { - CancellationToken = cancellationToken, - Configuration = configuration, - Registration = registration, - RemoteUri = uri, - Request = request, - Response = response - }; + throw new ProtocolException( + SR.FormatID0432(context.Error, context.ErrorDescription, context.ErrorUri), + context.Error, context.ErrorDescription, context.ErrorUri); + } - await dispatcher.DispatchAsync(context); + Debug.Assert(context.Response is not null, SR.GetResourceString(SR.ID4007)); - if (context.IsRejected) - { - throw new ProtocolException( - SR.FormatID0433(context.Error, context.ErrorDescription, context.ErrorUri), - context.Error, context.ErrorDescription, context.ErrorUri); - } + context.Logger.LogInformation(SR.GetResourceString(SR.ID6193), context.RemoteUri, context.Response); - return context.Response; - } + return context.Response; } - finally + async ValueTask HandleRevocationResponseAsync() { - if (scope is IAsyncDisposable disposable) + var context = new HandleRevocationResponseContext(transaction) { - await disposable.DisposeAsync(); - } + CancellationToken = cancellationToken, + Configuration = configuration, + Registration = registration, + RemoteUri = uri, + Request = request, + Response = response + }; + + await dispatcher.DispatchAsync(context); - else + if (context.IsRejected) { - scope.Dispose(); + throw new ProtocolException( + SR.FormatID0433(context.Error, context.ErrorDescription, context.ErrorUri), + context.Error, context.ErrorDescription, context.ErrorUri); } + + return context.Response; } } @@ -2354,135 +2048,117 @@ public class OpenIddictClientService // Note: this service is registered as a singleton service. As such, it cannot // directly depend on scoped services like the validation provider. To work around // this limitation, a scope is manually created for each method to this service. - var scope = _provider.CreateScope(); + await using var scope = _provider.CreateAsyncScope(); - // Note: a try/finally block is deliberately used here to ensure the service scope - // can be disposed of asynchronously if it implements IAsyncDisposable. - try - { - var dispatcher = scope.ServiceProvider.GetRequiredService(); - var factory = scope.ServiceProvider.GetRequiredService(); - var transaction = await factory.CreateTransactionAsync(); + var dispatcher = scope.ServiceProvider.GetRequiredService(); + var factory = scope.ServiceProvider.GetRequiredService(); + var transaction = await factory.CreateTransactionAsync(); - request = await PrepareTokenRequestAsync(); - request = await ApplyTokenRequestAsync(); + request = await PrepareTokenRequestAsync(); + request = await ApplyTokenRequestAsync(); - var response = await ExtractTokenResponseAsync(); + var response = await ExtractTokenResponseAsync(); - return await HandleTokenResponseAsync(); + return await HandleTokenResponseAsync(); - async ValueTask PrepareTokenRequestAsync() + async ValueTask PrepareTokenRequestAsync() + { + var context = new PrepareTokenRequestContext(transaction) { - var context = new PrepareTokenRequestContext(transaction) - { - CancellationToken = cancellationToken, - ClientAuthenticationMethod = method, - Configuration = configuration, - Registration = registration, - RemoteUri = uri, - Request = request - }; - - await dispatcher.DispatchAsync(context); - - if (context.IsRejected) - { - throw new ProtocolException( - SR.FormatID0320(context.Error, context.ErrorDescription, context.ErrorUri), - context.Error, context.ErrorDescription, context.ErrorUri); - } + CancellationToken = cancellationToken, + ClientAuthenticationMethod = method, + Configuration = configuration, + Registration = registration, + RemoteUri = uri, + Request = request + }; - return context.Request; - } + await dispatcher.DispatchAsync(context); - async ValueTask ApplyTokenRequestAsync() + if (context.IsRejected) { - var context = new ApplyTokenRequestContext(transaction) - { - CancellationToken = cancellationToken, - Configuration = configuration, - Registration = registration, - RemoteUri = uri, - Request = request - }; - - await dispatcher.DispatchAsync(context); + throw new ProtocolException( + SR.FormatID0320(context.Error, context.ErrorDescription, context.ErrorUri), + context.Error, context.ErrorDescription, context.ErrorUri); + } - if (context.IsRejected) - { - throw new ProtocolException( - SR.FormatID0321(context.Error, context.ErrorDescription, context.ErrorUri), - context.Error, context.ErrorDescription, context.ErrorUri); - } + return context.Request; + } - context.Logger.LogInformation(SR.GetResourceString(SR.ID6192), context.RemoteUri, context.Request); + async ValueTask ApplyTokenRequestAsync() + { + var context = new ApplyTokenRequestContext(transaction) + { + CancellationToken = cancellationToken, + Configuration = configuration, + Registration = registration, + RemoteUri = uri, + Request = request + }; - return context.Request; - } + await dispatcher.DispatchAsync(context); - async ValueTask ExtractTokenResponseAsync() + if (context.IsRejected) { - var context = new ExtractTokenResponseContext(transaction) - { - CancellationToken = cancellationToken, - Configuration = configuration, - Registration = registration, - RemoteUri = uri, - Request = request - }; - - await dispatcher.DispatchAsync(context); + throw new ProtocolException( + SR.FormatID0321(context.Error, context.ErrorDescription, context.ErrorUri), + context.Error, context.ErrorDescription, context.ErrorUri); + } - if (context.IsRejected) - { - throw new ProtocolException( - SR.FormatID0322(context.Error, context.ErrorDescription, context.ErrorUri), - context.Error, context.ErrorDescription, context.ErrorUri); - } + context.Logger.LogInformation(SR.GetResourceString(SR.ID6192), context.RemoteUri, context.Request); - Debug.Assert(context.Response is not null, SR.GetResourceString(SR.ID4007)); + return context.Request; + } - context.Logger.LogInformation(SR.GetResourceString(SR.ID6193), context.RemoteUri, context.Response); + async ValueTask ExtractTokenResponseAsync() + { + var context = new ExtractTokenResponseContext(transaction) + { + CancellationToken = cancellationToken, + Configuration = configuration, + Registration = registration, + RemoteUri = uri, + Request = request + }; - return context.Response; - } + await dispatcher.DispatchAsync(context); - async ValueTask HandleTokenResponseAsync() + if (context.IsRejected) { - var context = new HandleTokenResponseContext(transaction) - { - CancellationToken = cancellationToken, - Configuration = configuration, - Registration = registration, - RemoteUri = uri, - Request = request, - Response = response - }; + throw new ProtocolException( + SR.FormatID0322(context.Error, context.ErrorDescription, context.ErrorUri), + context.Error, context.ErrorDescription, context.ErrorUri); + } - await dispatcher.DispatchAsync(context); + Debug.Assert(context.Response is not null, SR.GetResourceString(SR.ID4007)); - if (context.IsRejected) - { - throw new ProtocolException( - SR.FormatID0323(context.Error, context.ErrorDescription, context.ErrorUri), - context.Error, context.ErrorDescription, context.ErrorUri); - } + context.Logger.LogInformation(SR.GetResourceString(SR.ID6193), context.RemoteUri, context.Response); - return context.Response; - } + return context.Response; } - finally + async ValueTask HandleTokenResponseAsync() { - if (scope is IAsyncDisposable disposable) + var context = new HandleTokenResponseContext(transaction) { - await disposable.DisposeAsync(); - } + CancellationToken = cancellationToken, + Configuration = configuration, + Registration = registration, + RemoteUri = uri, + Request = request, + Response = response + }; + + await dispatcher.DispatchAsync(context); - else + if (context.IsRejected) { - scope.Dispose(); + throw new ProtocolException( + SR.FormatID0323(context.Error, context.ErrorDescription, context.ErrorUri), + context.Error, context.ErrorDescription, context.ErrorUri); } + + return context.Response; } } @@ -2525,137 +2201,119 @@ public class OpenIddictClientService // Note: this service is registered as a singleton service. As such, it cannot // directly depend on scoped services like the validation provider. To work around // this limitation, a scope is manually created for each method to this service. - var scope = _provider.CreateScope(); + await using var scope = _provider.CreateAsyncScope(); - // Note: a try/finally block is deliberately used here to ensure the service scope - // can be disposed of asynchronously if it implements IAsyncDisposable. - try - { - var dispatcher = scope.ServiceProvider.GetRequiredService(); - var factory = scope.ServiceProvider.GetRequiredService(); - var transaction = await factory.CreateTransactionAsync(); + var dispatcher = scope.ServiceProvider.GetRequiredService(); + var factory = scope.ServiceProvider.GetRequiredService(); + var transaction = await factory.CreateTransactionAsync(); - request = await PrepareUserInfoRequestAsync(); - request = await ApplyUserInfoRequestAsync(); + request = await PrepareUserInfoRequestAsync(); + request = await ApplyUserInfoRequestAsync(); - var (response, token) = await ExtractUserInfoResponseAsync(); + var (response, token) = await ExtractUserInfoResponseAsync(); - return await HandleUserInfoResponseAsync(); + return await HandleUserInfoResponseAsync(); - async ValueTask PrepareUserInfoRequestAsync() + async ValueTask PrepareUserInfoRequestAsync() + { + var context = new PrepareUserInfoRequestContext(transaction) { - var context = new PrepareUserInfoRequestContext(transaction) - { - CancellationToken = cancellationToken, - Configuration = configuration, - RemoteUri = uri, - Registration = registration, - Request = request - }; - - context.TokenBindingMethods.UnionWith(methods); - - await dispatcher.DispatchAsync(context); + CancellationToken = cancellationToken, + Configuration = configuration, + RemoteUri = uri, + Registration = registration, + Request = request + }; - if (context.IsRejected) - { - throw new ProtocolException( - SR.FormatID0324(context.Error, context.ErrorDescription, context.ErrorUri), - context.Error, context.ErrorDescription, context.ErrorUri); - } + context.TokenBindingMethods.UnionWith(methods); - return context.Request; - } + await dispatcher.DispatchAsync(context); - async ValueTask ApplyUserInfoRequestAsync() + if (context.IsRejected) { - var context = new ApplyUserInfoRequestContext(transaction) - { - CancellationToken = cancellationToken, - Configuration = configuration, - RemoteUri = uri, - Registration = registration, - Request = request - }; - - await dispatcher.DispatchAsync(context); + throw new ProtocolException( + SR.FormatID0324(context.Error, context.ErrorDescription, context.ErrorUri), + context.Error, context.ErrorDescription, context.ErrorUri); + } - if (context.IsRejected) - { - throw new ProtocolException( - SR.FormatID0325(context.Error, context.ErrorDescription, context.ErrorUri), - context.Error, context.ErrorDescription, context.ErrorUri); - } + return context.Request; + } - context.Logger.LogInformation(SR.GetResourceString(SR.ID6194), context.RemoteUri, context.Request); + async ValueTask ApplyUserInfoRequestAsync() + { + var context = new ApplyUserInfoRequestContext(transaction) + { + CancellationToken = cancellationToken, + Configuration = configuration, + RemoteUri = uri, + Registration = registration, + Request = request + }; - return context.Request; - } + await dispatcher.DispatchAsync(context); - async ValueTask<(OpenIddictResponse, string?)> ExtractUserInfoResponseAsync() + if (context.IsRejected) { - var context = new ExtractUserInfoResponseContext(transaction) - { - CancellationToken = cancellationToken, - Configuration = configuration, - RemoteUri = uri, - Registration = registration, - Request = request - }; - - await dispatcher.DispatchAsync(context); + throw new ProtocolException( + SR.FormatID0325(context.Error, context.ErrorDescription, context.ErrorUri), + context.Error, context.ErrorDescription, context.ErrorUri); + } - if (context.IsRejected) - { - throw new ProtocolException( - SR.FormatID0326(context.Error, context.ErrorDescription, context.ErrorUri), - context.Error, context.ErrorDescription, context.ErrorUri); - } + context.Logger.LogInformation(SR.GetResourceString(SR.ID6194), context.RemoteUri, context.Request); - Debug.Assert(context.Response is not null, SR.GetResourceString(SR.ID4007)); + return context.Request; + } - context.Logger.LogInformation(SR.GetResourceString(SR.ID6195), context.RemoteUri, context.Response); + async ValueTask<(OpenIddictResponse, string?)> ExtractUserInfoResponseAsync() + { + var context = new ExtractUserInfoResponseContext(transaction) + { + CancellationToken = cancellationToken, + Configuration = configuration, + RemoteUri = uri, + Registration = registration, + Request = request + }; - return (context.Response, context.UserInfoToken); - } + await dispatcher.DispatchAsync(context); - async ValueTask<(OpenIddictResponse, (ClaimsPrincipal?, string?))> HandleUserInfoResponseAsync() + if (context.IsRejected) { - var context = new HandleUserInfoResponseContext(transaction) - { - CancellationToken = cancellationToken, - Configuration = configuration, - Registration = registration, - RemoteUri = uri, - Request = request, - Response = response, - UserInfoToken = token - }; + throw new ProtocolException( + SR.FormatID0326(context.Error, context.ErrorDescription, context.ErrorUri), + context.Error, context.ErrorDescription, context.ErrorUri); + } - await dispatcher.DispatchAsync(context); + Debug.Assert(context.Response is not null, SR.GetResourceString(SR.ID4007)); - if (context.IsRejected) - { - throw new ProtocolException( - SR.FormatID0327(context.Error, context.ErrorDescription, context.ErrorUri), - context.Error, context.ErrorDescription, context.ErrorUri); - } + context.Logger.LogInformation(SR.GetResourceString(SR.ID6195), context.RemoteUri, context.Response); - return (context.Response, (context.Principal, context.UserInfoToken)); - } + return (context.Response, context.UserInfoToken); } - finally + async ValueTask<(OpenIddictResponse, (ClaimsPrincipal?, string?))> HandleUserInfoResponseAsync() { - if (scope is IAsyncDisposable disposable) + var context = new HandleUserInfoResponseContext(transaction) { - await disposable.DisposeAsync(); - } + CancellationToken = cancellationToken, + Configuration = configuration, + Registration = registration, + RemoteUri = uri, + Request = request, + Response = response, + UserInfoToken = token + }; - else + await dispatcher.DispatchAsync(context); + + if (context.IsRejected) { - scope.Dispose(); + throw new ProtocolException( + SR.FormatID0327(context.Error, context.ErrorDescription, context.ErrorUri), + context.Error, context.ErrorDescription, context.ErrorUri); } + + return (context.Response, (context.Principal, context.UserInfoToken)); } } } diff --git a/src/OpenIddict.Quartz/OpenIddictQuartzJob.cs b/src/OpenIddict.Quartz/OpenIddictQuartzJob.cs index 6fab9690..e297240e 100644 --- a/src/OpenIddict.Quartz/OpenIddictQuartzJob.cs +++ b/src/OpenIddict.Quartz/OpenIddictQuartzJob.cs @@ -55,124 +55,108 @@ public sealed class OpenIddictQuartzJob : IJob // Note: this job is registered as a transient service. As such, it cannot directly depend on scoped services // like the core managers. To work around this limitation, a scope is manually created for each invocation. - var scope = _provider.CreateScope(); + await using var scope = _provider.CreateAsyncScope(); - try - { - // Important: since authorizations that still have tokens attached are never - // pruned, the tokens MUST be deleted before deleting the authorizations. - - if (!_options.CurrentValue.DisableTokenPruning) - { - var manager = scope.ServiceProvider.GetService() ?? - throw new JobExecutionException(new InvalidOperationException(SR.GetResourceString(SR.ID0278))) - { - RefireImmediately = false, - UnscheduleAllTriggers = true, - UnscheduleFiringTrigger = true - }; - - var threshold = _options.CurrentValue.TimeProvider.GetUtcNow() - _options.CurrentValue.MinimumTokenLifespan; + // Important: since authorizations that still have tokens attached are never + // pruned, the tokens MUST be deleted before deleting the authorizations. - try + if (!_options.CurrentValue.DisableTokenPruning) + { + var manager = scope.ServiceProvider.GetService() ?? + throw new JobExecutionException(new InvalidOperationException(SR.GetResourceString(SR.ID0278))) { - await manager.PruneAsync(threshold, context.CancellationToken); - } + RefireImmediately = false, + UnscheduleAllTriggers = true, + UnscheduleFiringTrigger = true + }; - // OperationCanceledExceptions are typically thrown when the host is about to shut down. - // To allow the host to shut down as fast as possible, this exception type is special-cased - // to prevent further processing in this job and inform Quartz.NET it shouldn't be refired. - catch (OperationCanceledException exception) when (context.CancellationToken.IsCancellationRequested) - { - throw new JobExecutionException(exception) - { - RefireImmediately = false - }; - } - - // AggregateExceptions are generally thrown by the manager itself when one or multiple exception(s) - // occurred while trying to prune the entities. In this case, add the inner exceptions to the collection. - catch (AggregateException exception) when (!OpenIddictHelpers.IsFatal(exception)) - { - exceptions ??= []; - exceptions.AddRange(exception.InnerExceptions); - } + var threshold = _options.CurrentValue.TimeProvider.GetUtcNow() - _options.CurrentValue.MinimumTokenLifespan; - // Other non-fatal exceptions are assumed to be transient and are added to the exceptions collection - // to be re-thrown later (typically, at the very end of this job, as an AggregateException). - catch (Exception exception) when (!OpenIddictHelpers.IsFatal(exception)) + try + { + await manager.PruneAsync(threshold, context.CancellationToken); + } + + // OperationCanceledExceptions are typically thrown when the host is about to shut down. + // To allow the host to shut down as fast as possible, this exception type is special-cased + // to prevent further processing in this job and inform Quartz.NET it shouldn't be refired. + catch (OperationCanceledException exception) when (context.CancellationToken.IsCancellationRequested) + { + throw new JobExecutionException(exception) { - exceptions ??= []; - exceptions.Add(exception); - } + RefireImmediately = false + }; } - if (!_options.CurrentValue.DisableAuthorizationPruning) + // AggregateExceptions are generally thrown by the manager itself when one or multiple exception(s) + // occurred while trying to prune the entities. In this case, add the inner exceptions to the collection. + catch (AggregateException exception) when (!OpenIddictHelpers.IsFatal(exception)) { - var manager = scope.ServiceProvider.GetService() ?? - throw new JobExecutionException(new InvalidOperationException(SR.GetResourceString(SR.ID0278))) - { - RefireImmediately = false, - UnscheduleAllTriggers = true, - UnscheduleFiringTrigger = true - }; + exceptions ??= []; + exceptions.AddRange(exception.InnerExceptions); + } - var threshold = _options.CurrentValue.TimeProvider.GetUtcNow() - _options.CurrentValue.MinimumAuthorizationLifespan; + // Other non-fatal exceptions are assumed to be transient and are added to the exceptions collection + // to be re-thrown later (typically, at the very end of this job, as an AggregateException). + catch (Exception exception) when (!OpenIddictHelpers.IsFatal(exception)) + { + exceptions ??= []; + exceptions.Add(exception); + } + } - try + if (!_options.CurrentValue.DisableAuthorizationPruning) + { + var manager = scope.ServiceProvider.GetService() ?? + throw new JobExecutionException(new InvalidOperationException(SR.GetResourceString(SR.ID0278))) { - await manager.PruneAsync(threshold, context.CancellationToken); - } + RefireImmediately = false, + UnscheduleAllTriggers = true, + UnscheduleFiringTrigger = true + }; - // OperationCanceledExceptions are typically thrown when the host is about to shut down. - // To allow the host to shut down as fast as possible, this exception type is special-cased - // to prevent further processing in this job and inform Quartz.NET it shouldn't be refired. - catch (OperationCanceledException exception) when (context.CancellationToken.IsCancellationRequested) - { - throw new JobExecutionException(exception) - { - RefireImmediately = false - }; - } - - // AggregateExceptions are generally thrown by the manager itself when one or multiple exception(s) - // occurred while trying to prune the entities. In this case, add the inner exceptions to the collection. - catch (AggregateException exception) when (!OpenIddictHelpers.IsFatal(exception)) - { - exceptions ??= []; - exceptions.AddRange(exception.InnerExceptions); - } + var threshold = _options.CurrentValue.TimeProvider.GetUtcNow() - _options.CurrentValue.MinimumAuthorizationLifespan; - // Other non-fatal exceptions are assumed to be transient and are added to the exceptions collection - // to be re-thrown later (typically, at the very end of this job, as an AggregateException). - catch (Exception exception) when (!OpenIddictHelpers.IsFatal(exception)) - { - exceptions ??= []; - exceptions.Add(exception); - } + try + { + await manager.PruneAsync(threshold, context.CancellationToken); } - if (exceptions is not null) + // OperationCanceledExceptions are typically thrown when the host is about to shut down. + // To allow the host to shut down as fast as possible, this exception type is special-cased + // to prevent further processing in this job and inform Quartz.NET it shouldn't be refired. + catch (OperationCanceledException exception) when (context.CancellationToken.IsCancellationRequested) { - throw new JobExecutionException(new AggregateException(exceptions)) + throw new JobExecutionException(exception) { - // Only refire the job if the maximum refire count set in the options wasn't reached. - RefireImmediately = context.RefireCount < _options.CurrentValue.MaximumRefireCount + RefireImmediately = false }; } - } - finally - { - if (scope is IAsyncDisposable disposable) + // AggregateExceptions are generally thrown by the manager itself when one or multiple exception(s) + // occurred while trying to prune the entities. In this case, add the inner exceptions to the collection. + catch (AggregateException exception) when (!OpenIddictHelpers.IsFatal(exception)) { - await disposable.DisposeAsync(); + exceptions ??= []; + exceptions.AddRange(exception.InnerExceptions); } - else + // Other non-fatal exceptions are assumed to be transient and are added to the exceptions collection + // to be re-thrown later (typically, at the very end of this job, as an AggregateException). + catch (Exception exception) when (!OpenIddictHelpers.IsFatal(exception)) { - scope.Dispose(); + exceptions ??= []; + exceptions.Add(exception); } } + + if (exceptions is not null) + { + throw new JobExecutionException(new AggregateException(exceptions)) + { + // Only refire the job if the maximum refire count set in the options wasn't reached. + RefireImmediately = context.RefireCount < _options.CurrentValue.MaximumRefireCount + }; + } } } diff --git a/src/OpenIddict.Validation/OpenIddictValidationService.cs b/src/OpenIddict.Validation/OpenIddictValidationService.cs index 453d4a16..ec3d23de 100644 --- a/src/OpenIddict.Validation/OpenIddictValidationService.cs +++ b/src/OpenIddict.Validation/OpenIddictValidationService.cs @@ -46,47 +46,29 @@ public class OpenIddictValidationService // Note: this service is registered as a singleton service. As such, it cannot // directly depend on scoped services like the validation provider. To work around // this limitation, a scope is manually created for each method to this service. - var scope = _provider.CreateScope(); + await using var scope = _provider.CreateAsyncScope(); - // Note: a try/finally block is deliberately used here to ensure the service scope - // can be disposed of asynchronously if it implements IAsyncDisposable. - try - { - var dispatcher = scope.ServiceProvider.GetRequiredService(); - var factory = scope.ServiceProvider.GetRequiredService(); - var transaction = await factory.CreateTransactionAsync(); + var dispatcher = scope.ServiceProvider.GetRequiredService(); + var factory = scope.ServiceProvider.GetRequiredService(); + var transaction = await factory.CreateTransactionAsync(); - var context = new ProcessAuthenticationContext(transaction) - { - AccessToken = token - }; - - await dispatcher.DispatchAsync(context); - - if (context.IsRejected) - { - throw new ProtocolException( - SR.FormatID0163(context.Error, context.ErrorDescription, context.ErrorUri), - context.Error, context.ErrorDescription, context.ErrorUri); - } + var context = new ProcessAuthenticationContext(transaction) + { + AccessToken = token + }; - Debug.Assert(context.AccessTokenPrincipal is { Identity: ClaimsIdentity }, SR.GetResourceString(SR.ID4006)); + await dispatcher.DispatchAsync(context); - return context.AccessTokenPrincipal; + if (context.IsRejected) + { + throw new ProtocolException( + SR.FormatID0163(context.Error, context.ErrorDescription, context.ErrorUri), + context.Error, context.ErrorDescription, context.ErrorUri); } - finally - { - if (scope is IAsyncDisposable disposable) - { - await disposable.DisposeAsync(); - } + Debug.Assert(context.AccessTokenPrincipal is { Identity: ClaimsIdentity }, SR.GetResourceString(SR.ID4006)); - else - { - scope.Dispose(); - } - } + return context.AccessTokenPrincipal; } /// @@ -112,123 +94,105 @@ public class OpenIddictValidationService // Note: this service is registered as a singleton service. As such, it cannot // directly depend on scoped services like the validation provider. To work around // this limitation, a scope is manually created for each method to this service. - var scope = _provider.CreateScope(); + await using var scope = _provider.CreateAsyncScope(); - // Note: a try/finally block is deliberately used here to ensure the service scope - // can be disposed of asynchronously if it implements IAsyncDisposable. - try - { - var dispatcher = scope.ServiceProvider.GetRequiredService(); - var factory = scope.ServiceProvider.GetRequiredService(); - var transaction = await factory.CreateTransactionAsync(); + var dispatcher = scope.ServiceProvider.GetRequiredService(); + var factory = scope.ServiceProvider.GetRequiredService(); + var transaction = await factory.CreateTransactionAsync(); - var request = new OpenIddictRequest(); - request = await PrepareConfigurationRequestAsync(); - request = await ApplyConfigurationRequestAsync(); - var response = await ExtractConfigurationResponseAsync(); + var request = new OpenIddictRequest(); + request = await PrepareConfigurationRequestAsync(); + request = await ApplyConfigurationRequestAsync(); + var response = await ExtractConfigurationResponseAsync(); - return await HandleConfigurationResponseAsync() ?? - throw new InvalidOperationException(SR.GetResourceString(SR.ID0145)); + return await HandleConfigurationResponseAsync() ?? + throw new InvalidOperationException(SR.GetResourceString(SR.ID0145)); - async ValueTask PrepareConfigurationRequestAsync() + async ValueTask PrepareConfigurationRequestAsync() + { + var context = new PrepareConfigurationRequestContext(transaction) { - var context = new PrepareConfigurationRequestContext(transaction) - { - RemoteUri = uri, - Request = request - }; - - await dispatcher.DispatchAsync(context); - - if (context.IsRejected) - { - throw new ProtocolException( - SR.FormatID0148(context.Error, context.ErrorDescription, context.ErrorUri), - context.Error, context.ErrorDescription, context.ErrorUri); - } - - return context.Request; - } + RemoteUri = uri, + Request = request + }; - async ValueTask ApplyConfigurationRequestAsync() - { - var context = new ApplyConfigurationRequestContext(transaction) - { - RemoteUri = uri, - Request = request - }; + await dispatcher.DispatchAsync(context); - await dispatcher.DispatchAsync(context); + if (context.IsRejected) + { + throw new ProtocolException( + SR.FormatID0148(context.Error, context.ErrorDescription, context.ErrorUri), + context.Error, context.ErrorDescription, context.ErrorUri); + } - if (context.IsRejected) - { - throw new ProtocolException( - SR.FormatID0149(context.Error, context.ErrorDescription, context.ErrorUri), - context.Error, context.ErrorDescription, context.ErrorUri); - } + return context.Request; + } - context.Logger.LogInformation(SR.GetResourceString(SR.ID6186), context.RemoteUri, context.Request); + async ValueTask ApplyConfigurationRequestAsync() + { + var context = new ApplyConfigurationRequestContext(transaction) + { + RemoteUri = uri, + Request = request + }; - return context.Request; - } + await dispatcher.DispatchAsync(context); - async ValueTask ExtractConfigurationResponseAsync() + if (context.IsRejected) { - var context = new ExtractConfigurationResponseContext(transaction) - { - RemoteUri = uri, - Request = request - }; - - await dispatcher.DispatchAsync(context); + throw new ProtocolException( + SR.FormatID0149(context.Error, context.ErrorDescription, context.ErrorUri), + context.Error, context.ErrorDescription, context.ErrorUri); + } - if (context.IsRejected) - { - throw new ProtocolException( - SR.FormatID0150(context.Error, context.ErrorDescription, context.ErrorUri), - context.Error, context.ErrorDescription, context.ErrorUri); - } + context.Logger.LogInformation(SR.GetResourceString(SR.ID6186), context.RemoteUri, context.Request); - Debug.Assert(context.Response is not null, SR.GetResourceString(SR.ID4007)); + return context.Request; + } - context.Logger.LogInformation(SR.GetResourceString(SR.ID6187), context.RemoteUri, context.Response); + async ValueTask ExtractConfigurationResponseAsync() + { + var context = new ExtractConfigurationResponseContext(transaction) + { + RemoteUri = uri, + Request = request + }; - return context.Response; - } + await dispatcher.DispatchAsync(context); - async ValueTask HandleConfigurationResponseAsync() + if (context.IsRejected) { - var context = new HandleConfigurationResponseContext(transaction) - { - RemoteUri = uri, - Request = request, - Response = response - }; - - await dispatcher.DispatchAsync(context); - - if (context.IsRejected) - { - throw new ProtocolException( - SR.FormatID0151(context.Error, context.ErrorDescription, context.ErrorUri), - context.Error, context.ErrorDescription, context.ErrorUri); - } - - return context.Configuration; + throw new ProtocolException( + SR.FormatID0150(context.Error, context.ErrorDescription, context.ErrorUri), + context.Error, context.ErrorDescription, context.ErrorUri); } + + Debug.Assert(context.Response is not null, SR.GetResourceString(SR.ID4007)); + + context.Logger.LogInformation(SR.GetResourceString(SR.ID6187), context.RemoteUri, context.Response); + + return context.Response; } - finally + async ValueTask HandleConfigurationResponseAsync() { - if (scope is IAsyncDisposable disposable) + var context = new HandleConfigurationResponseContext(transaction) { - await disposable.DisposeAsync(); - } + RemoteUri = uri, + Request = request, + Response = response + }; + + await dispatcher.DispatchAsync(context); - else + if (context.IsRejected) { - scope.Dispose(); + throw new ProtocolException( + SR.FormatID0151(context.Error, context.ErrorDescription, context.ErrorUri), + context.Error, context.ErrorDescription, context.ErrorUri); } + + return context.Configuration; } } @@ -255,123 +219,105 @@ public class OpenIddictValidationService // Note: this service is registered as a singleton service. As such, it cannot // directly depend on scoped services like the validation provider. To work around // this limitation, a scope is manually created for each method to this service. - var scope = _provider.CreateScope(); + await using var scope = _provider.CreateAsyncScope(); - // Note: a try/finally block is deliberately used here to ensure the service scope - // can be disposed of asynchronously if it implements IAsyncDisposable. - try - { - var dispatcher = scope.ServiceProvider.GetRequiredService(); - var factory = scope.ServiceProvider.GetRequiredService(); - var transaction = await factory.CreateTransactionAsync(); + var dispatcher = scope.ServiceProvider.GetRequiredService(); + var factory = scope.ServiceProvider.GetRequiredService(); + var transaction = await factory.CreateTransactionAsync(); - var request = new OpenIddictRequest(); - request = await PrepareJsonWebKeySetRequestAsync(); - request = await ApplyJsonWebKeySetRequestAsync(); + var request = new OpenIddictRequest(); + request = await PrepareJsonWebKeySetRequestAsync(); + request = await ApplyJsonWebKeySetRequestAsync(); - var response = await ExtractJsonWebKeySetResponseAsync(); + var response = await ExtractJsonWebKeySetResponseAsync(); - return await HandleJsonWebKeySetResponseAsync() ?? - throw new InvalidOperationException(SR.GetResourceString(SR.ID0147)); + return await HandleJsonWebKeySetResponseAsync() ?? + throw new InvalidOperationException(SR.GetResourceString(SR.ID0147)); - async ValueTask PrepareJsonWebKeySetRequestAsync() + async ValueTask PrepareJsonWebKeySetRequestAsync() + { + var context = new PrepareJsonWebKeySetRequestContext(transaction) { - var context = new PrepareJsonWebKeySetRequestContext(transaction) - { - RemoteUri = uri, - Request = request - }; - - await dispatcher.DispatchAsync(context); - - if (context.IsRejected) - { - throw new ProtocolException( - SR.FormatID0152(context.Error, context.ErrorDescription, context.ErrorUri), - context.Error, context.ErrorDescription, context.ErrorUri); - } - - return context.Request; - } + RemoteUri = uri, + Request = request + }; - async ValueTask ApplyJsonWebKeySetRequestAsync() - { - var context = new ApplyJsonWebKeySetRequestContext(transaction) - { - RemoteUri = uri, - Request = request - }; + await dispatcher.DispatchAsync(context); - await dispatcher.DispatchAsync(context); + if (context.IsRejected) + { + throw new ProtocolException( + SR.FormatID0152(context.Error, context.ErrorDescription, context.ErrorUri), + context.Error, context.ErrorDescription, context.ErrorUri); + } - if (context.IsRejected) - { - throw new ProtocolException( - SR.FormatID0153(context.Error, context.ErrorDescription, context.ErrorUri), - context.Error, context.ErrorDescription, context.ErrorUri); - } + return context.Request; + } - context.Logger.LogInformation(SR.GetResourceString(SR.ID6188), context.RemoteUri, context.Request); + async ValueTask ApplyJsonWebKeySetRequestAsync() + { + var context = new ApplyJsonWebKeySetRequestContext(transaction) + { + RemoteUri = uri, + Request = request + }; - return context.Request; - } + await dispatcher.DispatchAsync(context); - async ValueTask ExtractJsonWebKeySetResponseAsync() + if (context.IsRejected) { - var context = new ExtractJsonWebKeySetResponseContext(transaction) - { - RemoteUri = uri, - Request = request - }; - - await dispatcher.DispatchAsync(context); + throw new ProtocolException( + SR.FormatID0153(context.Error, context.ErrorDescription, context.ErrorUri), + context.Error, context.ErrorDescription, context.ErrorUri); + } - if (context.IsRejected) - { - throw new ProtocolException( - SR.FormatID0154(context.Error, context.ErrorDescription, context.ErrorUri), - context.Error, context.ErrorDescription, context.ErrorUri); - } + context.Logger.LogInformation(SR.GetResourceString(SR.ID6188), context.RemoteUri, context.Request); - Debug.Assert(context.Response is not null, SR.GetResourceString(SR.ID4007)); + return context.Request; + } - context.Logger.LogInformation(SR.GetResourceString(SR.ID6189), context.RemoteUri, context.Response); + async ValueTask ExtractJsonWebKeySetResponseAsync() + { + var context = new ExtractJsonWebKeySetResponseContext(transaction) + { + RemoteUri = uri, + Request = request + }; - return context.Response; - } + await dispatcher.DispatchAsync(context); - async ValueTask HandleJsonWebKeySetResponseAsync() + if (context.IsRejected) { - var context = new HandleJsonWebKeySetResponseContext(transaction) - { - Request = request, - Response = response - }; - - await dispatcher.DispatchAsync(context); - - if (context.IsRejected) - { - throw new ProtocolException( - SR.FormatID0155(context.Error, context.ErrorDescription, context.ErrorUri), - context.Error, context.ErrorDescription, context.ErrorUri); - } - - return context.SecurityKeys; + throw new ProtocolException( + SR.FormatID0154(context.Error, context.ErrorDescription, context.ErrorUri), + context.Error, context.ErrorDescription, context.ErrorUri); } + + Debug.Assert(context.Response is not null, SR.GetResourceString(SR.ID4007)); + + context.Logger.LogInformation(SR.GetResourceString(SR.ID6189), context.RemoteUri, context.Response); + + return context.Response; } - finally + async ValueTask HandleJsonWebKeySetResponseAsync() { - if (scope is IAsyncDisposable disposable) + var context = new HandleJsonWebKeySetResponseContext(transaction) { - await disposable.DisposeAsync(); - } + Request = request, + Response = response + }; + + await dispatcher.DispatchAsync(context); - else + if (context.IsRejected) { - scope.Dispose(); + throw new ProtocolException( + SR.FormatID0155(context.Error, context.ErrorDescription, context.ErrorUri), + context.Error, context.ErrorDescription, context.ErrorUri); } + + return context.SecurityKeys; } } @@ -413,133 +359,115 @@ public class OpenIddictValidationService // Note: this service is registered as a singleton service. As such, it cannot // directly depend on scoped services like the validation provider. To work around // this limitation, a scope is manually created for each method to this service. - var scope = _provider.CreateScope(); + await using var scope = _provider.CreateAsyncScope(); - // Note: a try/finally block is deliberately used here to ensure the service scope - // can be disposed of asynchronously if it implements IAsyncDisposable. - try - { - var dispatcher = scope.ServiceProvider.GetRequiredService(); - var factory = scope.ServiceProvider.GetRequiredService(); - var transaction = await factory.CreateTransactionAsync(); + var dispatcher = scope.ServiceProvider.GetRequiredService(); + var factory = scope.ServiceProvider.GetRequiredService(); + var transaction = await factory.CreateTransactionAsync(); - request = await PrepareIntrospectionRequestAsync(); - request = await ApplyIntrospectionRequestAsync(); + request = await PrepareIntrospectionRequestAsync(); + request = await ApplyIntrospectionRequestAsync(); - var response = await ExtractIntrospectionResponseAsync(); + var response = await ExtractIntrospectionResponseAsync(); - return await HandleIntrospectionResponseAsync(); + return await HandleIntrospectionResponseAsync(); - async ValueTask PrepareIntrospectionRequestAsync() + async ValueTask PrepareIntrospectionRequestAsync() + { + var context = new PrepareIntrospectionRequestContext(transaction) { - var context = new PrepareIntrospectionRequestContext(transaction) - { - CancellationToken = cancellationToken, - ClientAuthenticationMethod = method, - RemoteUri = uri, - Configuration = configuration, - Request = request - }; - - await dispatcher.DispatchAsync(context); - - if (context.IsRejected) - { - throw new ProtocolException( - SR.FormatID0158(context.Error, context.ErrorDescription, context.ErrorUri), - context.Error, context.ErrorDescription, context.ErrorUri); - } - - return context.Request; - } + CancellationToken = cancellationToken, + ClientAuthenticationMethod = method, + RemoteUri = uri, + Configuration = configuration, + Request = request + }; + + await dispatcher.DispatchAsync(context); - async ValueTask ApplyIntrospectionRequestAsync() + if (context.IsRejected) { - var context = new ApplyIntrospectionRequestContext(transaction) - { - CancellationToken = cancellationToken, - RemoteUri = uri, - Configuration = configuration, - Request = request - }; - - await dispatcher.DispatchAsync(context); - - if (context.IsRejected) - { - throw new ProtocolException( - SR.FormatID0159(context.Error, context.ErrorDescription, context.ErrorUri), - context.Error, context.ErrorDescription, context.ErrorUri); - } - - context.Logger.LogInformation(SR.GetResourceString(SR.ID6192), context.RemoteUri, context.Request); - - return context.Request; + throw new ProtocolException( + SR.FormatID0158(context.Error, context.ErrorDescription, context.ErrorUri), + context.Error, context.ErrorDescription, context.ErrorUri); } - async ValueTask ExtractIntrospectionResponseAsync() + return context.Request; + } + + async ValueTask ApplyIntrospectionRequestAsync() + { + var context = new ApplyIntrospectionRequestContext(transaction) { - var context = new ExtractIntrospectionResponseContext(transaction) - { - CancellationToken = cancellationToken, - RemoteUri = uri, - Configuration = configuration, - Request = request - }; + CancellationToken = cancellationToken, + RemoteUri = uri, + Configuration = configuration, + Request = request + }; - await dispatcher.DispatchAsync(context); + await dispatcher.DispatchAsync(context); - if (context.IsRejected) - { - throw new ProtocolException( - SR.FormatID0160(context.Error, context.ErrorDescription, context.ErrorUri), - context.Error, context.ErrorDescription, context.ErrorUri); - } + if (context.IsRejected) + { + throw new ProtocolException( + SR.FormatID0159(context.Error, context.ErrorDescription, context.ErrorUri), + context.Error, context.ErrorDescription, context.ErrorUri); + } - Debug.Assert(context.Response is not null, SR.GetResourceString(SR.ID4007)); + context.Logger.LogInformation(SR.GetResourceString(SR.ID6192), context.RemoteUri, context.Request); - context.Logger.LogInformation(SR.GetResourceString(SR.ID6193), context.RemoteUri, context.Response); + return context.Request; + } - return context.Response; - } + async ValueTask ExtractIntrospectionResponseAsync() + { + var context = new ExtractIntrospectionResponseContext(transaction) + { + CancellationToken = cancellationToken, + RemoteUri = uri, + Configuration = configuration, + Request = request + }; + + await dispatcher.DispatchAsync(context); - async ValueTask<(OpenIddictResponse, ClaimsPrincipal)> HandleIntrospectionResponseAsync() + if (context.IsRejected) { - var context = new HandleIntrospectionResponseContext(transaction) - { - CancellationToken = cancellationToken, - RemoteUri = uri, - Configuration = configuration, - Request = request, - Response = response - }; - - await dispatcher.DispatchAsync(context); - - if (context.IsRejected) - { - throw new ProtocolException( - SR.FormatID0161(context.Error, context.ErrorDescription, context.ErrorUri), - context.Error, context.ErrorDescription, context.ErrorUri); - } - - Debug.Assert(context.Principal is { Identity: ClaimsIdentity }, SR.GetResourceString(SR.ID4006)); - - return (context.Response, context.Principal); + throw new ProtocolException( + SR.FormatID0160(context.Error, context.ErrorDescription, context.ErrorUri), + context.Error, context.ErrorDescription, context.ErrorUri); } + + Debug.Assert(context.Response is not null, SR.GetResourceString(SR.ID4007)); + + context.Logger.LogInformation(SR.GetResourceString(SR.ID6193), context.RemoteUri, context.Response); + + return context.Response; } - finally + async ValueTask<(OpenIddictResponse, ClaimsPrincipal)> HandleIntrospectionResponseAsync() { - if (scope is IAsyncDisposable disposable) + var context = new HandleIntrospectionResponseContext(transaction) { - await disposable.DisposeAsync(); - } + CancellationToken = cancellationToken, + RemoteUri = uri, + Configuration = configuration, + Request = request, + Response = response + }; - else + await dispatcher.DispatchAsync(context); + + if (context.IsRejected) { - scope.Dispose(); + throw new ProtocolException( + SR.FormatID0161(context.Error, context.ErrorDescription, context.ErrorUri), + context.Error, context.ErrorDescription, context.ErrorUri); } + + Debug.Assert(context.Principal is { Identity: ClaimsIdentity }, SR.GetResourceString(SR.ID4006)); + + return (context.Response, context.Principal); } } } diff --git a/test/OpenIddict.Server.Owin.IntegrationTests/OpenIddictServerOwinIntegrationTests.cs b/test/OpenIddict.Server.Owin.IntegrationTests/OpenIddictServerOwinIntegrationTests.cs index e9deeaab..2b11d0f1 100644 --- a/test/OpenIddict.Server.Owin.IntegrationTests/OpenIddictServerOwinIntegrationTests.cs +++ b/test/OpenIddict.Server.Owin.IntegrationTests/OpenIddictServerOwinIntegrationTests.cs @@ -579,7 +579,7 @@ public partial class OpenIddictServerOwinIntegrationTests : OpenIddictServerInte { app.Use(async (context, next) => { - using var scope = provider.CreateScope(); + await using var scope = provider.CreateAsyncScope(); context.Set(typeof(IServiceProvider).FullName, scope.ServiceProvider); diff --git a/test/OpenIddict.Validation.Owin.IntegrationTests/OpenIddictValidationOwinIntegrationTests.cs b/test/OpenIddict.Validation.Owin.IntegrationTests/OpenIddictValidationOwinIntegrationTests.cs index e2a11407..ac27ccc2 100644 --- a/test/OpenIddict.Validation.Owin.IntegrationTests/OpenIddictValidationOwinIntegrationTests.cs +++ b/test/OpenIddict.Validation.Owin.IntegrationTests/OpenIddictValidationOwinIntegrationTests.cs @@ -128,7 +128,7 @@ public partial class OpenIddictValidationOwinIntegrationTests : OpenIddictValida { app.Use(async (context, next) => { - using var scope = provider.CreateScope(); + await using var scope = provider.CreateAsyncScope(); context.Set(typeof(IServiceProvider).FullName, scope.ServiceProvider);