Browse Source

Replace ValueTask<ImmutableArray<T>> by IAsyncEnumerable<T>

pull/777/head
Kévin Chalet 7 years ago
committed by GitHub
parent
commit
2113b573ad
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 5
      eng/Versions.props
  2. 27
      src/OpenIddict.Abstractions/Caches/IOpenIddictApplicationCache.cs
  3. 55
      src/OpenIddict.Abstractions/Caches/IOpenIddictAuthorizationCache.cs
  4. 27
      src/OpenIddict.Abstractions/Caches/IOpenIddictScopeCache.cs
  5. 55
      src/OpenIddict.Abstractions/Caches/IOpenIddictTokenCache.cs
  6. 121
      src/OpenIddict.Abstractions/Managers/IOpenIddictApplicationManager.cs
  7. 145
      src/OpenIddict.Abstractions/Managers/IOpenIddictAuthorizationManager.cs
  8. 102
      src/OpenIddict.Abstractions/Managers/IOpenIddictScopeManager.cs
  9. 153
      src/OpenIddict.Abstractions/Managers/IOpenIddictTokenManager.cs
  10. 121
      src/OpenIddict.Abstractions/Stores/IOpenIddictApplicationStore.cs
  11. 134
      src/OpenIddict.Abstractions/Stores/IOpenIddictAuthorizationStore.cs
  12. 97
      src/OpenIddict.Abstractions/Stores/IOpenIddictScopeStore.cs
  13. 159
      src/OpenIddict.Abstractions/Stores/IOpenIddictTokenStore.cs
  14. 64
      src/OpenIddict.Core/Caches/OpenIddictApplicationCache.cs
  15. 150
      src/OpenIddict.Core/Caches/OpenIddictAuthorizationCache.cs
  16. 61
      src/OpenIddict.Core/Caches/OpenIddictScopeCache.cs
  17. 156
      src/OpenIddict.Core/Caches/OpenIddictTokenCache.cs
  18. 294
      src/OpenIddict.Core/Managers/OpenIddictApplicationManager.cs
  19. 402
      src/OpenIddict.Core/Managers/OpenIddictAuthorizationManager.cs
  20. 246
      src/OpenIddict.Core/Managers/OpenIddictScopeManager.cs
  21. 420
      src/OpenIddict.Core/Managers/OpenIddictTokenManager.cs
  22. 1
      src/OpenIddict.Core/OpenIddict.Core.csproj
  23. 30
      src/OpenIddict.EntityFramework/OpenIddictEntityFrameworkHelpers.cs
  24. 281
      src/OpenIddict.EntityFramework/Stores/OpenIddictApplicationStore.cs
  25. 300
      src/OpenIddict.EntityFramework/Stores/OpenIddictAuthorizationStore.cs
  26. 161
      src/OpenIddict.EntityFramework/Stores/OpenIddictScopeStore.cs
  27. 320
      src/OpenIddict.EntityFramework/Stores/OpenIddictTokenStore.cs
  28. 2
      src/OpenIddict.EntityFrameworkCore/OpenIddictEntityFrameworkCoreHelpers.cs
  29. 263
      src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictApplicationStore.cs
  30. 353
      src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictAuthorizationStore.cs
  31. 151
      src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictScopeStore.cs
  32. 285
      src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictTokenStore.cs
  33. 75
      src/OpenIddict.MongoDb/OpenIddictMongoDbHelpers.cs
  34. 202
      src/OpenIddict.MongoDb/Stores/OpenIddictApplicationStore.cs
  35. 291
      src/OpenIddict.MongoDb/Stores/OpenIddictAuthorizationStore.cs
  36. 163
      src/OpenIddict.MongoDb/Stores/OpenIddictScopeStore.cs
  37. 311
      src/OpenIddict.MongoDb/Stores/OpenIddictTokenStore.cs
  38. 31
      src/OpenIddict.NHibernate/OpenIddictNHibernateHelpers.cs
  39. 259
      src/OpenIddict.NHibernate/Stores/OpenIddictApplicationStore.cs
  40. 329
      src/OpenIddict.NHibernate/Stores/OpenIddictAuthorizationStore.cs
  41. 184
      src/OpenIddict.NHibernate/Stores/OpenIddictScopeStore.cs
  42. 368
      src/OpenIddict.NHibernate/Stores/OpenIddictTokenStore.cs
  43. 2
      src/OpenIddict.Server/OpenIddictServerHandlers.Authentication.cs
  44. 2
      src/OpenIddict.Server/OpenIddictServerHandlers.Exchange.cs
  45. 51
      src/OpenIddict.Server/OpenIddictServerHandlers.Session.cs

5
eng/Versions.props

@ -14,12 +14,13 @@
<EntityFrameworkVersion>6.3.0-preview8-19405-04</EntityFrameworkVersion>
<EntityFrameworkCoreVersion>3.0.0-preview8.19405.11</EntityFrameworkCoreVersion>
<ExtensionsVersion>3.0.0-preview8.19405.4</ExtensionsVersion>
<JetBrainsVersion>2018.3.0</JetBrainsVersion>
<JetBrainsVersion>2019.1.3</JetBrainsVersion>
<JsonNetVersion>12.0.2</JsonNetVersion>
<JsonNetBsonVersion>1.0.1</JsonNetBsonVersion>
<IdentityModelVersion>6.2.0-preview-60806030202</IdentityModelVersion>
<ImmutableCollectionsVersion>1.5.0</ImmutableCollectionsVersion>
<MongoDbVersion>2.7.0</MongoDbVersion>
<LinqAsyncVersion>4.0.0-preview.6.build.801</LinqAsyncVersion>
<MongoDbVersion>2.9.0</MongoDbVersion>
<MoqVersion>4.7.63</MoqVersion>
<NHibernateVersion>5.2.2</NHibernateVersion>
<OwinVersion>4.0.0</OwinVersion>

27
src/OpenIddict.Abstractions/Caches/IOpenIddictApplicationCache.cs

@ -4,6 +4,7 @@
* the license and the contributors participating to this project.
*/
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Threading;
using System.Threading.Tasks;
@ -22,10 +23,8 @@ namespace OpenIddict.Abstractions
/// </summary>
/// <param name="application">The application to add to the cache.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
Task AddAsync([NotNull] TApplication application, CancellationToken cancellationToken);
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
ValueTask AddAsync([NotNull] TApplication application, CancellationToken cancellationToken);
/// <summary>
/// Retrieves an application using its client identifier.
@ -54,11 +53,8 @@ namespace OpenIddict.Abstractions
/// </summary>
/// <param name="address">The redirect_uri associated with the applications.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
/// whose result returns the client applications corresponding to the specified redirect_uri.
/// </returns>
ValueTask<ImmutableArray<TApplication>> FindByPostLogoutRedirectUriAsync(
/// <returns>The client applications corresponding to the specified redirect_uri.</returns>
IAsyncEnumerable<TApplication> FindByPostLogoutRedirectUriAsync(
[NotNull] string address, CancellationToken cancellationToken);
/// <summary>
@ -66,11 +62,8 @@ namespace OpenIddict.Abstractions
/// </summary>
/// <param name="address">The redirect_uri associated with the applications.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
/// whose result returns the client applications corresponding to the specified redirect_uri.
/// </returns>
ValueTask<ImmutableArray<TApplication>> FindByRedirectUriAsync(
/// <returns>The client applications corresponding to the specified redirect_uri.</returns>
IAsyncEnumerable<TApplication> FindByRedirectUriAsync(
[NotNull] string address, CancellationToken cancellationToken);
/// <summary>
@ -78,9 +71,7 @@ namespace OpenIddict.Abstractions
/// </summary>
/// <param name="application">The application to remove from the cache.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
Task RemoveAsync([NotNull] TApplication application, CancellationToken cancellationToken);
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
ValueTask RemoveAsync([NotNull] TApplication application, CancellationToken cancellationToken);
}
}

55
src/OpenIddict.Abstractions/Caches/IOpenIddictAuthorizationCache.cs

@ -4,6 +4,7 @@
* the license and the contributors participating to this project.
*/
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Threading;
using System.Threading.Tasks;
@ -22,10 +23,8 @@ namespace OpenIddict.Abstractions
/// </summary>
/// <param name="authorization">The authorization to add to the cache.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
Task AddAsync([NotNull] TAuthorization authorization, CancellationToken cancellationToken);
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
ValueTask AddAsync([NotNull] TAuthorization authorization, CancellationToken cancellationToken);
/// <summary>
/// Retrieves the authorizations corresponding to the specified
@ -34,11 +33,8 @@ namespace OpenIddict.Abstractions
/// <param name="subject">The subject associated with the authorization.</param>
/// <param name="client">The client associated with the authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
/// whose result returns the authorizations corresponding to the subject/client.
/// </returns>
ValueTask<ImmutableArray<TAuthorization>> FindAsync(
/// <returns>The authorizations corresponding to the subject/client.</returns>
IAsyncEnumerable<TAuthorization> FindAsync(
[NotNull] string subject, [NotNull] string client, CancellationToken cancellationToken);
/// <summary>
@ -48,11 +44,8 @@ namespace OpenIddict.Abstractions
/// <param name="client">The client associated with the authorization.</param>
/// <param name="status">The authorization status.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
/// whose result returns the authorizations corresponding to the criteria.
/// </returns>
ValueTask<ImmutableArray<TAuthorization>> FindAsync(
/// <returns>The authorizations corresponding to the criteria.</returns>
IAsyncEnumerable<TAuthorization> FindAsync(
[NotNull] string subject, [NotNull] string client, [NotNull] string status, CancellationToken cancellationToken);
/// <summary>
@ -63,11 +56,8 @@ namespace OpenIddict.Abstractions
/// <param name="status">The authorization status.</param>
/// <param name="type">The authorization type.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
/// whose result returns the authorizations corresponding to the criteria.
/// </returns>
ValueTask<ImmutableArray<TAuthorization>> FindAsync(
/// <returns>The authorizations corresponding to the criteria.</returns>
IAsyncEnumerable<TAuthorization> FindAsync(
[NotNull] string subject, [NotNull] string client, [NotNull] string status,
[NotNull] string type, CancellationToken cancellationToken);
@ -80,11 +70,8 @@ namespace OpenIddict.Abstractions
/// <param name="type">The authorization type.</param>
/// <param name="scopes">The minimal scopes associated with the authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
/// whose result returns the authorizations corresponding to the criteria.
/// </returns>
ValueTask<ImmutableArray<TAuthorization>> FindAsync(
/// <returns>The authorizations corresponding to the criteria.</returns>
IAsyncEnumerable<TAuthorization> FindAsync(
[NotNull] string subject, [NotNull] string client, [NotNull] string status,
[NotNull] string type, ImmutableArray<string> scopes, CancellationToken cancellationToken);
@ -93,11 +80,8 @@ namespace OpenIddict.Abstractions
/// </summary>
/// <param name="identifier">The application identifier associated with the authorizations.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
/// whose result returns the authorizations corresponding to the specified application.
/// </returns>
ValueTask<ImmutableArray<TAuthorization>> FindByApplicationIdAsync(
/// <returns>The authorizations corresponding to the specified application.</returns>
IAsyncEnumerable<TAuthorization> FindByApplicationIdAsync(
[NotNull] string identifier, CancellationToken cancellationToken);
/// <summary>
@ -116,20 +100,15 @@ namespace OpenIddict.Abstractions
/// </summary>
/// <param name="subject">The subject associated with the authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
/// whose result returns the authorizations corresponding to the specified subject.
/// </returns>
ValueTask<ImmutableArray<TAuthorization>> FindBySubjectAsync([NotNull] string subject, CancellationToken cancellationToken);
/// <returns>The authorizations corresponding to the specified subject.</returns>
IAsyncEnumerable<TAuthorization> FindBySubjectAsync([NotNull] string subject, CancellationToken cancellationToken);
/// <summary>
/// Removes the specified authorization from the cache.
/// </summary>
/// <param name="authorization">The authorization to remove from the cache.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
Task RemoveAsync([NotNull] TAuthorization authorization, CancellationToken cancellationToken);
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
ValueTask RemoveAsync([NotNull] TAuthorization authorization, CancellationToken cancellationToken);
}
}

27
src/OpenIddict.Abstractions/Caches/IOpenIddictScopeCache.cs

@ -4,6 +4,7 @@
* the license and the contributors participating to this project.
*/
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Threading;
using System.Threading.Tasks;
@ -22,10 +23,8 @@ namespace OpenIddict.Abstractions
/// </summary>
/// <param name="scope">The scope to add to the cache.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
Task AddAsync([NotNull] TScope scope, CancellationToken cancellationToken);
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
ValueTask AddAsync([NotNull] TScope scope, CancellationToken cancellationToken);
/// <summary>
/// Retrieves a scope using its unique identifier.
@ -54,31 +53,23 @@ namespace OpenIddict.Abstractions
/// </summary>
/// <param name="names">The names associated with the scopes.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
/// whose result returns the scopes corresponding to the specified names.
/// </returns>
ValueTask<ImmutableArray<TScope>> FindByNamesAsync(ImmutableArray<string> names, CancellationToken cancellationToken);
/// <returns>The scopes corresponding to the specified names.</returns>
IAsyncEnumerable<TScope> FindByNamesAsync(ImmutableArray<string> names, CancellationToken cancellationToken);
/// <summary>
/// Retrieves all the scopes that contain the specified resource.
/// </summary>
/// <param name="resource">The resource associated with the scopes.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
/// whose result returns the scopes associated with the specified resource.
/// </returns>
ValueTask<ImmutableArray<TScope>> FindByResourceAsync([NotNull] string resource, CancellationToken cancellationToken);
/// <returns>The scopes associated with the specified resource.</returns>
IAsyncEnumerable<TScope> FindByResourceAsync([NotNull] string resource, CancellationToken cancellationToken);
/// <summary>
/// Removes the specified scope from the cache.
/// </summary>
/// <param name="scope">The scope to remove from the cache.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
Task RemoveAsync([NotNull] TScope scope, CancellationToken cancellationToken);
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
ValueTask RemoveAsync([NotNull] TScope scope, CancellationToken cancellationToken);
}
}

55
src/OpenIddict.Abstractions/Caches/IOpenIddictTokenCache.cs

@ -4,6 +4,7 @@
* the license and the contributors participating to this project.
*/
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Threading;
using System.Threading.Tasks;
@ -22,10 +23,8 @@ namespace OpenIddict.Abstractions
/// </summary>
/// <param name="token">The token to add to the cache.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
Task AddAsync([NotNull] TToken token, CancellationToken cancellationToken);
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
ValueTask AddAsync([NotNull] TToken token, CancellationToken cancellationToken);
/// <summary>
/// Retrieves the tokens corresponding to the specified
@ -34,11 +33,8 @@ namespace OpenIddict.Abstractions
/// <param name="subject">The subject associated with the token.</param>
/// <param name="client">The client associated with the token.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
/// whose result returns the tokens corresponding to the subject/client.
/// </returns>
ValueTask<ImmutableArray<TToken>> FindAsync([NotNull] string subject,
/// <returns>The tokens corresponding to the subject/client.</returns>
IAsyncEnumerable<TToken> FindAsync([NotNull] string subject,
[NotNull] string client, CancellationToken cancellationToken);
/// <summary>
@ -48,11 +44,8 @@ namespace OpenIddict.Abstractions
/// <param name="client">The client associated with the token.</param>
/// <param name="status">The token status.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
/// whose result returns the tokens corresponding to the criteria.
/// </returns>
ValueTask<ImmutableArray<TToken>> FindAsync(
/// <returns>The tokens corresponding to the criteria.</returns>
IAsyncEnumerable<TToken> FindAsync(
[NotNull] string subject, [NotNull] string client,
[NotNull] string status, CancellationToken cancellationToken);
@ -64,11 +57,8 @@ namespace OpenIddict.Abstractions
/// <param name="status">The token status.</param>
/// <param name="type">The token type.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
/// whose result returns the tokens corresponding to the criteria.
/// </returns>
ValueTask<ImmutableArray<TToken>> FindAsync(
/// <returns>The tokens corresponding to the criteria.</returns>
IAsyncEnumerable<TToken> FindAsync(
[NotNull] string subject, [NotNull] string client,
[NotNull] string status, [NotNull] string type, CancellationToken cancellationToken);
@ -77,22 +67,16 @@ namespace OpenIddict.Abstractions
/// </summary>
/// <param name="identifier">The application identifier associated with the tokens.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
/// whose result returns the tokens corresponding to the specified application.
/// </returns>
ValueTask<ImmutableArray<TToken>> FindByApplicationIdAsync([NotNull] string identifier, CancellationToken cancellationToken);
/// <returns>The tokens corresponding to the specified application.</returns>
IAsyncEnumerable<TToken> FindByApplicationIdAsync([NotNull] string identifier, CancellationToken cancellationToken);
/// <summary>
/// Retrieves the list of tokens corresponding to the specified authorization identifier.
/// </summary>
/// <param name="identifier">The authorization identifier associated with the tokens.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
/// whose result returns the tokens corresponding to the specified authorization.
/// </returns>
ValueTask<ImmutableArray<TToken>> FindByAuthorizationIdAsync([NotNull] string identifier, CancellationToken cancellationToken);
/// <returns>The tokens corresponding to the specified authorization.</returns>
IAsyncEnumerable<TToken> FindByAuthorizationIdAsync([NotNull] string identifier, CancellationToken cancellationToken);
/// <summary>
/// Retrieves a token using its unique identifier.
@ -122,20 +106,15 @@ namespace OpenIddict.Abstractions
/// </summary>
/// <param name="subject">The subject associated with the tokens.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
/// whose result returns the tokens corresponding to the specified subject.
/// </returns>
ValueTask<ImmutableArray<TToken>> FindBySubjectAsync([NotNull] string subject, CancellationToken cancellationToken);
/// <returns>The tokens corresponding to the specified subject.</returns>
IAsyncEnumerable<TToken> FindBySubjectAsync([NotNull] string subject, CancellationToken cancellationToken);
/// <summary>
/// Removes the specified token from the cache.
/// </summary>
/// <param name="token">The token to remove from the cache.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
Task RemoveAsync([NotNull] TToken token, CancellationToken cancellationToken);
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
ValueTask RemoveAsync([NotNull] TToken token, CancellationToken cancellationToken);
}
}

121
src/OpenIddict.Abstractions/Managers/IOpenIddictApplicationManager.cs

@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.ComponentModel.DataAnnotations;
using System.Linq;
@ -23,10 +24,10 @@ namespace OpenIddict.Abstractions
/// </summary>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the number of applications in the database.
/// </returns>
Task<long> CountAsync(CancellationToken cancellationToken = default);
ValueTask<long> CountAsync(CancellationToken cancellationToken = default);
/// <summary>
/// Determines the number of applications that match the specified query.
@ -35,10 +36,10 @@ namespace OpenIddict.Abstractions
/// <param name="query">The query to execute.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the number of applications that match the specified query.
/// </returns>
Task<long> CountAsync<TResult>([NotNull] Func<IQueryable<object>, IQueryable<TResult>> query, CancellationToken cancellationToken = default);
ValueTask<long> CountAsync<TResult>([NotNull] Func<IQueryable<object>, IQueryable<TResult>> query, CancellationToken cancellationToken = default);
/// <summary>
/// Creates a new application based on the specified descriptor.
@ -48,10 +49,10 @@ namespace OpenIddict.Abstractions
/// <param name="descriptor">The application descriptor.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the unique identifier associated with the application.
/// </returns>
Task<object> CreateAsync([NotNull] OpenIddictApplicationDescriptor descriptor, CancellationToken cancellationToken = default);
ValueTask<object> CreateAsync([NotNull] OpenIddictApplicationDescriptor descriptor, CancellationToken cancellationToken = default);
/// <summary>
/// Creates a new application.
@ -59,9 +60,9 @@ namespace OpenIddict.Abstractions
/// <param name="application">The application to create.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.
/// </returns>
Task CreateAsync([NotNull] object application, CancellationToken cancellationToken = default);
ValueTask CreateAsync([NotNull] object application, CancellationToken cancellationToken = default);
/// <summary>
/// Creates a new application.
@ -72,9 +73,9 @@ namespace OpenIddict.Abstractions
/// <param name="secret">The client secret associated with the application, if applicable.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.
/// </returns>
Task CreateAsync([NotNull] object application, [CanBeNull] string secret, CancellationToken cancellationToken = default);
ValueTask CreateAsync([NotNull] object application, [CanBeNull] string secret, CancellationToken cancellationToken = default);
/// <summary>
/// Removes an existing application.
@ -82,9 +83,9 @@ namespace OpenIddict.Abstractions
/// <param name="application">The application to delete.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.
/// </returns>
Task DeleteAsync([NotNull] object application, CancellationToken cancellationToken = default);
ValueTask DeleteAsync([NotNull] object application, CancellationToken cancellationToken = default);
/// <summary>
/// Retrieves an application using its client identifier.
@ -92,10 +93,10 @@ namespace OpenIddict.Abstractions
/// <param name="identifier">The client identifier associated with the application.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the client application corresponding to the identifier.
/// </returns>
Task<object> FindByClientIdAsync([NotNull] string identifier, CancellationToken cancellationToken = default);
ValueTask<object> FindByClientIdAsync([NotNull] string identifier, CancellationToken cancellationToken = default);
/// <summary>
/// Retrieves an application using its unique identifier.
@ -103,32 +104,26 @@ namespace OpenIddict.Abstractions
/// <param name="identifier">The unique identifier associated with the application.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the client application corresponding to the identifier.
/// </returns>
Task<object> FindByIdAsync([NotNull] string identifier, CancellationToken cancellationToken = default);
ValueTask<object> FindByIdAsync([NotNull] string identifier, CancellationToken cancellationToken = default);
/// <summary>
/// Retrieves all the applications associated with the specified post_logout_redirect_uri.
/// </summary>
/// <param name="address">The post_logout_redirect_uri associated with the applications.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation, whose result
/// returns the client applications corresponding to the specified post_logout_redirect_uri.
/// </returns>
Task<ImmutableArray<object>> FindByPostLogoutRedirectUriAsync([NotNull] string address, CancellationToken cancellationToken = default);
/// <returns>The client applications corresponding to the specified post_logout_redirect_uri.</returns>
IAsyncEnumerable<object> FindByPostLogoutRedirectUriAsync([NotNull] string address, CancellationToken cancellationToken = default);
/// <summary>
/// Retrieves all the applications associated with the specified redirect_uri.
/// </summary>
/// <param name="address">The redirect_uri associated with the applications.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation, whose result
/// returns the client applications corresponding to the specified redirect_uri.
/// </returns>
Task<ImmutableArray<object>> FindByRedirectUriAsync([NotNull] string address, CancellationToken cancellationToken = default);
/// <returns>The client applications corresponding to the specified redirect_uri.</returns>
IAsyncEnumerable<object> FindByRedirectUriAsync([NotNull] string address, CancellationToken cancellationToken = default);
/// <summary>
/// Executes the specified query and returns the first element.
@ -137,10 +132,10 @@ namespace OpenIddict.Abstractions
/// <param name="query">The query to execute.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the first element returned when executing the query.
/// </returns>
Task<TResult> GetAsync<TResult>(
ValueTask<TResult> GetAsync<TResult>(
[NotNull] Func<IQueryable<object>, IQueryable<TResult>> query, CancellationToken cancellationToken = default);
/// <summary>
@ -152,10 +147,10 @@ namespace OpenIddict.Abstractions
/// <param name="state">The optional state.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the first element returned when executing the query.
/// </returns>
Task<TResult> GetAsync<TState, TResult>(
ValueTask<TResult> GetAsync<TState, TResult>(
[NotNull] Func<IQueryable<object>, TState, IQueryable<TResult>> query,
[CanBeNull] TState state, CancellationToken cancellationToken = default);
@ -254,7 +249,7 @@ namespace OpenIddict.Abstractions
/// <param name="permission">The permission.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns><c>true</c> if the application has been granted the specified permission, <c>false</c> otherwise.</returns>
Task<bool> HasPermissionAsync([NotNull] object application, [NotNull] string permission, CancellationToken cancellationToken = default);
ValueTask<bool> HasPermissionAsync([NotNull] object application, [NotNull] string permission, CancellationToken cancellationToken = default);
/// <summary>
/// Determines whether an application is a confidential client.
@ -262,7 +257,7 @@ namespace OpenIddict.Abstractions
/// <param name="application">The application.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns><c>true</c> if the application is a confidential client, <c>false</c> otherwise.</returns>
Task<bool> IsConfidentialAsync([NotNull] object application, CancellationToken cancellationToken = default);
ValueTask<bool> IsConfidentialAsync([NotNull] object application, CancellationToken cancellationToken = default);
/// <summary>
/// Determines whether an application is a hybrid client.
@ -270,7 +265,7 @@ namespace OpenIddict.Abstractions
/// <param name="application">The application.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns><c>true</c> if the application is a hybrid client, <c>false</c> otherwise.</returns>
Task<bool> IsHybridAsync([NotNull] object application, CancellationToken cancellationToken = default);
ValueTask<bool> IsHybridAsync([NotNull] object application, CancellationToken cancellationToken = default);
/// <summary>
/// Determines whether an application is a public client.
@ -278,7 +273,7 @@ namespace OpenIddict.Abstractions
/// <param name="application">The application.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns><c>true</c> if the application is a public client, <c>false</c> otherwise.</returns>
Task<bool> IsPublicAsync([NotNull] object application, CancellationToken cancellationToken = default);
ValueTask<bool> IsPublicAsync([NotNull] object application, CancellationToken cancellationToken = default);
/// <summary>
/// Executes the specified query and returns all the corresponding elements.
@ -286,11 +281,8 @@ namespace OpenIddict.Abstractions
/// <param name="count">The number of results to return.</param>
/// <param name="offset">The number of results to skip.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the elements returned when executing the specified query.
/// </returns>
Task<ImmutableArray<object>> ListAsync(
/// <returns>All the elements returned when executing the specified query.</returns>
IAsyncEnumerable<object> ListAsync(
[CanBeNull] int? count = null, [CanBeNull] int? offset = null, CancellationToken cancellationToken = default);
/// <summary>
@ -299,11 +291,8 @@ namespace OpenIddict.Abstractions
/// <typeparam name="TResult">The result type.</typeparam>
/// <param name="query">The query to execute.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the elements returned when executing the specified query.
/// </returns>
Task<ImmutableArray<TResult>> ListAsync<TResult>(
/// <returns>All the elements returned when executing the specified query.</returns>
IAsyncEnumerable<TResult> ListAsync<TResult>(
[NotNull] Func<IQueryable<object>, IQueryable<TResult>> query, CancellationToken cancellationToken = default);
/// <summary>
@ -314,11 +303,8 @@ namespace OpenIddict.Abstractions
/// <param name="query">The query to execute.</param>
/// <param name="state">The optional state.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the elements returned when executing the specified query.
/// </returns>
Task<ImmutableArray<TResult>> ListAsync<TState, TResult>(
/// <returns>All the elements returned when executing the specified query.</returns>
IAsyncEnumerable<TResult> ListAsync<TState, TResult>(
[NotNull] Func<IQueryable<object>, TState, IQueryable<TResult>> query,
[CanBeNull] TState state, CancellationToken cancellationToken = default);
@ -329,9 +315,9 @@ namespace OpenIddict.Abstractions
/// <param name="application">The application.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.
/// </returns>
Task PopulateAsync([NotNull] OpenIddictApplicationDescriptor descriptor, [NotNull] object application, CancellationToken cancellationToken = default);
ValueTask PopulateAsync([NotNull] OpenIddictApplicationDescriptor descriptor, [NotNull] object application, CancellationToken cancellationToken = default);
/// <summary>
/// Populates the application using the specified descriptor.
@ -340,9 +326,9 @@ namespace OpenIddict.Abstractions
/// <param name="descriptor">The descriptor.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.
/// </returns>
Task PopulateAsync([NotNull] object application, [NotNull] OpenIddictApplicationDescriptor descriptor, CancellationToken cancellationToken = default);
ValueTask PopulateAsync([NotNull] object application, [NotNull] OpenIddictApplicationDescriptor descriptor, CancellationToken cancellationToken = default);
/// <summary>
/// Updates an existing application.
@ -350,9 +336,9 @@ namespace OpenIddict.Abstractions
/// <param name="application">The application to update.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.
/// </returns>
Task UpdateAsync([NotNull] object application, CancellationToken cancellationToken = default);
ValueTask UpdateAsync([NotNull] object application, CancellationToken cancellationToken = default);
/// <summary>
/// Updates an existing application.
@ -361,9 +347,9 @@ namespace OpenIddict.Abstractions
/// <param name="descriptor">The descriptor used to update the application.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.
/// </returns>
Task UpdateAsync([NotNull] object application, [NotNull] OpenIddictApplicationDescriptor descriptor, CancellationToken cancellationToken = default);
ValueTask UpdateAsync([NotNull] object application, [NotNull] OpenIddictApplicationDescriptor descriptor, CancellationToken cancellationToken = default);
/// <summary>
/// Updates an existing application and replaces the existing secret.
@ -374,20 +360,17 @@ namespace OpenIddict.Abstractions
/// <param name="secret">The client secret associated with the application.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.
/// </returns>
Task UpdateAsync([NotNull] object application, [CanBeNull] string secret, CancellationToken cancellationToken = default);
ValueTask UpdateAsync([NotNull] object application, [CanBeNull] string secret, CancellationToken cancellationToken = default);
/// <summary>
/// Validates the application to ensure it's in a consistent state.
/// </summary>
/// <param name="application">The application.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the validation error encountered when validating the application.
/// </returns>
Task<ImmutableArray<ValidationResult>> ValidateAsync([NotNull] object application, CancellationToken cancellationToken = default);
/// <returns>The validation error encountered when validating the application.</returns>
IAsyncEnumerable<ValidationResult> ValidateAsync([NotNull] object application, CancellationToken cancellationToken = default);
/// <summary>
/// Validates the client_secret associated with an application.
@ -395,12 +378,12 @@ namespace OpenIddict.Abstractions
/// <param name="application">The application.</param>
/// <param name="secret">The secret that should be compared to the client_secret stored in the database.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>A <see cref="Task"/> that can be used to monitor the asynchronous operation.</returns>
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns a boolean indicating whether the client secret was valid.
/// </returns>
Task<bool> ValidateClientSecretAsync([NotNull] object application, string secret, CancellationToken cancellationToken = default);
ValueTask<bool> ValidateClientSecretAsync([NotNull] object application, string secret, CancellationToken cancellationToken = default);
/// <summary>
/// Validates the redirect_uri to ensure it's associated with an application.
@ -409,9 +392,9 @@ namespace OpenIddict.Abstractions
/// <param name="address">The address that should be compared to one of the redirect_uri stored in the database.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns a boolean indicating whether the redirect_uri was valid.
/// </returns>
Task<bool> ValidateRedirectUriAsync([NotNull] object application, [NotNull] string address, CancellationToken cancellationToken = default);
ValueTask<bool> ValidateRedirectUriAsync([NotNull] object application, [NotNull] string address, CancellationToken cancellationToken = default);
}
}

145
src/OpenIddict.Abstractions/Managers/IOpenIddictAuthorizationManager.cs

@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.ComponentModel.DataAnnotations;
using System.Linq;
@ -23,10 +24,10 @@ namespace OpenIddict.Abstractions
/// </summary>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the number of authorizations in the database.
/// </returns>
Task<long> CountAsync(CancellationToken cancellationToken = default);
ValueTask<long> CountAsync(CancellationToken cancellationToken = default);
/// <summary>
/// Determines the number of authorizations that match the specified query.
@ -35,10 +36,10 @@ namespace OpenIddict.Abstractions
/// <param name="query">The query to execute.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the number of authorizations that match the specified query.
/// </returns>
Task<long> CountAsync<TResult>(
ValueTask<long> CountAsync<TResult>(
[NotNull] Func<IQueryable<object>, IQueryable<TResult>> query, CancellationToken cancellationToken = default);
/// <summary>
@ -51,9 +52,9 @@ namespace OpenIddict.Abstractions
/// <param name="scopes">The minimal scopes associated with the authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation, whose result returns the authorization.
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation, whose result returns the authorization.
/// </returns>
Task<object> CreateAsync(
ValueTask<object> CreateAsync(
[NotNull] ImmutableDictionary<string, object> claims, [NotNull] string subject, [NotNull] string client,
[NotNull] string type, ImmutableArray<string> scopes, CancellationToken cancellationToken = default);
@ -63,9 +64,9 @@ namespace OpenIddict.Abstractions
/// <param name="descriptor">The authorization descriptor.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation, whose result returns the authorization.
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation, whose result returns the authorization.
/// </returns>
Task<object> CreateAsync([NotNull] OpenIddictAuthorizationDescriptor descriptor, CancellationToken cancellationToken = default);
ValueTask<object> CreateAsync([NotNull] OpenIddictAuthorizationDescriptor descriptor, CancellationToken cancellationToken = default);
/// <summary>
/// Creates a new authorization.
@ -73,9 +74,9 @@ namespace OpenIddict.Abstractions
/// <param name="authorization">The application to create.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.
/// </returns>
Task CreateAsync([NotNull] object authorization, CancellationToken cancellationToken = default);
ValueTask CreateAsync([NotNull] object authorization, CancellationToken cancellationToken = default);
/// <summary>
/// Removes an existing authorization.
@ -83,9 +84,9 @@ namespace OpenIddict.Abstractions
/// <param name="authorization">The authorization to delete.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.
/// </returns>
Task DeleteAsync([NotNull] object authorization, CancellationToken cancellationToken = default);
ValueTask DeleteAsync([NotNull] object authorization, CancellationToken cancellationToken = default);
/// <summary>
/// Retrieves the authorizations corresponding to the specified
@ -94,11 +95,8 @@ namespace OpenIddict.Abstractions
/// <param name="subject">The subject associated with the authorization.</param>
/// <param name="client">The client associated with the authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the authorizations corresponding to the subject/client.
/// </returns>
Task<ImmutableArray<object>> FindAsync([NotNull] string subject, [NotNull] string client, CancellationToken cancellationToken = default);
/// <returns>The authorizations corresponding to the subject/client.</returns>
IAsyncEnumerable<object> FindAsync([NotNull] string subject, [NotNull] string client, CancellationToken cancellationToken = default);
/// <summary>
/// Retrieves the authorizations matching the specified parameters.
@ -107,11 +105,8 @@ namespace OpenIddict.Abstractions
/// <param name="client">The client associated with the authorization.</param>
/// <param name="status">The authorization status.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the authorizations corresponding to the criteria.
/// </returns>
Task<ImmutableArray<object>> FindAsync(
/// <returns>The authorizations corresponding to the criteria.</returns>
IAsyncEnumerable<object> FindAsync(
[NotNull] string subject, [NotNull] string client,
[NotNull] string status, CancellationToken cancellationToken = default);
@ -123,11 +118,8 @@ namespace OpenIddict.Abstractions
/// <param name="status">The authorization status.</param>
/// <param name="type">The authorization type.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the authorizations corresponding to the criteria.
/// </returns>
Task<ImmutableArray<object>> FindAsync(
/// <returns>The authorizations corresponding to the criteria.</returns>
IAsyncEnumerable<object> FindAsync(
[NotNull] string subject, [NotNull] string client,
[NotNull] string status, [NotNull] string type, CancellationToken cancellationToken = default);
@ -140,11 +132,8 @@ namespace OpenIddict.Abstractions
/// <param name="type">The authorization type.</param>
/// <param name="scopes">The minimal scopes associated with the authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the authorizations corresponding to the criteria.
/// </returns>
Task<ImmutableArray<object>> FindAsync(
/// <returns>The authorizations corresponding to the criteria.</returns>
IAsyncEnumerable<object> FindAsync(
[NotNull] string subject, [NotNull] string client, [NotNull] string status,
[NotNull] string type, ImmutableArray<string> scopes, CancellationToken cancellationToken = default);
@ -153,11 +142,8 @@ namespace OpenIddict.Abstractions
/// </summary>
/// <param name="identifier">The application identifier associated with the authorizations.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the authorizations corresponding to the specified application.
/// </returns>
Task<ImmutableArray<object>> FindByApplicationIdAsync([NotNull] string identifier, CancellationToken cancellationToken = default);
/// <returns>The authorizations corresponding to the specified application.</returns>
IAsyncEnumerable<object> FindByApplicationIdAsync([NotNull] string identifier, CancellationToken cancellationToken = default);
/// <summary>
/// Retrieves an authorization using its unique identifier.
@ -165,21 +151,18 @@ namespace OpenIddict.Abstractions
/// <param name="identifier">The unique identifier associated with the authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the authorization corresponding to the identifier.
/// </returns>
Task<object> FindByIdAsync([NotNull] string identifier, CancellationToken cancellationToken = default);
ValueTask<object> FindByIdAsync([NotNull] string identifier, CancellationToken cancellationToken = default);
/// <summary>
/// Retrieves all the authorizations corresponding to the specified subject.
/// </summary>
/// <param name="subject">The subject associated with the authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the authorizations corresponding to the specified subject.
/// </returns>
Task<ImmutableArray<object>> FindBySubjectAsync([NotNull] string subject, CancellationToken cancellationToken = default);
/// <returns>The authorizations corresponding to the specified subject.</returns>
IAsyncEnumerable<object> FindBySubjectAsync([NotNull] string subject, CancellationToken cancellationToken = default);
/// <summary>
/// Retrieves the optional application identifier associated with an authorization.
@ -199,10 +182,10 @@ namespace OpenIddict.Abstractions
/// <param name="query">The query to execute.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the first element returned when executing the query.
/// </returns>
Task<TResult> GetAsync<TResult>(
ValueTask<TResult> GetAsync<TResult>(
[NotNull] Func<IQueryable<object>, IQueryable<TResult>> query, CancellationToken cancellationToken = default);
/// <summary>
@ -214,10 +197,10 @@ namespace OpenIddict.Abstractions
/// <param name="state">The optional state.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the first element returned when executing the query.
/// </returns>
Task<TResult> GetAsync<TState, TResult>(
ValueTask<TResult> GetAsync<TState, TResult>(
[NotNull] Func<IQueryable<object>, TState, IQueryable<TResult>> query,
[CanBeNull] TState state, CancellationToken cancellationToken = default);
@ -283,7 +266,7 @@ namespace OpenIddict.Abstractions
/// <param name="scopes">The scopes.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns><c>true</c> if the scopes are included in the authorization, <c>false</c> otherwise.</returns>
Task<bool> HasScopesAsync([NotNull] object authorization, ImmutableArray<string> scopes, CancellationToken cancellationToken = default);
ValueTask<bool> HasScopesAsync([NotNull] object authorization, ImmutableArray<string> scopes, CancellationToken cancellationToken = default);
/// <summary>
/// Determines whether a given authorization is ad hoc.
@ -291,7 +274,7 @@ namespace OpenIddict.Abstractions
/// <param name="authorization">The authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns><c>true</c> if the authorization is ad hoc, <c>false</c> otherwise.</returns>
Task<bool> IsAdHocAsync([NotNull] object authorization, CancellationToken cancellationToken = default);
ValueTask<bool> IsAdHocAsync([NotNull] object authorization, CancellationToken cancellationToken = default);
/// <summary>
/// Determines whether a given authorization is permanent.
@ -299,7 +282,7 @@ namespace OpenIddict.Abstractions
/// <param name="authorization">The authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns><c>true</c> if the authorization is permanent, <c>false</c> otherwise.</returns>
Task<bool> IsPermanentAsync([NotNull] object authorization, CancellationToken cancellationToken = default);
ValueTask<bool> IsPermanentAsync([NotNull] object authorization, CancellationToken cancellationToken = default);
/// <summary>
/// Determines whether a given authorization has been revoked.
@ -307,7 +290,7 @@ namespace OpenIddict.Abstractions
/// <param name="authorization">The authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns><c>true</c> if the authorization has been revoked, <c>false</c> otherwise.</returns>
Task<bool> IsRevokedAsync([NotNull] object authorization, CancellationToken cancellationToken = default);
ValueTask<bool> IsRevokedAsync([NotNull] object authorization, CancellationToken cancellationToken = default);
/// <summary>
/// Determines whether a given authorization is valid.
@ -315,7 +298,7 @@ namespace OpenIddict.Abstractions
/// <param name="authorization">The authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns><c>true</c> if the authorization is valid, <c>false</c> otherwise.</returns>
Task<bool> IsValidAsync([NotNull] object authorization, CancellationToken cancellationToken = default);
ValueTask<bool> IsValidAsync([NotNull] object authorization, CancellationToken cancellationToken = default);
/// <summary>
/// Executes the specified query and returns all the corresponding elements.
@ -323,11 +306,8 @@ namespace OpenIddict.Abstractions
/// <param name="count">The number of results to return.</param>
/// <param name="offset">The number of results to skip.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the elements returned when executing the specified query.
/// </returns>
Task<ImmutableArray<object>> ListAsync(
/// <returns>All the elements returned when executing the specified query.</returns>
IAsyncEnumerable<object> ListAsync(
[CanBeNull] int? count = null, [CanBeNull] int? offset = null, CancellationToken cancellationToken = default);
/// <summary>
@ -336,11 +316,8 @@ namespace OpenIddict.Abstractions
/// <typeparam name="TResult">The result type.</typeparam>
/// <param name="query">The query to execute.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the elements returned when executing the specified query.
/// </returns>
Task<ImmutableArray<TResult>> ListAsync<TResult>(
/// <returns>All the elements returned when executing the specified query.</returns>
IAsyncEnumerable<TResult> ListAsync<TResult>(
[NotNull] Func<IQueryable<object>, IQueryable<TResult>> query, CancellationToken cancellationToken = default);
/// <summary>
@ -351,11 +328,8 @@ namespace OpenIddict.Abstractions
/// <param name="query">The query to execute.</param>
/// <param name="state">The optional state.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the elements returned when executing the specified query.
/// </returns>
Task<ImmutableArray<TResult>> ListAsync<TState, TResult>(
/// <returns>All the elements returned when executing the specified query.</returns>
IAsyncEnumerable<TResult> ListAsync<TState, TResult>(
[NotNull] Func<IQueryable<object>, TState, IQueryable<TResult>> query,
[CanBeNull] TState state, CancellationToken cancellationToken = default);
@ -366,9 +340,9 @@ namespace OpenIddict.Abstractions
/// <param name="authorization">The authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.
/// </returns>
Task PopulateAsync([NotNull] OpenIddictAuthorizationDescriptor descriptor, [NotNull] object authorization, CancellationToken cancellationToken = default);
ValueTask PopulateAsync([NotNull] OpenIddictAuthorizationDescriptor descriptor, [NotNull] object authorization, CancellationToken cancellationToken = default);
/// <summary>
/// Populates the authorization using the specified descriptor.
@ -377,26 +351,26 @@ namespace OpenIddict.Abstractions
/// <param name="descriptor">The descriptor.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.
/// </returns>
Task PopulateAsync([NotNull] object authorization, [NotNull] OpenIddictAuthorizationDescriptor descriptor, CancellationToken cancellationToken = default);
ValueTask PopulateAsync([NotNull] object authorization, [NotNull] OpenIddictAuthorizationDescriptor descriptor, CancellationToken cancellationToken = default);
/// <summary>
/// Removes the authorizations that are marked as invalid and the ad-hoc ones that have no valid/nonexpired token attached.
/// </summary>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.
/// </returns>
Task PruneAsync(CancellationToken cancellationToken = default);
ValueTask PruneAsync(CancellationToken cancellationToken = default);
/// <summary>
/// Revokes an authorization.
/// </summary>
/// <param name="authorization">The authorization to revoke.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>A <see cref="Task"/> that can be used to monitor the asynchronous operation.</returns>
Task RevokeAsync([NotNull] object authorization, CancellationToken cancellationToken = default);
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
ValueTask RevokeAsync([NotNull] object authorization, CancellationToken cancellationToken = default);
/// <summary>
/// Sets the application identifier associated with an authorization.
@ -405,9 +379,9 @@ namespace OpenIddict.Abstractions
/// <param name="identifier">The unique identifier associated with the client application.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.
/// </returns>
Task SetApplicationIdAsync([NotNull] object authorization, [CanBeNull] string identifier, CancellationToken cancellationToken = default);
ValueTask SetApplicationIdAsync([NotNull] object authorization, [CanBeNull] string identifier, CancellationToken cancellationToken = default);
/// <summary>
/// Updates an existing authorization.
@ -415,9 +389,9 @@ namespace OpenIddict.Abstractions
/// <param name="authorization">The authorization to update.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.
/// </returns>
Task UpdateAsync([NotNull] object authorization, CancellationToken cancellationToken = default);
ValueTask UpdateAsync([NotNull] object authorization, CancellationToken cancellationToken = default);
/// <summary>
/// Updates an existing authorization.
@ -426,19 +400,16 @@ namespace OpenIddict.Abstractions
/// <param name="descriptor">The descriptor used to update the authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.
/// </returns>
Task UpdateAsync([NotNull] object authorization, [NotNull] OpenIddictAuthorizationDescriptor descriptor, CancellationToken cancellationToken = default);
ValueTask UpdateAsync([NotNull] object authorization, [NotNull] OpenIddictAuthorizationDescriptor descriptor, CancellationToken cancellationToken = default);
/// <summary>
/// Validates the authorization to ensure it's in a consistent state.
/// </summary>
/// <param name="authorization">The authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the validation error encountered when validating the authorization.
/// </returns>
Task<ImmutableArray<ValidationResult>> ValidateAsync([NotNull] object authorization, CancellationToken cancellationToken = default);
/// <returns>The validation error encountered when validating the authorization.</returns>
IAsyncEnumerable<ValidationResult> ValidateAsync([NotNull] object authorization, CancellationToken cancellationToken = default);
}
}

102
src/OpenIddict.Abstractions/Managers/IOpenIddictScopeManager.cs

@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.ComponentModel.DataAnnotations;
using System.Linq;
@ -23,10 +24,10 @@ namespace OpenIddict.Abstractions
/// </summary>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the number of scopes in the database.
/// </returns>
Task<long> CountAsync(CancellationToken cancellationToken = default);
ValueTask<long> CountAsync(CancellationToken cancellationToken = default);
/// <summary>
/// Determines the number of scopes that match the specified query.
@ -35,10 +36,10 @@ namespace OpenIddict.Abstractions
/// <param name="query">The query to execute.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the number of scopes that match the specified query.
/// </returns>
Task<long> CountAsync<TResult>([NotNull] Func<IQueryable<object>, IQueryable<TResult>> query, CancellationToken cancellationToken = default);
ValueTask<long> CountAsync<TResult>([NotNull] Func<IQueryable<object>, IQueryable<TResult>> query, CancellationToken cancellationToken = default);
/// <summary>
/// Creates a new scope based on the specified descriptor.
@ -46,9 +47,9 @@ namespace OpenIddict.Abstractions
/// <param name="descriptor">The scope descriptor.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation, whose result returns the scope.
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation, whose result returns the scope.
/// </returns>
Task<object> CreateAsync([NotNull] OpenIddictScopeDescriptor descriptor, CancellationToken cancellationToken = default);
ValueTask<object> CreateAsync([NotNull] OpenIddictScopeDescriptor descriptor, CancellationToken cancellationToken = default);
/// <summary>
/// Creates a new scope.
@ -56,9 +57,9 @@ namespace OpenIddict.Abstractions
/// <param name="scope">The scope to create.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.
/// </returns>
Task CreateAsync([NotNull] object scope, CancellationToken cancellationToken = default);
ValueTask CreateAsync([NotNull] object scope, CancellationToken cancellationToken = default);
/// <summary>
/// Removes an existing scope.
@ -66,9 +67,9 @@ namespace OpenIddict.Abstractions
/// <param name="scope">The scope to delete.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.
/// </returns>
Task DeleteAsync([NotNull] object scope, CancellationToken cancellationToken = default);
ValueTask DeleteAsync([NotNull] object scope, CancellationToken cancellationToken = default);
/// <summary>
/// Retrieves a scope using its unique identifier.
@ -76,10 +77,10 @@ namespace OpenIddict.Abstractions
/// <param name="identifier">The unique identifier associated with the scope.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the scope corresponding to the identifier.
/// </returns>
Task<object> FindByIdAsync([NotNull] string identifier, CancellationToken cancellationToken = default);
ValueTask<object> FindByIdAsync([NotNull] string identifier, CancellationToken cancellationToken = default);
/// <summary>
/// Retrieves a scope using its name.
@ -87,32 +88,26 @@ namespace OpenIddict.Abstractions
/// <param name="name">The name associated with the scope.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the scope corresponding to the specified name.
/// </returns>
Task<object> FindByNameAsync([NotNull] string name, CancellationToken cancellationToken = default);
ValueTask<object> FindByNameAsync([NotNull] string name, CancellationToken cancellationToken = default);
/// <summary>
/// Retrieves a list of scopes using their name.
/// </summary>
/// <param name="names">The names associated with the scopes.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the scopes corresponding to the specified names.
/// </returns>
Task<ImmutableArray<object>> FindByNamesAsync(ImmutableArray<string> names, CancellationToken cancellationToken = default);
/// <returns>The scopes corresponding to the specified names.</returns>
IAsyncEnumerable<object> FindByNamesAsync(ImmutableArray<string> names, CancellationToken cancellationToken = default);
/// <summary>
/// Retrieves all the scopes that contain the specified resource.
/// </summary>
/// <param name="resource">The resource associated with the scopes.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the scopes associated with the specified resource.
/// </returns>
Task<ImmutableArray<object>> FindByResourceAsync([NotNull] string resource, CancellationToken cancellationToken = default);
/// <returns>The scopes associated with the specified resource.</returns>
IAsyncEnumerable<object> FindByResourceAsync([NotNull] string resource, CancellationToken cancellationToken = default);
/// <summary>
/// Executes the specified query and returns the first element.
@ -121,10 +116,10 @@ namespace OpenIddict.Abstractions
/// <param name="query">The query to execute.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the first element returned when executing the query.
/// </returns>
Task<TResult> GetAsync<TResult>(
ValueTask<TResult> GetAsync<TResult>(
[NotNull] Func<IQueryable<object>, IQueryable<TResult>> query, CancellationToken cancellationToken = default);
/// <summary>
@ -136,10 +131,10 @@ namespace OpenIddict.Abstractions
/// <param name="state">The optional state.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the first element returned when executing the query.
/// </returns>
Task<TResult> GetAsync<TState, TResult>(
ValueTask<TResult> GetAsync<TState, TResult>(
[NotNull] Func<IQueryable<object>, TState, IQueryable<TResult>> query,
[CanBeNull] TState state, CancellationToken cancellationToken = default);
@ -204,11 +199,8 @@ namespace OpenIddict.Abstractions
/// <param name="count">The number of results to return.</param>
/// <param name="offset">The number of results to skip.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the elements returned when executing the specified query.
/// </returns>
Task<ImmutableArray<object>> ListAsync(
/// <returns>All the elements returned when executing the specified query.</returns>
IAsyncEnumerable<object> ListAsync(
[CanBeNull] int? count = null, [CanBeNull] int? offset = null, CancellationToken cancellationToken = default);
/// <summary>
@ -217,11 +209,8 @@ namespace OpenIddict.Abstractions
/// <typeparam name="TResult">The result type.</typeparam>
/// <param name="query">The query to execute.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the elements returned when executing the specified query.
/// </returns>
Task<ImmutableArray<TResult>> ListAsync<TResult>(
/// <returns>All the elements returned when executing the specified query.</returns>
IAsyncEnumerable<TResult> ListAsync<TResult>(
[NotNull] Func<IQueryable<object>, IQueryable<TResult>> query, CancellationToken cancellationToken = default);
/// <summary>
@ -232,11 +221,8 @@ namespace OpenIddict.Abstractions
/// <param name="query">The query to execute.</param>
/// <param name="state">The optional state.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the elements returned when executing the specified query.
/// </returns>
Task<ImmutableArray<TResult>> ListAsync<TState, TResult>(
/// <returns>All the elements returned when executing the specified query.</returns>
IAsyncEnumerable<TResult> ListAsync<TState, TResult>(
[NotNull] Func<IQueryable<object>, TState, IQueryable<TResult>> query,
[CanBeNull] TState state, CancellationToken cancellationToken = default);
@ -245,11 +231,8 @@ namespace OpenIddict.Abstractions
/// </summary>
/// <param name="scopes">The scopes.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the resources associated with the specified scopes.
/// </returns>
Task<ImmutableArray<string>> ListResourcesAsync(ImmutableArray<string> scopes, CancellationToken cancellationToken = default);
/// <returns>All the resources associated with the specified scopes.</returns>
IAsyncEnumerable<string> ListResourcesAsync(ImmutableArray<string> scopes, CancellationToken cancellationToken = default);
/// <summary>
/// Populates the specified descriptor using the properties exposed by the scope.
@ -258,9 +241,9 @@ namespace OpenIddict.Abstractions
/// <param name="scope">The scope.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.
/// </returns>
Task PopulateAsync([NotNull] OpenIddictScopeDescriptor descriptor, [NotNull] object scope, CancellationToken cancellationToken = default);
ValueTask PopulateAsync([NotNull] OpenIddictScopeDescriptor descriptor, [NotNull] object scope, CancellationToken cancellationToken = default);
/// <summary>
/// Populates the scope using the specified descriptor.
@ -269,9 +252,9 @@ namespace OpenIddict.Abstractions
/// <param name="descriptor">The descriptor.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.
/// </returns>
Task PopulateAsync([NotNull] object scope, [NotNull] OpenIddictScopeDescriptor descriptor, CancellationToken cancellationToken = default);
ValueTask PopulateAsync([NotNull] object scope, [NotNull] OpenIddictScopeDescriptor descriptor, CancellationToken cancellationToken = default);
/// <summary>
/// Updates an existing scope.
@ -279,9 +262,9 @@ namespace OpenIddict.Abstractions
/// <param name="scope">The scope to update.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.
/// </returns>
Task UpdateAsync([NotNull] object scope, CancellationToken cancellationToken = default);
ValueTask UpdateAsync([NotNull] object scope, CancellationToken cancellationToken = default);
/// <summary>
/// Updates an existing scope.
@ -290,19 +273,16 @@ namespace OpenIddict.Abstractions
/// <param name="descriptor">The descriptor used to update the scope.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.
/// </returns>
Task UpdateAsync([NotNull] object scope, [NotNull] OpenIddictScopeDescriptor descriptor, CancellationToken cancellationToken = default);
ValueTask UpdateAsync([NotNull] object scope, [NotNull] OpenIddictScopeDescriptor descriptor, CancellationToken cancellationToken = default);
/// <summary>
/// Validates the scope to ensure it's in a consistent state.
/// </summary>
/// <param name="scope">The scope.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the validation error encountered when validating the scope.
/// </returns>
Task<ImmutableArray<ValidationResult>> ValidateAsync([NotNull] object scope, CancellationToken cancellationToken = default);
/// <returns>The validation error encountered when validating the scope.</returns>
IAsyncEnumerable<ValidationResult> ValidateAsync([NotNull] object scope, CancellationToken cancellationToken = default);
}
}

153
src/OpenIddict.Abstractions/Managers/IOpenIddictTokenManager.cs

@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.ComponentModel.DataAnnotations;
using System.Linq;
@ -23,10 +24,10 @@ namespace OpenIddict.Abstractions
/// </summary>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the number of tokens in the database.
/// </returns>
Task<long> CountAsync(CancellationToken cancellationToken = default);
ValueTask<long> CountAsync(CancellationToken cancellationToken = default);
/// <summary>
/// Determines the number of tokens that match the specified query.
@ -35,10 +36,10 @@ namespace OpenIddict.Abstractions
/// <param name="query">The query to execute.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the number of tokens that match the specified query.
/// </returns>
Task<long> CountAsync<TResult>([NotNull] Func<IQueryable<object>, IQueryable<TResult>> query, CancellationToken cancellationToken = default);
ValueTask<long> CountAsync<TResult>([NotNull] Func<IQueryable<object>, IQueryable<TResult>> query, CancellationToken cancellationToken = default);
/// <summary>
/// Creates a new token based on the specified descriptor.
@ -46,9 +47,9 @@ namespace OpenIddict.Abstractions
/// <param name="descriptor">The token descriptor.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation, whose result returns the token.
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation, whose result returns the token.
/// </returns>
Task<object> CreateAsync([NotNull] OpenIddictTokenDescriptor descriptor, CancellationToken cancellationToken = default);
ValueTask<object> CreateAsync([NotNull] OpenIddictTokenDescriptor descriptor, CancellationToken cancellationToken = default);
/// <summary>
/// Creates a new token.
@ -56,9 +57,9 @@ namespace OpenIddict.Abstractions
/// <param name="token">The token.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.
/// </returns>
Task CreateAsync([NotNull] object token, CancellationToken cancellationToken = default);
ValueTask CreateAsync([NotNull] object token, CancellationToken cancellationToken = default);
/// <summary>
/// Removes an existing token.
@ -66,9 +67,9 @@ namespace OpenIddict.Abstractions
/// <param name="token">The token to delete.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.
/// </returns>
Task DeleteAsync([NotNull] object token, CancellationToken cancellationToken = default);
ValueTask DeleteAsync([NotNull] object token, CancellationToken cancellationToken = default);
/// <summary>
/// Extends the specified token by replacing its expiration date.
@ -77,9 +78,9 @@ namespace OpenIddict.Abstractions
/// <param name="date">The date on which the token will no longer be considered valid.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.
/// </returns>
Task ExtendAsync([NotNull] object token, [CanBeNull] DateTimeOffset? date, CancellationToken cancellationToken = default);
ValueTask ExtendAsync([NotNull] object token, [CanBeNull] DateTimeOffset? date, CancellationToken cancellationToken = default);
/// <summary>
/// Retrieves the tokens corresponding to the specified
@ -88,11 +89,8 @@ namespace OpenIddict.Abstractions
/// <param name="subject">The subject associated with the token.</param>
/// <param name="client">The client associated with the token.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the tokens corresponding to the subject/client.
/// </returns>
Task<ImmutableArray<object>> FindAsync([NotNull] string subject,
/// <returns>The tokens corresponding to the subject/client.</returns>
IAsyncEnumerable<object> FindAsync([NotNull] string subject,
[NotNull] string client, CancellationToken cancellationToken = default);
/// <summary>
@ -102,11 +100,8 @@ namespace OpenIddict.Abstractions
/// <param name="client">The client associated with the token.</param>
/// <param name="status">The token status.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the tokens corresponding to the criteria.
/// </returns>
Task<ImmutableArray<object>> FindAsync(
/// <returns>The tokens corresponding to the criteria.</returns>
IAsyncEnumerable<object> FindAsync(
[NotNull] string subject, [NotNull] string client,
[NotNull] string status, CancellationToken cancellationToken = default);
@ -118,11 +113,8 @@ namespace OpenIddict.Abstractions
/// <param name="status">The token status.</param>
/// <param name="type">The token type.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the tokens corresponding to the criteria.
/// </returns>
Task<ImmutableArray<object>> FindAsync(
/// <returns>The tokens corresponding to the criteria.</returns>
IAsyncEnumerable<object> FindAsync(
[NotNull] string subject, [NotNull] string client,
[NotNull] string status, [NotNull] string type, CancellationToken cancellationToken = default);
@ -131,22 +123,16 @@ namespace OpenIddict.Abstractions
/// </summary>
/// <param name="identifier">The application identifier associated with the tokens.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the tokens corresponding to the specified application.
/// </returns>
Task<ImmutableArray<object>> FindByApplicationIdAsync([NotNull] string identifier, CancellationToken cancellationToken = default);
/// <returns>The tokens corresponding to the specified application.</returns>
IAsyncEnumerable<object> FindByApplicationIdAsync([NotNull] string identifier, CancellationToken cancellationToken = default);
/// <summary>
/// Retrieves the list of tokens corresponding to the specified authorization identifier.
/// </summary>
/// <param name="identifier">The authorization identifier associated with the tokens.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the tokens corresponding to the specified authorization.
/// </returns>
Task<ImmutableArray<object>> FindByAuthorizationIdAsync([NotNull] string identifier, CancellationToken cancellationToken = default);
/// <returns>The tokens corresponding to the specified authorization.</returns>
IAsyncEnumerable<object> FindByAuthorizationIdAsync([NotNull] string identifier, CancellationToken cancellationToken = default);
/// <summary>
/// Retrieves a token using its unique identifier.
@ -154,10 +140,10 @@ namespace OpenIddict.Abstractions
/// <param name="identifier">The unique identifier associated with the token.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the token corresponding to the unique identifier.
/// </returns>
Task<object> FindByIdAsync([NotNull] string identifier, CancellationToken cancellationToken = default);
ValueTask<object> FindByIdAsync([NotNull] string identifier, CancellationToken cancellationToken = default);
/// <summary>
/// Retrieves the list of tokens corresponding to the specified reference identifier.
@ -166,21 +152,18 @@ namespace OpenIddict.Abstractions
/// <param name="identifier">The reference identifier associated with the tokens.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the tokens corresponding to the specified reference identifier.
/// </returns>
Task<object> FindByReferenceIdAsync([NotNull] string identifier, CancellationToken cancellationToken = default);
ValueTask<object> FindByReferenceIdAsync([NotNull] string identifier, CancellationToken cancellationToken = default);
/// <summary>
/// Retrieves the list of tokens corresponding to the specified subject.
/// </summary>
/// <param name="subject">The subject associated with the tokens.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the tokens corresponding to the specified subject.
/// </returns>
Task<ImmutableArray<object>> FindBySubjectAsync([NotNull] string subject, CancellationToken cancellationToken = default);
/// <returns>The tokens corresponding to the specified subject.</returns>
IAsyncEnumerable<object> FindBySubjectAsync([NotNull] string subject, CancellationToken cancellationToken = default);
/// <summary>
/// Retrieves the optional application identifier associated with a token.
@ -200,10 +183,10 @@ namespace OpenIddict.Abstractions
/// <param name="query">The query to execute.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the first element returned when executing the query.
/// </returns>
Task<TResult> GetAsync<TResult>(
ValueTask<TResult> GetAsync<TResult>(
[NotNull] Func<IQueryable<object>, IQueryable<TResult>> query, CancellationToken cancellationToken = default);
/// <summary>
@ -215,10 +198,10 @@ namespace OpenIddict.Abstractions
/// <param name="state">The optional state.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the first element returned when executing the query.
/// </returns>
Task<TResult> GetAsync<TState, TResult>(
ValueTask<TResult> GetAsync<TState, TResult>(
[NotNull] Func<IQueryable<object>, TState, IQueryable<TResult>> query,
[CanBeNull] TState state, CancellationToken cancellationToken = default);
@ -329,7 +312,7 @@ namespace OpenIddict.Abstractions
/// <param name="token">The token.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns><c>true</c> if the token has already been redemeed, <c>false</c> otherwise.</returns>
Task<bool> IsRedeemedAsync([NotNull] object token, CancellationToken cancellationToken = default);
ValueTask<bool> IsRedeemedAsync([NotNull] object token, CancellationToken cancellationToken = default);
/// <summary>
/// Determines whether a given token has been revoked.
@ -337,7 +320,7 @@ namespace OpenIddict.Abstractions
/// <param name="token">The token.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns><c>true</c> if the token has been revoked, <c>false</c> otherwise.</returns>
Task<bool> IsRevokedAsync([NotNull] object token, CancellationToken cancellationToken = default);
ValueTask<bool> IsRevokedAsync([NotNull] object token, CancellationToken cancellationToken = default);
/// <summary>
/// Determines whether a given token is valid.
@ -345,7 +328,7 @@ namespace OpenIddict.Abstractions
/// <param name="token">The token.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns><c>true</c> if the token is valid, <c>false</c> otherwise.</returns>
Task<bool> IsValidAsync([NotNull] object token, CancellationToken cancellationToken = default);
ValueTask<bool> IsValidAsync([NotNull] object token, CancellationToken cancellationToken = default);
/// <summary>
/// Executes the specified query and returns all the corresponding elements.
@ -353,11 +336,8 @@ namespace OpenIddict.Abstractions
/// <param name="count">The number of results to return.</param>
/// <param name="offset">The number of results to skip.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the elements returned when executing the specified query.
/// </returns>
Task<ImmutableArray<object>> ListAsync(
/// <returns>All the elements returned when executing the specified query.</returns>
IAsyncEnumerable<object> ListAsync(
[CanBeNull] int? count = null, [CanBeNull] int? offset = null, CancellationToken cancellationToken = default);
/// <summary>
@ -366,11 +346,8 @@ namespace OpenIddict.Abstractions
/// <typeparam name="TResult">The result type.</typeparam>
/// <param name="query">The query to execute.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the elements returned when executing the specified query.
/// </returns>
Task<ImmutableArray<TResult>> ListAsync<TResult>(
/// <returns>All the elements returned when executing the specified query.</returns>
IAsyncEnumerable<TResult> ListAsync<TResult>(
[NotNull] Func<IQueryable<object>, IQueryable<TResult>> query, CancellationToken cancellationToken = default);
/// <summary>
@ -381,11 +358,8 @@ namespace OpenIddict.Abstractions
/// <param name="query">The query to execute.</param>
/// <param name="state">The optional state.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the elements returned when executing the specified query.
/// </returns>
Task<ImmutableArray<TResult>> ListAsync<TState, TResult>(
/// <returns>All the elements returned when executing the specified query.</returns>
IAsyncEnumerable<TResult> ListAsync<TState, TResult>(
[NotNull] Func<IQueryable<object>, TState, IQueryable<TResult>> query,
[CanBeNull] TState state, CancellationToken cancellationToken = default);
@ -396,9 +370,9 @@ namespace OpenIddict.Abstractions
/// <param name="token">The token.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.
/// </returns>
Task PopulateAsync([NotNull] OpenIddictTokenDescriptor descriptor, [NotNull] object token, CancellationToken cancellationToken = default);
ValueTask PopulateAsync([NotNull] OpenIddictTokenDescriptor descriptor, [NotNull] object token, CancellationToken cancellationToken = default);
/// <summary>
/// Populates the token using the specified descriptor.
@ -407,34 +381,34 @@ namespace OpenIddict.Abstractions
/// <param name="descriptor">The descriptor.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.
/// </returns>
Task PopulateAsync([NotNull] object token, [NotNull] OpenIddictTokenDescriptor descriptor, CancellationToken cancellationToken = default);
ValueTask PopulateAsync([NotNull] object token, [NotNull] OpenIddictTokenDescriptor descriptor, CancellationToken cancellationToken = default);
/// <summary>
/// Removes the tokens that are marked as expired or invalid.
/// </summary>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.
/// </returns>
Task PruneAsync(CancellationToken cancellationToken = default);
ValueTask PruneAsync(CancellationToken cancellationToken = default);
/// <summary>
/// Redeems a token.
/// </summary>
/// <param name="token">The token to redeem.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>A <see cref="Task"/> that can be used to monitor the asynchronous operation.</returns>
Task RedeemAsync([NotNull] object token, CancellationToken cancellationToken = default);
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
ValueTask RedeemAsync([NotNull] object token, CancellationToken cancellationToken = default);
/// <summary>
/// Revokes a token.
/// </summary>
/// <param name="token">The token to revoke.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>A <see cref="Task"/> that can be used to monitor the asynchronous operation.</returns>
Task RevokeAsync([NotNull] object token, CancellationToken cancellationToken = default);
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
ValueTask RevokeAsync([NotNull] object token, CancellationToken cancellationToken = default);
/// <summary>
/// Sets the application identifier associated with a token.
@ -443,9 +417,9 @@ namespace OpenIddict.Abstractions
/// <param name="identifier">The unique identifier associated with the client application.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.
/// </returns>
Task SetApplicationIdAsync([NotNull] object token, [CanBeNull] string identifier, CancellationToken cancellationToken = default);
ValueTask SetApplicationIdAsync([NotNull] object token, [CanBeNull] string identifier, CancellationToken cancellationToken = default);
/// <summary>
/// Sets the authorization identifier associated with a token.
@ -454,9 +428,9 @@ namespace OpenIddict.Abstractions
/// <param name="identifier">The unique identifier associated with the authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.
/// </returns>
Task SetAuthorizationIdAsync([NotNull] object token, [CanBeNull] string identifier, CancellationToken cancellationToken = default);
ValueTask SetAuthorizationIdAsync([NotNull] object token, [CanBeNull] string identifier, CancellationToken cancellationToken = default);
/// <summary>
/// Updates an existing token.
@ -464,9 +438,9 @@ namespace OpenIddict.Abstractions
/// <param name="token">The token to update.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.
/// </returns>
Task UpdateAsync([NotNull] object token, CancellationToken cancellationToken = default);
ValueTask UpdateAsync([NotNull] object token, CancellationToken cancellationToken = default);
/// <summary>
/// Updates an existing token.
@ -475,19 +449,16 @@ namespace OpenIddict.Abstractions
/// <param name="descriptor">The descriptor used to update the token.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.
/// </returns>
Task UpdateAsync([NotNull] object token, [NotNull] OpenIddictTokenDescriptor descriptor, CancellationToken cancellationToken = default);
ValueTask UpdateAsync([NotNull] object token, [NotNull] OpenIddictTokenDescriptor descriptor, CancellationToken cancellationToken = default);
/// <summary>
/// Validates the token to ensure it's in a consistent state.
/// </summary>
/// <param name="token">The token.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the validation error encountered when validating the token.
/// </returns>
Task<ImmutableArray<ValidationResult>> ValidateAsync([NotNull] object token, CancellationToken cancellationToken = default);
/// <returns>The validation error encountered when validating the token.</returns>
IAsyncEnumerable<ValidationResult> ValidateAsync([NotNull] object token, CancellationToken cancellationToken = default);
}
}

121
src/OpenIddict.Abstractions/Stores/IOpenIddictApplicationStore.cs

@ -5,6 +5,7 @@
*/
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Threading;
@ -25,10 +26,10 @@ namespace OpenIddict.Abstractions
/// </summary>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the number of applications in the database.
/// </returns>
Task<long> CountAsync(CancellationToken cancellationToken);
ValueTask<long> CountAsync(CancellationToken cancellationToken);
/// <summary>
/// Determines the number of applications that match the specified query.
@ -37,30 +38,26 @@ namespace OpenIddict.Abstractions
/// <param name="query">The query to execute.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the number of applications that match the specified query.
/// </returns>
Task<long> CountAsync<TResult>([NotNull] Func<IQueryable<TApplication>, IQueryable<TResult>> query, CancellationToken cancellationToken);
ValueTask<long> CountAsync<TResult>([NotNull] Func<IQueryable<TApplication>, IQueryable<TResult>> query, CancellationToken cancellationToken);
/// <summary>
/// Creates a new application.
/// </summary>
/// <param name="application">The application to create.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
Task CreateAsync([NotNull] TApplication application, CancellationToken cancellationToken);
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
ValueTask CreateAsync([NotNull] TApplication application, CancellationToken cancellationToken);
/// <summary>
/// Removes an existing application.
/// </summary>
/// <param name="application">The application to delete.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
Task DeleteAsync([NotNull] TApplication application, CancellationToken cancellationToken);
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
ValueTask DeleteAsync([NotNull] TApplication application, CancellationToken cancellationToken);
/// <summary>
/// Retrieves an application using its unique identifier.
@ -68,10 +65,10 @@ namespace OpenIddict.Abstractions
/// <param name="identifier">The unique identifier associated with the application.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the client application corresponding to the identifier.
/// </returns>
Task<TApplication> FindByIdAsync([NotNull] string identifier, CancellationToken cancellationToken);
ValueTask<TApplication> FindByIdAsync([NotNull] string identifier, CancellationToken cancellationToken);
/// <summary>
/// Retrieves an application using its client identifier.
@ -79,32 +76,26 @@ namespace OpenIddict.Abstractions
/// <param name="identifier">The client identifier associated with the application.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the client application corresponding to the identifier.
/// </returns>
Task<TApplication> FindByClientIdAsync([NotNull] string identifier, CancellationToken cancellationToken);
ValueTask<TApplication> FindByClientIdAsync([NotNull] string identifier, CancellationToken cancellationToken);
/// <summary>
/// Retrieves all the applications associated with the specified post_logout_redirect_uri.
/// </summary>
/// <param name="address">The post_logout_redirect_uri associated with the applications.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation, whose result
/// returns the client applications corresponding to the specified post_logout_redirect_uri.
/// </returns>
Task<ImmutableArray<TApplication>> FindByPostLogoutRedirectUriAsync([NotNull] string address, CancellationToken cancellationToken);
/// <returns>The client applications corresponding to the specified post_logout_redirect_uri.</returns>
IAsyncEnumerable<TApplication> FindByPostLogoutRedirectUriAsync([NotNull] string address, CancellationToken cancellationToken);
/// <summary>
/// Retrieves all the applications associated with the specified redirect_uri.
/// </summary>
/// <param name="address">The redirect_uri associated with the applications.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation, whose result
/// returns the client applications corresponding to the specified redirect_uri.
/// </returns>
Task<ImmutableArray<TApplication>> FindByRedirectUriAsync([NotNull] string address, CancellationToken cancellationToken);
/// <returns>The client applications corresponding to the specified redirect_uri.</returns>
IAsyncEnumerable<TApplication> FindByRedirectUriAsync([NotNull] string address, CancellationToken cancellationToken);
/// <summary>
/// Executes the specified query and returns the first element.
@ -115,10 +106,10 @@ namespace OpenIddict.Abstractions
/// <param name="state">The optional state.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the first element returned when executing the query.
/// </returns>
Task<TResult> GetAsync<TState, TResult>(
ValueTask<TResult> GetAsync<TState, TResult>(
[NotNull] Func<IQueryable<TApplication>, TState, IQueryable<TResult>> query,
[CanBeNull] TState state, CancellationToken cancellationToken);
@ -250,11 +241,8 @@ namespace OpenIddict.Abstractions
/// <param name="count">The number of results to return.</param>
/// <param name="offset">The number of results to skip.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the elements returned when executing the specified query.
/// </returns>
Task<ImmutableArray<TApplication>> ListAsync([CanBeNull] int? count, [CanBeNull] int? offset, CancellationToken cancellationToken);
/// <returns>All the elements returned when executing the specified query.</returns>
IAsyncEnumerable<TApplication> ListAsync([CanBeNull] int? count, [CanBeNull] int? offset, CancellationToken cancellationToken);
/// <summary>
/// Executes the specified query and returns all the corresponding elements.
@ -264,11 +252,8 @@ namespace OpenIddict.Abstractions
/// <param name="query">The query to execute.</param>
/// <param name="state">The optional state.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the elements returned when executing the specified query.
/// </returns>
Task<ImmutableArray<TResult>> ListAsync<TState, TResult>(
/// <returns>All the elements returned when executing the specified query.</returns>
IAsyncEnumerable<TResult> ListAsync<TState, TResult>(
[NotNull] Func<IQueryable<TApplication>, TState, IQueryable<TResult>> query,
[CanBeNull] TState state, CancellationToken cancellationToken);
@ -278,10 +263,8 @@ namespace OpenIddict.Abstractions
/// <param name="application">The application.</param>
/// <param name="identifier">The client identifier associated with the application.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
Task SetClientIdAsync([NotNull] TApplication application, [CanBeNull] string identifier, CancellationToken cancellationToken);
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
ValueTask SetClientIdAsync([NotNull] TApplication application, [CanBeNull] string identifier, CancellationToken cancellationToken);
/// <summary>
/// Sets the client secret associated with an application.
@ -291,10 +274,8 @@ namespace OpenIddict.Abstractions
/// <param name="application">The application.</param>
/// <param name="secret">The client secret associated with the application.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
Task SetClientSecretAsync([NotNull] TApplication application, [CanBeNull] string secret, CancellationToken cancellationToken);
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
ValueTask SetClientSecretAsync([NotNull] TApplication application, [CanBeNull] string secret, CancellationToken cancellationToken);
/// <summary>
/// Sets the client type associated with an application.
@ -302,10 +283,8 @@ namespace OpenIddict.Abstractions
/// <param name="application">The application.</param>
/// <param name="type">The client type associated with the application.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
Task SetClientTypeAsync([NotNull] TApplication application, [CanBeNull] string type, CancellationToken cancellationToken);
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
ValueTask SetClientTypeAsync([NotNull] TApplication application, [CanBeNull] string type, CancellationToken cancellationToken);
/// <summary>
/// Sets the consent type associated with an application.
@ -313,10 +292,8 @@ namespace OpenIddict.Abstractions
/// <param name="application">The application.</param>
/// <param name="type">The consent type associated with the application.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
Task SetConsentTypeAsync([NotNull] TApplication application, [CanBeNull] string type, CancellationToken cancellationToken);
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
ValueTask SetConsentTypeAsync([NotNull] TApplication application, [CanBeNull] string type, CancellationToken cancellationToken);
/// <summary>
/// Sets the display name associated with an application.
@ -324,10 +301,8 @@ namespace OpenIddict.Abstractions
/// <param name="application">The application.</param>
/// <param name="name">The display name associated with the application.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
Task SetDisplayNameAsync([NotNull] TApplication application, [CanBeNull] string name, CancellationToken cancellationToken);
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
ValueTask SetDisplayNameAsync([NotNull] TApplication application, [CanBeNull] string name, CancellationToken cancellationToken);
/// <summary>
/// Sets the permissions associated with an application.
@ -335,10 +310,8 @@ namespace OpenIddict.Abstractions
/// <param name="application">The application.</param>
/// <param name="permissions">The permissions associated with the application </param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
Task SetPermissionsAsync([NotNull] TApplication application, ImmutableArray<string> permissions, CancellationToken cancellationToken);
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
ValueTask SetPermissionsAsync([NotNull] TApplication application, ImmutableArray<string> permissions, CancellationToken cancellationToken);
/// <summary>
/// Sets the logout callback addresses associated with an application.
@ -346,10 +319,8 @@ namespace OpenIddict.Abstractions
/// <param name="application">The application.</param>
/// <param name="addresses">The logout callback addresses associated with the application </param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
Task SetPostLogoutRedirectUrisAsync([NotNull] TApplication application,
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
ValueTask SetPostLogoutRedirectUrisAsync([NotNull] TApplication application,
ImmutableArray<string> addresses, CancellationToken cancellationToken);
/// <summary>
@ -358,10 +329,8 @@ namespace OpenIddict.Abstractions
/// <param name="application">The application.</param>
/// <param name="properties">The additional properties associated with the application.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
Task SetPropertiesAsync([NotNull] TApplication application, [CanBeNull] JObject properties, CancellationToken cancellationToken);
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
ValueTask SetPropertiesAsync([NotNull] TApplication application, [CanBeNull] JObject properties, CancellationToken cancellationToken);
/// <summary>
/// Sets the callback addresses associated with an application.
@ -369,10 +338,8 @@ namespace OpenIddict.Abstractions
/// <param name="application">The application.</param>
/// <param name="addresses">The callback addresses associated with the application </param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
Task SetRedirectUrisAsync([NotNull] TApplication application,
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
ValueTask SetRedirectUrisAsync([NotNull] TApplication application,
ImmutableArray<string> addresses, CancellationToken cancellationToken);
/// <summary>
@ -380,9 +347,7 @@ namespace OpenIddict.Abstractions
/// </summary>
/// <param name="application">The application to update.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
Task UpdateAsync([NotNull] TApplication application, CancellationToken cancellationToken);
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
ValueTask UpdateAsync([NotNull] TApplication application, CancellationToken cancellationToken);
}
}

134
src/OpenIddict.Abstractions/Stores/IOpenIddictAuthorizationStore.cs

@ -5,6 +5,7 @@
*/
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Threading;
@ -25,10 +26,10 @@ namespace OpenIddict.Abstractions
/// </summary>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the number of authorizations in the database.
/// </returns>
Task<long> CountAsync(CancellationToken cancellationToken);
ValueTask<long> CountAsync(CancellationToken cancellationToken);
/// <summary>
/// Determines the number of authorizations that match the specified query.
@ -37,30 +38,26 @@ namespace OpenIddict.Abstractions
/// <param name="query">The query to execute.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the number of authorizations that match the specified query.
/// </returns>
Task<long> CountAsync<TResult>([NotNull] Func<IQueryable<TAuthorization>, IQueryable<TResult>> query, CancellationToken cancellationToken);
ValueTask<long> CountAsync<TResult>([NotNull] Func<IQueryable<TAuthorization>, IQueryable<TResult>> query, CancellationToken cancellationToken);
/// <summary>
/// Creates a new authorization.
/// </summary>
/// <param name="authorization">The authorization to create.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
Task CreateAsync([NotNull] TAuthorization authorization, CancellationToken cancellationToken);
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
ValueTask CreateAsync([NotNull] TAuthorization authorization, CancellationToken cancellationToken);
/// <summary>
/// Removes an existing authorization.
/// </summary>
/// <param name="authorization">The authorization to delete.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
Task DeleteAsync([NotNull] TAuthorization authorization, CancellationToken cancellationToken);
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
ValueTask DeleteAsync([NotNull] TAuthorization authorization, CancellationToken cancellationToken);
/// <summary>
/// Retrieves the authorizations corresponding to the specified
@ -69,12 +66,8 @@ namespace OpenIddict.Abstractions
/// <param name="subject">The subject associated with the authorization.</param>
/// <param name="client">The client associated with the authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the authorizations corresponding to the subject/client.
/// </returns>
Task<ImmutableArray<TAuthorization>> FindAsync(
[NotNull] string subject, [NotNull] string client, CancellationToken cancellationToken);
/// <returns>The authorizations corresponding to the subject/client.</returns>
IAsyncEnumerable<TAuthorization> FindAsync([NotNull] string subject, [NotNull] string client, CancellationToken cancellationToken);
/// <summary>
/// Retrieves the authorizations matching the specified parameters.
@ -83,11 +76,8 @@ namespace OpenIddict.Abstractions
/// <param name="client">The client associated with the authorization.</param>
/// <param name="status">The authorization status.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the authorizations corresponding to the criteria.
/// </returns>
Task<ImmutableArray<TAuthorization>> FindAsync(
/// <returns>The authorizations corresponding to the criteria.</returns>
IAsyncEnumerable<TAuthorization> FindAsync(
[NotNull] string subject, [NotNull] string client,
[NotNull] string status, CancellationToken cancellationToken);
@ -99,11 +89,8 @@ namespace OpenIddict.Abstractions
/// <param name="status">The authorization status.</param>
/// <param name="type">The authorization type.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the authorizations corresponding to the criteria.
/// </returns>
Task<ImmutableArray<TAuthorization>> FindAsync(
/// <returns>The authorizations corresponding to the criteria.</returns>
IAsyncEnumerable<TAuthorization> FindAsync(
[NotNull] string subject, [NotNull] string client,
[NotNull] string status, [NotNull] string type, CancellationToken cancellationToken);
@ -116,11 +103,8 @@ namespace OpenIddict.Abstractions
/// <param name="type">The authorization type.</param>
/// <param name="scopes">The minimal scopes associated with the authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the authorizations corresponding to the criteria.
/// </returns>
Task<ImmutableArray<TAuthorization>> FindAsync(
/// <returns>The authorizations corresponding to the criteria.</returns>
IAsyncEnumerable<TAuthorization> FindAsync(
[NotNull] string subject, [NotNull] string client,
[NotNull] string status, [NotNull] string type,
ImmutableArray<string> scopes, CancellationToken cancellationToken);
@ -130,11 +114,8 @@ namespace OpenIddict.Abstractions
/// </summary>
/// <param name="identifier">The application identifier associated with the authorizations.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the authorizations corresponding to the specified application.
/// </returns>
Task<ImmutableArray<TAuthorization>> FindByApplicationIdAsync([NotNull] string identifier, CancellationToken cancellationToken);
/// <returns>The authorizations corresponding to the specified application.</returns>
IAsyncEnumerable<TAuthorization> FindByApplicationIdAsync([NotNull] string identifier, CancellationToken cancellationToken);
/// <summary>
/// Retrieves an authorization using its unique identifier.
@ -142,21 +123,18 @@ namespace OpenIddict.Abstractions
/// <param name="identifier">The unique identifier associated with the authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the authorization corresponding to the identifier.
/// </returns>
Task<TAuthorization> FindByIdAsync([NotNull] string identifier, CancellationToken cancellationToken);
ValueTask<TAuthorization> FindByIdAsync([NotNull] string identifier, CancellationToken cancellationToken);
/// <summary>
/// Retrieves all the authorizations corresponding to the specified subject.
/// </summary>
/// <param name="subject">The subject associated with the authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the authorizations corresponding to the specified subject.
/// </returns>
Task<ImmutableArray<TAuthorization>> FindBySubjectAsync([NotNull] string subject, CancellationToken cancellationToken);
/// <returns>The authorizations corresponding to the specified subject.</returns>
IAsyncEnumerable<TAuthorization> FindBySubjectAsync([NotNull] string subject, CancellationToken cancellationToken);
/// <summary>
/// Retrieves the optional application identifier associated with an authorization.
@ -178,10 +156,10 @@ namespace OpenIddict.Abstractions
/// <param name="state">The optional state.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the first element returned when executing the query.
/// </returns>
Task<TResult> GetAsync<TState, TResult>(
ValueTask<TResult> GetAsync<TState, TResult>(
[NotNull] Func<IQueryable<TAuthorization>, TState, IQueryable<TResult>> query,
[CanBeNull] TState state, CancellationToken cancellationToken);
@ -267,11 +245,8 @@ namespace OpenIddict.Abstractions
/// <param name="count">The number of results to return.</param>
/// <param name="offset">The number of results to skip.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the elements returned when executing the specified query.
/// </returns>
Task<ImmutableArray<TAuthorization>> ListAsync([CanBeNull] int? count, [CanBeNull] int? offset, CancellationToken cancellationToken);
/// <returns>All the elements returned when executing the specified query.</returns>
IAsyncEnumerable<TAuthorization> ListAsync([CanBeNull] int? count, [CanBeNull] int? offset, CancellationToken cancellationToken);
/// <summary>
/// Executes the specified query and returns all the corresponding elements.
@ -281,11 +256,8 @@ namespace OpenIddict.Abstractions
/// <param name="query">The query to execute.</param>
/// <param name="state">The optional state.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the elements returned when executing the specified query.
/// </returns>
Task<ImmutableArray<TResult>> ListAsync<TState, TResult>(
/// <returns>All the elements returned when executing the specified query.</returns>
IAsyncEnumerable<TResult> ListAsync<TState, TResult>(
[NotNull] Func<IQueryable<TAuthorization>, TState, IQueryable<TResult>> query,
[CanBeNull] TState state, CancellationToken cancellationToken);
@ -293,10 +265,8 @@ namespace OpenIddict.Abstractions
/// Removes the authorizations that are marked as invalid and the ad-hoc ones that have no valid/nonexpired token attached.
/// </summary>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
Task PruneAsync(CancellationToken cancellationToken);
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
ValueTask PruneAsync(CancellationToken cancellationToken);
/// <summary>
/// Sets the application identifier associated with an authorization.
@ -304,10 +274,8 @@ namespace OpenIddict.Abstractions
/// <param name="authorization">The authorization.</param>
/// <param name="identifier">The unique identifier associated with the client application.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
Task SetApplicationIdAsync([NotNull] TAuthorization authorization,
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
ValueTask SetApplicationIdAsync([NotNull] TAuthorization authorization,
[CanBeNull] string identifier, CancellationToken cancellationToken);
/// <summary>
@ -316,10 +284,8 @@ namespace OpenIddict.Abstractions
/// <param name="authorization">The authorization.</param>
/// <param name="properties">The additional properties associated with the authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
Task SetPropertiesAsync([NotNull] TAuthorization authorization, [CanBeNull] JObject properties, CancellationToken cancellationToken);
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
ValueTask SetPropertiesAsync([NotNull] TAuthorization authorization, [CanBeNull] JObject properties, CancellationToken cancellationToken);
/// <summary>
/// Sets the scopes associated with an authorization.
@ -327,10 +293,8 @@ namespace OpenIddict.Abstractions
/// <param name="authorization">The authorization.</param>
/// <param name="scopes">The scopes associated with the authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
Task SetScopesAsync([NotNull] TAuthorization authorization,
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
ValueTask SetScopesAsync([NotNull] TAuthorization authorization,
ImmutableArray<string> scopes, CancellationToken cancellationToken);
/// <summary>
@ -339,10 +303,8 @@ namespace OpenIddict.Abstractions
/// <param name="authorization">The authorization.</param>
/// <param name="status">The status associated with the authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
Task SetStatusAsync([NotNull] TAuthorization authorization,
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
ValueTask SetStatusAsync([NotNull] TAuthorization authorization,
[CanBeNull] string status, CancellationToken cancellationToken);
/// <summary>
@ -351,10 +313,8 @@ namespace OpenIddict.Abstractions
/// <param name="authorization">The authorization.</param>
/// <param name="subject">The subject associated with the authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
Task SetSubjectAsync([NotNull] TAuthorization authorization,
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
ValueTask SetSubjectAsync([NotNull] TAuthorization authorization,
[CanBeNull] string subject, CancellationToken cancellationToken);
/// <summary>
@ -363,10 +323,8 @@ namespace OpenIddict.Abstractions
/// <param name="authorization">The authorization.</param>
/// <param name="type">The type associated with the authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
Task SetTypeAsync([NotNull] TAuthorization authorization,
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
ValueTask SetTypeAsync([NotNull] TAuthorization authorization,
[CanBeNull] string type, CancellationToken cancellationToken);
/// <summary>
@ -374,9 +332,7 @@ namespace OpenIddict.Abstractions
/// </summary>
/// <param name="authorization">The authorization to update.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
Task UpdateAsync([NotNull] TAuthorization authorization, CancellationToken cancellationToken);
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
ValueTask UpdateAsync([NotNull] TAuthorization authorization, CancellationToken cancellationToken);
}
}

97
src/OpenIddict.Abstractions/Stores/IOpenIddictScopeStore.cs

@ -5,6 +5,7 @@
*/
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Threading;
@ -25,10 +26,10 @@ namespace OpenIddict.Abstractions
/// </summary>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the number of scopes in the database.
/// </returns>
Task<long> CountAsync(CancellationToken cancellationToken);
ValueTask<long> CountAsync(CancellationToken cancellationToken);
/// <summary>
/// Determines the number of scopes that match the specified query.
@ -37,30 +38,26 @@ namespace OpenIddict.Abstractions
/// <param name="query">The query to execute.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the number of scopes that match the specified query.
/// </returns>
Task<long> CountAsync<TResult>([NotNull] Func<IQueryable<TScope>, IQueryable<TResult>> query, CancellationToken cancellationToken);
ValueTask<long> CountAsync<TResult>([NotNull] Func<IQueryable<TScope>, IQueryable<TResult>> query, CancellationToken cancellationToken);
/// <summary>
/// Creates a new scope.
/// </summary>
/// <param name="scope">The scope to create.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
Task CreateAsync([NotNull] TScope scope, CancellationToken cancellationToken);
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
ValueTask CreateAsync([NotNull] TScope scope, CancellationToken cancellationToken);
/// <summary>
/// Removes an existing scope.
/// </summary>
/// <param name="scope">The scope to delete.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
Task DeleteAsync([NotNull] TScope scope, CancellationToken cancellationToken);
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
ValueTask DeleteAsync([NotNull] TScope scope, CancellationToken cancellationToken);
/// <summary>
/// Retrieves a scope using its unique identifier.
@ -68,10 +65,10 @@ namespace OpenIddict.Abstractions
/// <param name="identifier">The unique identifier associated with the scope.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the scope corresponding to the identifier.
/// </returns>
Task<TScope> FindByIdAsync([NotNull] string identifier, CancellationToken cancellationToken);
ValueTask<TScope> FindByIdAsync([NotNull] string identifier, CancellationToken cancellationToken);
/// <summary>
/// Retrieves a scope using its name.
@ -79,32 +76,26 @@ namespace OpenIddict.Abstractions
/// <param name="name">The name associated with the scope.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the scope corresponding to the specified name.
/// </returns>
Task<TScope> FindByNameAsync([NotNull] string name, CancellationToken cancellationToken);
ValueTask<TScope> FindByNameAsync([NotNull] string name, CancellationToken cancellationToken);
/// <summary>
/// Retrieves a list of scopes using their name.
/// </summary>
/// <param name="names">The names associated with the scopes.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the scopes corresponding to the specified names.
/// </returns>
Task<ImmutableArray<TScope>> FindByNamesAsync(ImmutableArray<string> names, CancellationToken cancellationToken);
/// <returns>The scopes corresponding to the specified names.</returns>
IAsyncEnumerable<TScope> FindByNamesAsync(ImmutableArray<string> names, CancellationToken cancellationToken);
/// <summary>
/// Retrieves all the scopes that contain the specified resource.
/// </summary>
/// <param name="resource">The resource associated with the scopes.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the scopes associated with the specified resource.
/// </returns>
Task<ImmutableArray<TScope>> FindByResourceAsync([NotNull] string resource, CancellationToken cancellationToken);
/// <returns>The scopes associated with the specified resource.</returns>
IAsyncEnumerable<TScope> FindByResourceAsync([NotNull] string resource, CancellationToken cancellationToken);
/// <summary>
/// Executes the specified query and returns the first element.
@ -115,10 +106,10 @@ namespace OpenIddict.Abstractions
/// <param name="state">The optional state.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the first element returned when executing the query.
/// </returns>
Task<TResult> GetAsync<TState, TResult>(
ValueTask<TResult> GetAsync<TState, TResult>(
[NotNull] Func<IQueryable<TScope>, TState, IQueryable<TResult>> query,
[CanBeNull] TState state, CancellationToken cancellationToken);
@ -204,11 +195,8 @@ namespace OpenIddict.Abstractions
/// <param name="count">The number of results to return.</param>
/// <param name="offset">The number of results to skip.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the elements returned when executing the specified query.
/// </returns>
Task<ImmutableArray<TScope>> ListAsync([CanBeNull] int? count, [CanBeNull] int? offset, CancellationToken cancellationToken);
/// <returns>All the elements returned when executing the specified query.</returns>
IAsyncEnumerable<TScope> ListAsync([CanBeNull] int? count, [CanBeNull] int? offset, CancellationToken cancellationToken);
/// <summary>
/// Executes the specified query and returns all the corresponding elements.
@ -218,11 +206,8 @@ namespace OpenIddict.Abstractions
/// <param name="query">The query to execute.</param>
/// <param name="state">The optional state.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the elements returned when executing the specified query.
/// </returns>
Task<ImmutableArray<TResult>> ListAsync<TState, TResult>(
/// <returns>All the elements returned when executing the specified query.</returns>
IAsyncEnumerable<TResult> ListAsync<TState, TResult>(
[NotNull] Func<IQueryable<TScope>, TState, IQueryable<TResult>> query,
[CanBeNull] TState state, CancellationToken cancellationToken);
@ -232,10 +217,8 @@ namespace OpenIddict.Abstractions
/// <param name="scope">The scope.</param>
/// <param name="description">The description associated with the authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
Task SetDescriptionAsync([NotNull] TScope scope, [CanBeNull] string description, CancellationToken cancellationToken);
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
ValueTask SetDescriptionAsync([NotNull] TScope scope, [CanBeNull] string description, CancellationToken cancellationToken);
/// <summary>
/// Sets the display name associated with a scope.
@ -243,10 +226,8 @@ namespace OpenIddict.Abstractions
/// <param name="scope">The scope.</param>
/// <param name="name">The display name associated with the scope.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
Task SetDisplayNameAsync([NotNull] TScope scope, [CanBeNull] string name, CancellationToken cancellationToken);
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
ValueTask SetDisplayNameAsync([NotNull] TScope scope, [CanBeNull] string name, CancellationToken cancellationToken);
/// <summary>
/// Sets the name associated with a scope.
@ -254,10 +235,8 @@ namespace OpenIddict.Abstractions
/// <param name="scope">The scope.</param>
/// <param name="name">The name associated with the authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
Task SetNameAsync([NotNull] TScope scope, [CanBeNull] string name, CancellationToken cancellationToken);
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
ValueTask SetNameAsync([NotNull] TScope scope, [CanBeNull] string name, CancellationToken cancellationToken);
/// <summary>
/// Sets the additional properties associated with a scope.
@ -265,10 +244,8 @@ namespace OpenIddict.Abstractions
/// <param name="scope">The scope.</param>
/// <param name="properties">The additional properties associated with the scope.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
Task SetPropertiesAsync([NotNull] TScope scope, [CanBeNull] JObject properties, CancellationToken cancellationToken);
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
ValueTask SetPropertiesAsync([NotNull] TScope scope, [CanBeNull] JObject properties, CancellationToken cancellationToken);
/// <summary>
/// Sets the resources associated with a scope.
@ -276,19 +253,15 @@ namespace OpenIddict.Abstractions
/// <param name="scope">The scope.</param>
/// <param name="resources">The resources associated with the scope.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
Task SetResourcesAsync([NotNull] TScope scope, ImmutableArray<string> resources, CancellationToken cancellationToken);
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
ValueTask SetResourcesAsync([NotNull] TScope scope, ImmutableArray<string> resources, CancellationToken cancellationToken);
/// <summary>
/// Updates an existing scope.
/// </summary>
/// <param name="scope">The scope to update.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
Task UpdateAsync([NotNull] TScope scope, CancellationToken cancellationToken);
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
ValueTask UpdateAsync([NotNull] TScope scope, CancellationToken cancellationToken);
}
}

159
src/OpenIddict.Abstractions/Stores/IOpenIddictTokenStore.cs

@ -5,6 +5,7 @@
*/
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Threading;
@ -25,10 +26,10 @@ namespace OpenIddict.Abstractions
/// </summary>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the number of applications in the database.
/// </returns>
Task<long> CountAsync(CancellationToken cancellationToken);
ValueTask<long> CountAsync(CancellationToken cancellationToken);
/// <summary>
/// Determines the number of tokens that match the specified query.
@ -37,28 +38,26 @@ namespace OpenIddict.Abstractions
/// <param name="query">The query to execute.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the number of tokens that match the specified query.
/// </returns>
Task<long> CountAsync<TResult>([NotNull] Func<IQueryable<TToken>, IQueryable<TResult>> query, CancellationToken cancellationToken);
ValueTask<long> CountAsync<TResult>([NotNull] Func<IQueryable<TToken>, IQueryable<TResult>> query, CancellationToken cancellationToken);
/// <summary>
/// Creates a new token.
/// </summary>
/// <param name="token">The token to create.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
Task CreateAsync([NotNull] TToken token, CancellationToken cancellationToken);
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
ValueTask CreateAsync([NotNull] TToken token, CancellationToken cancellationToken);
/// <summary>
/// Removes a token.
/// </summary>
/// <param name="token">The token to delete.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>A <see cref="Task"/> that can be used to monitor the asynchronous operation.</returns>
Task DeleteAsync([NotNull] TToken token, CancellationToken cancellationToken);
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
ValueTask DeleteAsync([NotNull] TToken token, CancellationToken cancellationToken);
/// <summary>
/// Retrieves the tokens corresponding to the specified
@ -67,11 +66,8 @@ namespace OpenIddict.Abstractions
/// <param name="subject">The subject associated with the token.</param>
/// <param name="client">The client associated with the token.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the tokens corresponding to the subject/client.
/// </returns>
Task<ImmutableArray<TToken>> FindAsync([NotNull] string subject, [NotNull] string client, CancellationToken cancellationToken);
/// <returns>The tokens corresponding to the subject/client.</returns>
IAsyncEnumerable<TToken> FindAsync([NotNull] string subject, [NotNull] string client, CancellationToken cancellationToken);
/// <summary>
/// Retrieves the tokens matching the specified parameters.
@ -80,11 +76,8 @@ namespace OpenIddict.Abstractions
/// <param name="client">The client associated with the token.</param>
/// <param name="status">The token status.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the tokens corresponding to the criteria.
/// </returns>
Task<ImmutableArray<TToken>> FindAsync(
/// <returns>The tokens corresponding to the criteria.</returns>
IAsyncEnumerable<TToken> FindAsync(
[NotNull] string subject, [NotNull] string client,
[NotNull] string status, CancellationToken cancellationToken);
@ -96,11 +89,8 @@ namespace OpenIddict.Abstractions
/// <param name="status">The token status.</param>
/// <param name="type">The token type.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the tokens corresponding to the criteria.
/// </returns>
Task<ImmutableArray<TToken>> FindAsync(
/// <returns>The tokens corresponding to the criteria.</returns>
IAsyncEnumerable<TToken> FindAsync(
[NotNull] string subject, [NotNull] string client,
[NotNull] string status, [NotNull] string type, CancellationToken cancellationToken);
@ -109,22 +99,16 @@ namespace OpenIddict.Abstractions
/// </summary>
/// <param name="identifier">The application identifier associated with the tokens.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the tokens corresponding to the specified application.
/// </returns>
Task<ImmutableArray<TToken>> FindByApplicationIdAsync([NotNull] string identifier, CancellationToken cancellationToken);
/// <returns>The tokens corresponding to the specified application.</returns>
IAsyncEnumerable<TToken> FindByApplicationIdAsync([NotNull] string identifier, CancellationToken cancellationToken);
/// <summary>
/// Retrieves the list of tokens corresponding to the specified authorization identifier.
/// </summary>
/// <param name="identifier">The authorization identifier associated with the tokens.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the tokens corresponding to the specified authorization.
/// </returns>
Task<ImmutableArray<TToken>> FindByAuthorizationIdAsync([NotNull] string identifier, CancellationToken cancellationToken);
/// <returns>The tokens corresponding to the specified authorization.</returns>
IAsyncEnumerable<TToken> FindByAuthorizationIdAsync([NotNull] string identifier, CancellationToken cancellationToken);
/// <summary>
/// Retrieves a token using its unique identifier.
@ -132,10 +116,10 @@ namespace OpenIddict.Abstractions
/// <param name="identifier">The unique identifier associated with the token.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the token corresponding to the unique identifier.
/// </returns>
Task<TToken> FindByIdAsync([NotNull] string identifier, CancellationToken cancellationToken);
ValueTask<TToken> FindByIdAsync([NotNull] string identifier, CancellationToken cancellationToken);
/// <summary>
/// Retrieves the list of tokens corresponding to the specified reference identifier.
@ -144,21 +128,18 @@ namespace OpenIddict.Abstractions
/// <param name="identifier">The reference identifier associated with the tokens.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the tokens corresponding to the specified reference identifier.
/// </returns>
Task<TToken> FindByReferenceIdAsync([NotNull] string identifier, CancellationToken cancellationToken);
ValueTask<TToken> FindByReferenceIdAsync([NotNull] string identifier, CancellationToken cancellationToken);
/// <summary>
/// Retrieves the list of tokens corresponding to the specified subject.
/// </summary>
/// <param name="subject">The subject associated with the tokens.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the tokens corresponding to the specified subject.
/// </returns>
Task<ImmutableArray<TToken>> FindBySubjectAsync([NotNull] string subject, CancellationToken cancellationToken);
/// <returns>The tokens corresponding to the specified subject.</returns>
IAsyncEnumerable<TToken> FindBySubjectAsync([NotNull] string subject, CancellationToken cancellationToken);
/// <summary>
/// Retrieves the optional application identifier associated with a token.
@ -180,10 +161,10 @@ namespace OpenIddict.Abstractions
/// <param name="state">The optional state.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the first element returned when executing the query.
/// </returns>
Task<TResult> GetAsync<TState, TResult>(
ValueTask<TResult> GetAsync<TState, TResult>(
[NotNull] Func<IQueryable<TToken>, TState, IQueryable<TResult>> query,
[CanBeNull] TState state, CancellationToken cancellationToken);
@ -315,11 +296,8 @@ namespace OpenIddict.Abstractions
/// <param name="count">The number of results to return.</param>
/// <param name="offset">The number of results to skip.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the elements returned when executing the specified query.
/// </returns>
Task<ImmutableArray<TToken>> ListAsync([CanBeNull] int? count, [CanBeNull] int? offset, CancellationToken cancellationToken);
/// <returns>All the elements returned when executing the specified query.</returns>
IAsyncEnumerable<TToken> ListAsync([CanBeNull] int? count, [CanBeNull] int? offset, CancellationToken cancellationToken);
/// <summary>
/// Executes the specified query and returns all the corresponding elements.
@ -329,11 +307,8 @@ namespace OpenIddict.Abstractions
/// <param name="query">The query to execute.</param>
/// <param name="state">The optional state.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the elements returned when executing the specified query.
/// </returns>
Task<ImmutableArray<TResult>> ListAsync<TState, TResult>(
/// <returns>All the elements returned when executing the specified query.</returns>
IAsyncEnumerable<TResult> ListAsync<TState, TResult>(
[NotNull] Func<IQueryable<TToken>, TState, IQueryable<TResult>> query,
[CanBeNull] TState state, CancellationToken cancellationToken);
@ -341,10 +316,8 @@ namespace OpenIddict.Abstractions
/// Removes the tokens that are marked as expired or invalid.
/// </summary>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
Task PruneAsync(CancellationToken cancellationToken);
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
ValueTask PruneAsync(CancellationToken cancellationToken);
/// <summary>
/// Sets the application identifier associated with a token.
@ -352,10 +325,8 @@ namespace OpenIddict.Abstractions
/// <param name="token">The token.</param>
/// <param name="identifier">The unique identifier associated with the token.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
Task SetApplicationIdAsync([NotNull] TToken token, [CanBeNull] string identifier, CancellationToken cancellationToken);
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
ValueTask SetApplicationIdAsync([NotNull] TToken token, [CanBeNull] string identifier, CancellationToken cancellationToken);
/// <summary>
/// Sets the authorization identifier associated with a token.
@ -363,10 +334,8 @@ namespace OpenIddict.Abstractions
/// <param name="token">The token.</param>
/// <param name="identifier">The unique identifier associated with the token.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
Task SetAuthorizationIdAsync([NotNull] TToken token, [CanBeNull] string identifier, CancellationToken cancellationToken);
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
ValueTask SetAuthorizationIdAsync([NotNull] TToken token, [CanBeNull] string identifier, CancellationToken cancellationToken);
/// <summary>
/// Sets the creation date associated with a token.
@ -374,10 +343,8 @@ namespace OpenIddict.Abstractions
/// <param name="token">The token.</param>
/// <param name="date">The creation date.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
Task SetCreationDateAsync([NotNull] TToken token, [CanBeNull] DateTimeOffset? date, CancellationToken cancellationToken);
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
ValueTask SetCreationDateAsync([NotNull] TToken token, [CanBeNull] DateTimeOffset? date, CancellationToken cancellationToken);
/// <summary>
/// Sets the expiration date associated with a token.
@ -385,10 +352,8 @@ namespace OpenIddict.Abstractions
/// <param name="token">The token.</param>
/// <param name="date">The expiration date.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
Task SetExpirationDateAsync([NotNull] TToken token, [CanBeNull] DateTimeOffset? date, CancellationToken cancellationToken);
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
ValueTask SetExpirationDateAsync([NotNull] TToken token, [CanBeNull] DateTimeOffset? date, CancellationToken cancellationToken);
/// <summary>
/// Sets the payload associated with a token.
@ -396,10 +361,8 @@ namespace OpenIddict.Abstractions
/// <param name="token">The token.</param>
/// <param name="payload">The payload associated with the token.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
Task SetPayloadAsync([NotNull] TToken token, [CanBeNull] string payload, CancellationToken cancellationToken);
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
ValueTask SetPayloadAsync([NotNull] TToken token, [CanBeNull] string payload, CancellationToken cancellationToken);
/// <summary>
/// Sets the additional properties associated with a token.
@ -407,10 +370,8 @@ namespace OpenIddict.Abstractions
/// <param name="token">The token.</param>
/// <param name="properties">The additional properties associated with the token.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
Task SetPropertiesAsync([NotNull] TToken token, [CanBeNull] JObject properties, CancellationToken cancellationToken);
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
ValueTask SetPropertiesAsync([NotNull] TToken token, [CanBeNull] JObject properties, CancellationToken cancellationToken);
/// <summary>
/// Sets the reference identifier associated with a token.
@ -420,10 +381,8 @@ namespace OpenIddict.Abstractions
/// <param name="token">The token.</param>
/// <param name="identifier">The reference identifier associated with the token.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
Task SetReferenceIdAsync([NotNull] TToken token, [CanBeNull] string identifier, CancellationToken cancellationToken);
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
ValueTask SetReferenceIdAsync([NotNull] TToken token, [CanBeNull] string identifier, CancellationToken cancellationToken);
/// <summary>
/// Sets the status associated with a token.
@ -431,10 +390,8 @@ namespace OpenIddict.Abstractions
/// <param name="token">The token.</param>
/// <param name="status">The status associated with the authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
Task SetStatusAsync([NotNull] TToken token, [CanBeNull] string status, CancellationToken cancellationToken);
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
ValueTask SetStatusAsync([NotNull] TToken token, [CanBeNull] string status, CancellationToken cancellationToken);
/// <summary>
/// Sets the subject associated with a token.
@ -442,10 +399,8 @@ namespace OpenIddict.Abstractions
/// <param name="token">The token.</param>
/// <param name="subject">The subject associated with the token.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
Task SetSubjectAsync([NotNull] TToken token, [CanBeNull] string subject, CancellationToken cancellationToken);
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
ValueTask SetSubjectAsync([NotNull] TToken token, [CanBeNull] string subject, CancellationToken cancellationToken);
/// <summary>
/// Sets the token type associated with a token.
@ -453,19 +408,15 @@ namespace OpenIddict.Abstractions
/// <param name="token">The token.</param>
/// <param name="type">The token type associated with the token.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
Task SetTypeAsync([NotNull] TToken token, [CanBeNull] string type, CancellationToken cancellationToken);
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
ValueTask SetTypeAsync([NotNull] TToken token, [CanBeNull] string type, CancellationToken cancellationToken);
/// <summary>
/// Updates an existing token.
/// </summary>
/// <param name="token">The token to update.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
Task UpdateAsync([NotNull] TToken token, CancellationToken cancellationToken);
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
ValueTask UpdateAsync([NotNull] TToken token, CancellationToken cancellationToken);
}
}

64
src/OpenIddict.Core/Caches/OpenIddictApplicationCache.cs

@ -6,7 +6,9 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using JetBrains.Annotations;
@ -45,10 +47,8 @@ namespace OpenIddict.Core
/// </summary>
/// <param name="application">The application to add to the cache.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public async Task AddAsync([NotNull] TApplication application, CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public async ValueTask AddAsync([NotNull] TApplication application, CancellationToken cancellationToken)
{
if (application == null)
{
@ -246,11 +246,8 @@ namespace OpenIddict.Core
/// </summary>
/// <param name="address">The post_logout_redirect_uri associated with the applications.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
/// whose result returns the client applications corresponding to the specified post_logout_redirect_uri.
/// </returns>
public ValueTask<ImmutableArray<TApplication>> FindByPostLogoutRedirectUriAsync(
/// <returns>The client applications corresponding to the specified post_logout_redirect_uri.</returns>
public IAsyncEnumerable<TApplication> FindByPostLogoutRedirectUriAsync(
[NotNull] string address, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(address))
@ -266,12 +263,15 @@ namespace OpenIddict.Core
if (_cache.TryGetValue(parameters, out ImmutableArray<TApplication> applications))
{
return new ValueTask<ImmutableArray<TApplication>>(applications);
return applications.ToAsyncEnumerable();
}
async Task<ImmutableArray<TApplication>> ExecuteAsync()
async IAsyncEnumerable<TApplication> ExecuteAsync()
{
foreach (var application in (applications = await _store.FindByPostLogoutRedirectUriAsync(address, cancellationToken)))
var applications = ImmutableArray.CreateRange(await _store.FindByPostLogoutRedirectUriAsync(
address, cancellationToken).ToListAsync(cancellationToken));
foreach (var application in applications)
{
await AddAsync(application, cancellationToken);
}
@ -293,10 +293,13 @@ namespace OpenIddict.Core
entry.SetValue(applications);
}
return applications;
foreach (var application in applications)
{
yield return application;
}
}
return new ValueTask<ImmutableArray<TApplication>>(ExecuteAsync());
return ExecuteAsync();
}
/// <summary>
@ -304,11 +307,8 @@ namespace OpenIddict.Core
/// </summary>
/// <param name="address">The redirect_uri associated with the applications.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
/// whose result returns the client applications corresponding to the specified redirect_uri.
/// </returns>
public ValueTask<ImmutableArray<TApplication>> FindByRedirectUriAsync(
/// <returns>The client applications corresponding to the specified redirect_uri.</returns>
public IAsyncEnumerable<TApplication> FindByRedirectUriAsync(
[NotNull] string address, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(address))
@ -324,12 +324,15 @@ namespace OpenIddict.Core
if (_cache.TryGetValue(parameters, out ImmutableArray<TApplication> applications))
{
return new ValueTask<ImmutableArray<TApplication>>(applications);
return applications.ToAsyncEnumerable();
}
async Task<ImmutableArray<TApplication>> ExecuteAsync()
async IAsyncEnumerable<TApplication> ExecuteAsync()
{
foreach (var application in (applications = await _store.FindByRedirectUriAsync(address, cancellationToken)))
var applications = ImmutableArray.CreateRange(await _store.FindByRedirectUriAsync(
address, cancellationToken).ToListAsync(cancellationToken));
foreach (var application in applications)
{
await AddAsync(application, cancellationToken);
}
@ -351,10 +354,13 @@ namespace OpenIddict.Core
entry.SetValue(applications);
}
return applications;
foreach (var application in applications)
{
yield return application;
}
}
return new ValueTask<ImmutableArray<TApplication>>(ExecuteAsync());
return ExecuteAsync();
}
/// <summary>
@ -362,10 +368,8 @@ namespace OpenIddict.Core
/// </summary>
/// <param name="application">The application to remove from the cache.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public async Task RemoveAsync([NotNull] TApplication application, CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public async ValueTask RemoveAsync([NotNull] TApplication application, CancellationToken cancellationToken)
{
if (application == null)
{
@ -391,10 +395,10 @@ namespace OpenIddict.Core
/// <param name="application">The application associated with the expiration signal.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns an expiration signal for the specified application.
/// </returns>
protected virtual async Task<IChangeToken> CreateExpirationSignalAsync(
protected virtual async ValueTask<IChangeToken> CreateExpirationSignalAsync(
[NotNull] TApplication application, CancellationToken cancellationToken)
{
if (application == null)

150
src/OpenIddict.Core/Caches/OpenIddictAuthorizationCache.cs

@ -6,7 +6,9 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using JetBrains.Annotations;
@ -46,9 +48,9 @@ namespace OpenIddict.Core
/// <param name="authorization">The authorization to add to the cache.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.
/// </returns>
public async Task AddAsync(TAuthorization authorization, CancellationToken cancellationToken)
public async ValueTask AddAsync(TAuthorization authorization, CancellationToken cancellationToken)
{
if (authorization == null)
{
@ -135,11 +137,8 @@ namespace OpenIddict.Core
/// <param name="subject">The subject associated with the authorization.</param>
/// <param name="client">The client associated with the authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
/// whose result returns the authorizations corresponding to the subject/client.
/// </returns>
public ValueTask<ImmutableArray<TAuthorization>> FindAsync(
/// <returns>The authorizations corresponding to the subject/client.</returns>
public IAsyncEnumerable<TAuthorization> FindAsync(
[NotNull] string subject, [NotNull] string client, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(subject))
@ -161,12 +160,15 @@ namespace OpenIddict.Core
if (_cache.TryGetValue(parameters, out ImmutableArray<TAuthorization> authorizations))
{
return new ValueTask<ImmutableArray<TAuthorization>>(authorizations);
return authorizations.ToAsyncEnumerable();
}
async Task<ImmutableArray<TAuthorization>> ExecuteAsync()
async IAsyncEnumerable<TAuthorization> ExecuteAsync()
{
foreach (var authorization in (authorizations = await _store.FindAsync(subject, client, cancellationToken)))
var authorizations = ImmutableArray.CreateRange(await _store.FindAsync(
subject, client, cancellationToken).ToListAsync(cancellationToken));
foreach (var authorization in authorizations)
{
await AddAsync(authorization, cancellationToken);
}
@ -188,10 +190,13 @@ namespace OpenIddict.Core
entry.SetValue(authorizations);
}
return authorizations;
foreach (var authorization in authorizations)
{
yield return authorization;
}
}
return new ValueTask<ImmutableArray<TAuthorization>>(ExecuteAsync());
return ExecuteAsync();
}
/// <summary>
@ -201,11 +206,8 @@ namespace OpenIddict.Core
/// <param name="client">The client associated with the authorization.</param>
/// <param name="status">The authorization status.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
/// whose result returns the authorizations corresponding to the criteria.
/// </returns>
public ValueTask<ImmutableArray<TAuthorization>> FindAsync(
/// <returns>The authorizations corresponding to the criteria.</returns>
public IAsyncEnumerable<TAuthorization> FindAsync(
[NotNull] string subject, [NotNull] string client,
[NotNull] string status, CancellationToken cancellationToken)
{
@ -234,12 +236,15 @@ namespace OpenIddict.Core
if (_cache.TryGetValue(parameters, out ImmutableArray<TAuthorization> authorizations))
{
return new ValueTask<ImmutableArray<TAuthorization>>(authorizations);
return authorizations.ToAsyncEnumerable();
}
async Task<ImmutableArray<TAuthorization>> ExecuteAsync()
async IAsyncEnumerable<TAuthorization> ExecuteAsync()
{
foreach (var authorization in (authorizations = await _store.FindAsync(subject, client, status, cancellationToken)))
var authorizations = ImmutableArray.CreateRange(await _store.FindAsync(
subject, client, status, cancellationToken).ToListAsync(cancellationToken));
foreach (var authorization in authorizations)
{
await AddAsync(authorization, cancellationToken);
}
@ -261,10 +266,13 @@ namespace OpenIddict.Core
entry.SetValue(authorizations);
}
return authorizations;
foreach (var authorization in authorizations)
{
yield return authorization;
}
}
return new ValueTask<ImmutableArray<TAuthorization>>(ExecuteAsync());
return ExecuteAsync();
}
/// <summary>
@ -275,11 +283,8 @@ namespace OpenIddict.Core
/// <param name="status">The authorization status.</param>
/// <param name="type">The authorization type.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
/// whose result returns the authorizations corresponding to the criteria.
/// </returns>
public ValueTask<ImmutableArray<TAuthorization>> FindAsync(
/// <returns>The authorizations corresponding to the criteria.</returns>
public IAsyncEnumerable<TAuthorization> FindAsync(
[NotNull] string subject, [NotNull] string client,
[NotNull] string status, [NotNull] string type, CancellationToken cancellationToken)
{
@ -314,12 +319,15 @@ namespace OpenIddict.Core
if (_cache.TryGetValue(parameters, out ImmutableArray<TAuthorization> authorizations))
{
return new ValueTask<ImmutableArray<TAuthorization>>(authorizations);
return authorizations.ToAsyncEnumerable();
}
async Task<ImmutableArray<TAuthorization>> ExecuteAsync()
async IAsyncEnumerable<TAuthorization> ExecuteAsync()
{
foreach (var authorization in (authorizations = await _store.FindAsync(subject, client, status, type, cancellationToken)))
var authorizations = ImmutableArray.CreateRange(await _store.FindAsync(
subject, client, status, type, cancellationToken).ToListAsync(cancellationToken));
foreach (var authorization in authorizations)
{
await AddAsync(authorization, cancellationToken);
}
@ -341,10 +349,13 @@ namespace OpenIddict.Core
entry.SetValue(authorizations);
}
return authorizations;
foreach (var authorization in authorizations)
{
yield return authorization;
}
}
return new ValueTask<ImmutableArray<TAuthorization>>(ExecuteAsync());
return ExecuteAsync();
}
/// <summary>
@ -356,11 +367,8 @@ namespace OpenIddict.Core
/// <param name="type">The authorization type.</param>
/// <param name="scopes">The minimal scopes associated with the authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
/// whose result returns the authorizations corresponding to the criteria.
/// </returns>
public ValueTask<ImmutableArray<TAuthorization>> FindAsync(
/// <returns>The authorizations corresponding to the criteria.</returns>
public IAsyncEnumerable<TAuthorization> FindAsync(
[NotNull] string subject, [NotNull] string client,
[NotNull] string status, [NotNull] string type,
ImmutableArray<string> scopes, CancellationToken cancellationToken)
@ -387,19 +395,17 @@ namespace OpenIddict.Core
// Note: this method is only partially cached.
async Task<ImmutableArray<TAuthorization>> ExecuteAsync()
async IAsyncEnumerable<TAuthorization> ExecuteAsync()
{
var authorizations = await _store.FindAsync(subject, client, status, type, scopes, cancellationToken);
foreach (var authorization in authorizations)
await foreach (var authorization in _store.FindAsync(subject, client, status, type, scopes, cancellationToken))
{
await AddAsync(authorization, cancellationToken);
}
return authorizations;
yield return authorization;
}
}
return new ValueTask<ImmutableArray<TAuthorization>>(ExecuteAsync());
return ExecuteAsync();
}
/// <summary>
@ -407,11 +413,8 @@ namespace OpenIddict.Core
/// </summary>
/// <param name="identifier">The application identifier associated with the authorizations.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
/// whose result returns the authorizations corresponding to the specified application.
/// </returns>
public ValueTask<ImmutableArray<TAuthorization>> FindByApplicationIdAsync(
/// <returns>The authorizations corresponding to the specified application.</returns>
public IAsyncEnumerable<TAuthorization> FindByApplicationIdAsync(
[NotNull] string identifier, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(identifier))
@ -427,12 +430,15 @@ namespace OpenIddict.Core
if (_cache.TryGetValue(parameters, out ImmutableArray<TAuthorization> authorizations))
{
return new ValueTask<ImmutableArray<TAuthorization>>(authorizations);
return authorizations.ToAsyncEnumerable();
}
async Task<ImmutableArray<TAuthorization>> ExecuteAsync()
async IAsyncEnumerable<TAuthorization> ExecuteAsync()
{
foreach (var authorization in (authorizations = await _store.FindByApplicationIdAsync(identifier, cancellationToken)))
var authorizations = ImmutableArray.CreateRange(await _store.FindByApplicationIdAsync(
identifier, cancellationToken).ToListAsync(cancellationToken));
foreach (var authorization in authorizations)
{
await AddAsync(authorization, cancellationToken);
}
@ -454,10 +460,13 @@ namespace OpenIddict.Core
entry.SetValue(authorizations);
}
return authorizations;
foreach (var authorization in authorizations)
{
yield return authorization;
}
}
return new ValueTask<ImmutableArray<TAuthorization>>(ExecuteAsync());
return ExecuteAsync();
}
/// <summary>
@ -522,11 +531,8 @@ namespace OpenIddict.Core
/// </summary>
/// <param name="subject">The subject associated with the authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
/// whose result returns the authorizations corresponding to the specified subject.
/// </returns>
public ValueTask<ImmutableArray<TAuthorization>> FindBySubjectAsync(
/// <returns>The authorizations corresponding to the specified subject.</returns>
public IAsyncEnumerable<TAuthorization> FindBySubjectAsync(
[NotNull] string subject, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(subject))
@ -542,12 +548,15 @@ namespace OpenIddict.Core
if (_cache.TryGetValue(parameters, out ImmutableArray<TAuthorization> authorizations))
{
return new ValueTask<ImmutableArray<TAuthorization>>(authorizations);
return authorizations.ToAsyncEnumerable();
}
async Task<ImmutableArray<TAuthorization>> ExecuteAsync()
async IAsyncEnumerable<TAuthorization> ExecuteAsync()
{
foreach (var authorization in (authorizations = await _store.FindBySubjectAsync(subject, cancellationToken)))
var authorizations = ImmutableArray.CreateRange(await _store.FindBySubjectAsync(
subject, cancellationToken).ToListAsync(cancellationToken));
foreach (var authorization in authorizations)
{
await AddAsync(authorization, cancellationToken);
}
@ -569,10 +578,13 @@ namespace OpenIddict.Core
entry.SetValue(authorizations);
}
return authorizations;
foreach (var authorization in authorizations)
{
yield return authorization;
}
}
return new ValueTask<ImmutableArray<TAuthorization>>(ExecuteAsync());
return ExecuteAsync();
}
/// <summary>
@ -580,10 +592,8 @@ namespace OpenIddict.Core
/// </summary>
/// <param name="authorization">The authorization to remove from the cache.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public async Task RemoveAsync([NotNull] TAuthorization authorization, CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public async ValueTask RemoveAsync([NotNull] TAuthorization authorization, CancellationToken cancellationToken)
{
if (authorization == null)
{
@ -609,10 +619,10 @@ namespace OpenIddict.Core
/// <param name="authorization">The authorization associated with the expiration signal.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns an expiration signal for the specified authorization.
/// </returns>
protected virtual async Task<IChangeToken> CreateExpirationSignalAsync(
protected virtual async ValueTask<IChangeToken> CreateExpirationSignalAsync(
[NotNull] TAuthorization authorization, CancellationToken cancellationToken)
{
if (authorization == null)

61
src/OpenIddict.Core/Caches/OpenIddictScopeCache.cs

@ -6,6 +6,7 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Threading;
@ -46,10 +47,8 @@ namespace OpenIddict.Core
/// </summary>
/// <param name="scope">The scope to add to the cache.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public async Task AddAsync([NotNull] TScope scope, CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public async ValueTask AddAsync([NotNull] TScope scope, CancellationToken cancellationToken)
{
if (scope == null)
{
@ -238,15 +237,12 @@ namespace OpenIddict.Core
/// </summary>
/// <param name="names">The names associated with the scopes.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
/// whose result returns the scopes corresponding to the specified names.
/// </returns>
public ValueTask<ImmutableArray<TScope>> FindByNamesAsync(ImmutableArray<string> names, CancellationToken cancellationToken)
/// <returns>The scopes corresponding to the specified names.</returns>
public IAsyncEnumerable<TScope> FindByNamesAsync(ImmutableArray<string> names, CancellationToken cancellationToken)
{
if (names.IsDefaultOrEmpty)
{
return new ValueTask<ImmutableArray<TScope>>(ImmutableArray.Create<TScope>());
return AsyncEnumerable.Empty<TScope>();
}
if (names.Any(name => string.IsNullOrEmpty(name)))
@ -256,19 +252,17 @@ namespace OpenIddict.Core
// Note: this method is only partially cached.
async Task<ImmutableArray<TScope>> ExecuteAsync()
async IAsyncEnumerable<TScope> ExecuteAsync()
{
var scopes = await _store.FindByNamesAsync(names, cancellationToken);
foreach (var scope in scopes)
await foreach (var scope in _store.FindByNamesAsync(names, cancellationToken))
{
await AddAsync(scope, cancellationToken);
}
return scopes;
yield return scope;
}
}
return new ValueTask<ImmutableArray<TScope>>(ExecuteAsync());
return ExecuteAsync();
}
/// <summary>
@ -276,11 +270,8 @@ namespace OpenIddict.Core
/// </summary>
/// <param name="resource">The resource associated with the scopes.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
/// whose result returns the scopes associated with the specified resource.
/// </returns>
public ValueTask<ImmutableArray<TScope>> FindByResourceAsync([NotNull] string resource, CancellationToken cancellationToken)
/// <returns>The scopes associated with the specified resource.</returns>
public IAsyncEnumerable<TScope> FindByResourceAsync([NotNull] string resource, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(resource))
{
@ -295,12 +286,15 @@ namespace OpenIddict.Core
if (_cache.TryGetValue(parameters, out ImmutableArray<TScope> scopes))
{
return new ValueTask<ImmutableArray<TScope>>(scopes);
return scopes.ToAsyncEnumerable();
}
async Task<ImmutableArray<TScope>> ExecuteAsync()
async IAsyncEnumerable<TScope> ExecuteAsync()
{
foreach (var scope in (scopes = await _store.FindByResourceAsync(resource, cancellationToken)))
var scopes = ImmutableArray.CreateRange(await _store.FindByResourceAsync(
resource, cancellationToken).ToListAsync(cancellationToken));
foreach (var scope in scopes)
{
await AddAsync(scope, cancellationToken);
}
@ -322,10 +316,13 @@ namespace OpenIddict.Core
entry.SetValue(scopes);
}
return scopes;
foreach (var scope in scopes)
{
yield return scope;
}
}
return new ValueTask<ImmutableArray<TScope>>(ExecuteAsync());
return ExecuteAsync();
}
/// <summary>
@ -333,10 +330,8 @@ namespace OpenIddict.Core
/// </summary>
/// <param name="scope">The scope to remove from the cache.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public async Task RemoveAsync([NotNull] TScope scope, CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public async ValueTask RemoveAsync([NotNull] TScope scope, CancellationToken cancellationToken)
{
if (scope == null)
{
@ -362,10 +357,10 @@ namespace OpenIddict.Core
/// <param name="scope">The scope associated with the expiration signal.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns an expiration signal for the specified scope.
/// </returns>
protected virtual async Task<IChangeToken> CreateExpirationSignalAsync([NotNull] TScope scope, CancellationToken cancellationToken)
protected virtual async ValueTask<IChangeToken> CreateExpirationSignalAsync([NotNull] TScope scope, CancellationToken cancellationToken)
{
if (scope == null)
{

156
src/OpenIddict.Core/Caches/OpenIddictTokenCache.cs

@ -6,7 +6,9 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using JetBrains.Annotations;
@ -45,10 +47,8 @@ namespace OpenIddict.Core
/// </summary>
/// <param name="token">The token to add to the cache.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public async Task AddAsync([NotNull] TToken token, CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public async ValueTask AddAsync([NotNull] TToken token, CancellationToken cancellationToken)
{
if (token == null)
{
@ -158,11 +158,8 @@ namespace OpenIddict.Core
/// <param name="subject">The subject associated with the token.</param>
/// <param name="client">The client associated with the token.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
/// whose result returns the tokens corresponding to the subject/client.
/// </returns>
public ValueTask<ImmutableArray<TToken>> FindAsync([NotNull] string subject,
/// <returns>The tokens corresponding to the subject/client.</returns>
public IAsyncEnumerable<TToken> FindAsync([NotNull] string subject,
[NotNull] string client, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(subject))
@ -184,12 +181,15 @@ namespace OpenIddict.Core
if (_cache.TryGetValue(parameters, out ImmutableArray<TToken> tokens))
{
return new ValueTask<ImmutableArray<TToken>>(tokens);
return tokens.ToAsyncEnumerable();
}
async Task<ImmutableArray<TToken>> ExecuteAsync()
async IAsyncEnumerable<TToken> ExecuteAsync()
{
foreach (var token in (tokens = await _store.FindAsync(subject, client, cancellationToken)))
var tokens = ImmutableArray.CreateRange(await _store.FindAsync(
subject, client, cancellationToken).ToListAsync(cancellationToken));
foreach (var token in tokens)
{
await AddAsync(token, cancellationToken);
}
@ -211,10 +211,13 @@ namespace OpenIddict.Core
entry.SetValue(tokens);
}
return tokens;
foreach (var token in tokens)
{
yield return token;
}
}
return new ValueTask<ImmutableArray<TToken>>(ExecuteAsync());
return ExecuteAsync();
}
/// <summary>
@ -224,11 +227,8 @@ namespace OpenIddict.Core
/// <param name="client">The client associated with the token.</param>
/// <param name="status">The token status.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
/// whose result returns the tokens corresponding to the criteria.
/// </returns>
public ValueTask<ImmutableArray<TToken>> FindAsync(
/// <returns>The tokens corresponding to the criteria.</returns>
public IAsyncEnumerable<TToken> FindAsync(
[NotNull] string subject, [NotNull] string client,
[NotNull] string status, CancellationToken cancellationToken)
{
@ -257,12 +257,15 @@ namespace OpenIddict.Core
if (_cache.TryGetValue(parameters, out ImmutableArray<TToken> tokens))
{
return new ValueTask<ImmutableArray<TToken>>(tokens);
return tokens.ToAsyncEnumerable();
}
async Task<ImmutableArray<TToken>> ExecuteAsync()
async IAsyncEnumerable<TToken> ExecuteAsync()
{
foreach (var token in (tokens = await _store.FindAsync(subject, client, status, cancellationToken)))
var tokens = ImmutableArray.CreateRange(await _store.FindAsync(
subject, client, status, cancellationToken).ToListAsync(cancellationToken));
foreach (var token in tokens)
{
await AddAsync(token, cancellationToken);
}
@ -284,10 +287,13 @@ namespace OpenIddict.Core
entry.SetValue(tokens);
}
return tokens;
foreach (var token in tokens)
{
yield return token;
}
}
return new ValueTask<ImmutableArray<TToken>>(ExecuteAsync());
return ExecuteAsync();
}
/// <summary>
@ -298,11 +304,8 @@ namespace OpenIddict.Core
/// <param name="status">The token status.</param>
/// <param name="type">The token type.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
/// whose result returns the tokens corresponding to the criteria.
/// </returns>
public ValueTask<ImmutableArray<TToken>> FindAsync(
/// <returns>The tokens corresponding to the criteria.</returns>
public IAsyncEnumerable<TToken> FindAsync(
[NotNull] string subject, [NotNull] string client,
[NotNull] string status, [NotNull] string type, CancellationToken cancellationToken)
{
@ -337,12 +340,15 @@ namespace OpenIddict.Core
if (_cache.TryGetValue(parameters, out ImmutableArray<TToken> tokens))
{
return new ValueTask<ImmutableArray<TToken>>(tokens);
return tokens.ToAsyncEnumerable();
}
async Task<ImmutableArray<TToken>> ExecuteAsync()
async IAsyncEnumerable<TToken> ExecuteAsync()
{
foreach (var token in (tokens = await _store.FindAsync(subject, client, status, type, cancellationToken)))
var tokens = ImmutableArray.CreateRange(await _store.FindAsync(
subject, client, status, type, cancellationToken).ToListAsync(cancellationToken));
foreach (var token in tokens)
{
await AddAsync(token, cancellationToken);
}
@ -364,10 +370,13 @@ namespace OpenIddict.Core
entry.SetValue(tokens);
}
return tokens;
foreach (var token in tokens)
{
yield return token;
}
}
return new ValueTask<ImmutableArray<TToken>>(ExecuteAsync());
return ExecuteAsync();
}
/// <summary>
@ -375,11 +384,8 @@ namespace OpenIddict.Core
/// </summary>
/// <param name="identifier">The application identifier associated with the tokens.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
/// whose result returns the tokens corresponding to the specified application.
/// </returns>
public ValueTask<ImmutableArray<TToken>> FindByApplicationIdAsync(
/// <returns>The tokens corresponding to the specified application.</returns>
public IAsyncEnumerable<TToken> FindByApplicationIdAsync(
[NotNull] string identifier, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(identifier))
@ -395,12 +401,15 @@ namespace OpenIddict.Core
if (_cache.TryGetValue(parameters, out ImmutableArray<TToken> tokens))
{
return new ValueTask<ImmutableArray<TToken>>(tokens);
return tokens.ToAsyncEnumerable();
}
async Task<ImmutableArray<TToken>> ExecuteAsync()
async IAsyncEnumerable<TToken> ExecuteAsync()
{
foreach (var token in (tokens = await _store.FindByApplicationIdAsync(identifier, cancellationToken)))
var tokens = ImmutableArray.CreateRange(await _store.FindByApplicationIdAsync(
identifier, cancellationToken).ToListAsync(cancellationToken));
foreach (var token in tokens)
{
await AddAsync(token, cancellationToken);
}
@ -422,10 +431,13 @@ namespace OpenIddict.Core
entry.SetValue(tokens);
}
return tokens;
foreach (var token in tokens)
{
yield return token;
}
}
return new ValueTask<ImmutableArray<TToken>>(ExecuteAsync());
return ExecuteAsync();
}
/// <summary>
@ -433,11 +445,8 @@ namespace OpenIddict.Core
/// </summary>
/// <param name="identifier">The authorization identifier associated with the tokens.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
/// whose result returns the tokens corresponding to the specified authorization.
/// </returns>
public ValueTask<ImmutableArray<TToken>> FindByAuthorizationIdAsync(
/// <returns>The tokens corresponding to the specified authorization.</returns>
public IAsyncEnumerable<TToken> FindByAuthorizationIdAsync(
[NotNull] string identifier, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(identifier))
@ -453,12 +462,15 @@ namespace OpenIddict.Core
if (_cache.TryGetValue(parameters, out ImmutableArray<TToken> tokens))
{
return new ValueTask<ImmutableArray<TToken>>(tokens);
return tokens.ToAsyncEnumerable();
}
async Task<ImmutableArray<TToken>> ExecuteAsync()
async IAsyncEnumerable<TToken> ExecuteAsync()
{
foreach (var token in (tokens = await _store.FindByAuthorizationIdAsync(identifier, cancellationToken)))
var tokens = ImmutableArray.CreateRange(await _store.FindByAuthorizationIdAsync(
identifier, cancellationToken).ToListAsync(cancellationToken));
foreach (var token in tokens)
{
await AddAsync(token, cancellationToken);
}
@ -480,10 +492,13 @@ namespace OpenIddict.Core
entry.SetValue(tokens);
}
return tokens;
foreach (var token in tokens)
{
yield return token;
}
}
return new ValueTask<ImmutableArray<TToken>>(ExecuteAsync());
return ExecuteAsync();
}
/// <summary>
@ -606,11 +621,8 @@ namespace OpenIddict.Core
/// </summary>
/// <param name="subject">The subject associated with the tokens.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
/// whose result returns the tokens corresponding to the specified subject.
/// </returns>
public ValueTask<ImmutableArray<TToken>> FindBySubjectAsync([NotNull] string subject, CancellationToken cancellationToken)
/// <returns>The tokens corresponding to the specified subject.</returns>
public IAsyncEnumerable<TToken> FindBySubjectAsync([NotNull] string subject, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(subject))
{
@ -625,12 +637,15 @@ namespace OpenIddict.Core
if (_cache.TryGetValue(parameters, out ImmutableArray<TToken> tokens))
{
return new ValueTask<ImmutableArray<TToken>>(tokens);
return tokens.ToAsyncEnumerable();
}
async Task<ImmutableArray<TToken>> ExecuteAsync()
async IAsyncEnumerable<TToken> ExecuteAsync()
{
foreach (var token in (tokens = await _store.FindBySubjectAsync(subject, cancellationToken)))
var tokens = ImmutableArray.CreateRange(await _store.FindBySubjectAsync(
subject, cancellationToken).ToListAsync(cancellationToken));
foreach (var token in tokens)
{
await AddAsync(token, cancellationToken);
}
@ -652,10 +667,13 @@ namespace OpenIddict.Core
entry.SetValue(tokens);
}
return tokens;
foreach (var token in tokens)
{
yield return token;
}
}
return new ValueTask<ImmutableArray<TToken>>(ExecuteAsync());
return ExecuteAsync();
}
/// <summary>
@ -663,10 +681,8 @@ namespace OpenIddict.Core
/// </summary>
/// <param name="token">The token to remove from the cache.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public async Task RemoveAsync([NotNull] TToken token, CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public async ValueTask RemoveAsync([NotNull] TToken token, CancellationToken cancellationToken)
{
if (token == null)
{
@ -692,10 +708,10 @@ namespace OpenIddict.Core
/// <param name="token">The token associated with the expiration signal.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns an expiration signal for the specified token.
/// </returns>
protected virtual async Task<IChangeToken> CreateExpirationSignalAsync([NotNull] TToken token, CancellationToken cancellationToken)
protected virtual async ValueTask<IChangeToken> CreateExpirationSignalAsync([NotNull] TToken token, CancellationToken cancellationToken)
{
if (token == null)
{

294
src/OpenIddict.Core/Managers/OpenIddictApplicationManager.cs

@ -5,9 +5,11 @@
*/
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
@ -62,10 +64,10 @@ namespace OpenIddict.Core
/// </summary>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the number of applications in the database.
/// </returns>
public virtual Task<long> CountAsync(CancellationToken cancellationToken = default)
public virtual ValueTask<long> CountAsync(CancellationToken cancellationToken = default)
=> Store.CountAsync(cancellationToken);
/// <summary>
@ -75,10 +77,10 @@ namespace OpenIddict.Core
/// <param name="query">The query to execute.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the number of applications that match the specified query.
/// </returns>
public virtual Task<long> CountAsync<TResult>(
public virtual ValueTask<long> CountAsync<TResult>(
[NotNull] Func<IQueryable<TApplication>, IQueryable<TResult>> query, CancellationToken cancellationToken = default)
{
if (query == null)
@ -95,9 +97,9 @@ namespace OpenIddict.Core
/// <param name="application">The application to create.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task CreateAsync([NotNull] TApplication application, CancellationToken cancellationToken = default)
public virtual ValueTask CreateAsync([NotNull] TApplication application, CancellationToken cancellationToken = default)
=> CreateAsync(application, secret: null, cancellationToken);
/// <summary>
@ -109,9 +111,9 @@ namespace OpenIddict.Core
/// <param name="secret">The client secret associated with the application, if applicable.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual async Task CreateAsync(
public virtual async ValueTask CreateAsync(
[NotNull] TApplication application,
[CanBeNull] string secret, CancellationToken cancellationToken = default)
{
@ -141,7 +143,7 @@ namespace OpenIddict.Core
await Store.SetClientSecretAsync(application, secret, cancellationToken);
}
var results = await ValidateAsync(application, cancellationToken);
var results = await ValidateAsync(application, cancellationToken).ToListAsync(cancellationToken);
if (results.Any(result => result != ValidationResult.Success))
{
var builder = new StringBuilder();
@ -153,7 +155,7 @@ namespace OpenIddict.Core
builder.AppendLine(result.ErrorMessage);
}
throw new OpenIddictExceptions.ValidationException(builder.ToString(), results);
throw new OpenIddictExceptions.ValidationException(builder.ToString(), results.ToImmutableArray());
}
await Store.CreateAsync(application, cancellationToken);
@ -172,10 +174,10 @@ namespace OpenIddict.Core
/// <param name="descriptor">The application descriptor.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the unique identifier associated with the application.
/// </returns>
public virtual async Task<TApplication> CreateAsync(
public virtual async ValueTask<TApplication> CreateAsync(
[NotNull] OpenIddictApplicationDescriptor descriptor, CancellationToken cancellationToken = default)
{
if (descriptor == null)
@ -211,9 +213,9 @@ namespace OpenIddict.Core
/// <param name="application">The application to delete.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual async Task DeleteAsync([NotNull] TApplication application, CancellationToken cancellationToken = default)
public virtual async ValueTask DeleteAsync([NotNull] TApplication application, CancellationToken cancellationToken = default)
{
if (application == null)
{
@ -234,10 +236,10 @@ namespace OpenIddict.Core
/// <param name="identifier">The client identifier associated with the application.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the client application corresponding to the identifier.
/// </returns>
public virtual async Task<TApplication> FindByClientIdAsync(
public virtual async ValueTask<TApplication> FindByClientIdAsync(
[NotNull] string identifier, CancellationToken cancellationToken = default)
{
if (string.IsNullOrEmpty(identifier))
@ -272,10 +274,10 @@ namespace OpenIddict.Core
/// <param name="identifier">The unique identifier associated with the application.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the client application corresponding to the identifier.
/// </returns>
public virtual async Task<TApplication> FindByIdAsync([NotNull] string identifier, CancellationToken cancellationToken = default)
public virtual async ValueTask<TApplication> FindByIdAsync([NotNull] string identifier, CancellationToken cancellationToken = default)
{
if (string.IsNullOrEmpty(identifier))
{
@ -308,11 +310,8 @@ namespace OpenIddict.Core
/// </summary>
/// <param name="address">The post_logout_redirect_uri associated with the applications.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation, whose result
/// returns the client applications corresponding to the specified post_logout_redirect_uri.
/// </returns>
public virtual async Task<ImmutableArray<TApplication>> FindByPostLogoutRedirectUriAsync(
/// <returns>The client applications corresponding to the specified post_logout_redirect_uri.</returns>
public virtual IAsyncEnumerable<TApplication> FindByPostLogoutRedirectUriAsync(
[NotNull] string address, CancellationToken cancellationToken = default)
{
if (string.IsNullOrEmpty(address))
@ -321,13 +320,8 @@ namespace OpenIddict.Core
}
var applications = Options.CurrentValue.DisableEntityCaching ?
await Store.FindByPostLogoutRedirectUriAsync(address, cancellationToken) :
await Cache.FindByPostLogoutRedirectUriAsync(address, cancellationToken);
if (applications.IsEmpty)
{
return ImmutableArray.Create<TApplication>();
}
Store.FindByPostLogoutRedirectUriAsync(address, cancellationToken) :
Cache.FindByPostLogoutRedirectUriAsync(address, cancellationToken);
if (Options.CurrentValue.DisableAdditionalFiltering)
{
@ -338,23 +332,8 @@ namespace OpenIddict.Core
// To ensure a case-sensitive comparison is enforced independently of the database/table/query collation
// used by the store, a second pass using string.Equals(StringComparison.Ordinal) is manually made here.
var builder = ImmutableArray.CreateBuilder<TApplication>(applications.Length);
foreach (var application in applications)
{
foreach (var uri in await Store.GetPostLogoutRedirectUrisAsync(application, cancellationToken))
{
// Note: the post_logout_redirect_uri must be compared using case-sensitive "Simple String Comparison".
if (string.Equals(uri, address, StringComparison.Ordinal))
{
builder.Add(application);
}
}
}
return builder.Count == builder.Capacity ?
builder.MoveToImmutable() :
builder.ToImmutable();
return applications.WhereAwait(async application =>
(await Store.GetPostLogoutRedirectUrisAsync(application, cancellationToken)).Contains(address, StringComparer.Ordinal));
}
/// <summary>
@ -362,11 +341,8 @@ namespace OpenIddict.Core
/// </summary>
/// <param name="address">The redirect_uri associated with the applications.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation, whose result
/// returns the client applications corresponding to the specified redirect_uri.
/// </returns>
public virtual async Task<ImmutableArray<TApplication>> FindByRedirectUriAsync(
/// <returns>The client applications corresponding to the specified redirect_uri.</returns>
public virtual IAsyncEnumerable<TApplication> FindByRedirectUriAsync(
[NotNull] string address, CancellationToken cancellationToken = default)
{
if (string.IsNullOrEmpty(address))
@ -375,13 +351,8 @@ namespace OpenIddict.Core
}
var applications = Options.CurrentValue.DisableEntityCaching ?
await Store.FindByRedirectUriAsync(address, cancellationToken) :
await Cache.FindByRedirectUriAsync(address, cancellationToken);
if (applications.IsEmpty)
{
return ImmutableArray.Create<TApplication>();
}
Store.FindByRedirectUriAsync(address, cancellationToken) :
Cache.FindByRedirectUriAsync(address, cancellationToken);
if (Options.CurrentValue.DisableAdditionalFiltering)
{
@ -392,23 +363,8 @@ namespace OpenIddict.Core
// To ensure a case-sensitive comparison is enforced independently of the database/table/query collation
// used by the store, a second pass using string.Equals(StringComparison.Ordinal) is manually made here.
var builder = ImmutableArray.CreateBuilder<TApplication>(applications.Length);
foreach (var application in applications)
{
foreach (var uri in await Store.GetRedirectUrisAsync(application, cancellationToken))
{
// Note: the post_logout_redirect_uri must be compared using case-sensitive "Simple String Comparison".
if (string.Equals(uri, address, StringComparison.Ordinal))
{
builder.Add(application);
}
}
}
return builder.Count == builder.Capacity ?
builder.MoveToImmutable() :
builder.ToImmutable();
return applications.WhereAwait(async application =>
(await Store.GetRedirectUrisAsync(application, cancellationToken)).Contains(address, StringComparer.Ordinal));
}
/// <summary>
@ -418,10 +374,10 @@ namespace OpenIddict.Core
/// <param name="query">The query to execute.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the first element returned when executing the query.
/// </returns>
public virtual Task<TResult> GetAsync<TResult>(
public virtual ValueTask<TResult> GetAsync<TResult>(
[NotNull] Func<IQueryable<TApplication>, IQueryable<TResult>> query, CancellationToken cancellationToken = default)
{
if (query == null)
@ -441,10 +397,10 @@ namespace OpenIddict.Core
/// <param name="state">The optional state.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the first element returned when executing the query.
/// </returns>
public virtual Task<TResult> GetAsync<TState, TResult>(
public virtual ValueTask<TResult> GetAsync<TState, TResult>(
[NotNull] Func<IQueryable<TApplication>, TState, IQueryable<TResult>> query,
[CanBeNull] TState state, CancellationToken cancellationToken = default)
{
@ -628,7 +584,7 @@ namespace OpenIddict.Core
/// <param name="permission">The permission.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns><c>true</c> if the application has been granted the specified permission, <c>false</c> otherwise.</returns>
public virtual async Task<bool> HasPermissionAsync(
public virtual async ValueTask<bool> HasPermissionAsync(
[NotNull] TApplication application, [NotNull] string permission, CancellationToken cancellationToken = default)
{
if (application == null)
@ -641,7 +597,7 @@ namespace OpenIddict.Core
throw new ArgumentException("The permission name cannot be null or empty.", nameof(permission));
}
return (await GetPermissionsAsync(application, cancellationToken)).Contains(permission);
return (await GetPermissionsAsync(application, cancellationToken)).Contains(permission, StringComparer.OrdinalIgnoreCase);
}
/// <summary>
@ -650,7 +606,7 @@ namespace OpenIddict.Core
/// <param name="application">The application.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns><c>true</c> if the application is a confidential client, <c>false</c> otherwise.</returns>
public async Task<bool> IsConfidentialAsync([NotNull] TApplication application, CancellationToken cancellationToken = default)
public async ValueTask<bool> IsConfidentialAsync([NotNull] TApplication application, CancellationToken cancellationToken = default)
{
if (application == null)
{
@ -672,7 +628,7 @@ namespace OpenIddict.Core
/// <param name="application">The application.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns><c>true</c> if the application is a hybrid client, <c>false</c> otherwise.</returns>
public async Task<bool> IsHybridAsync([NotNull] TApplication application, CancellationToken cancellationToken = default)
public async ValueTask<bool> IsHybridAsync([NotNull] TApplication application, CancellationToken cancellationToken = default)
{
if (application == null)
{
@ -694,7 +650,7 @@ namespace OpenIddict.Core
/// <param name="application">The application.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns><c>true</c> if the application is a public client, <c>false</c> otherwise.</returns>
public async Task<bool> IsPublicAsync([NotNull] TApplication application, CancellationToken cancellationToken = default)
public async ValueTask<bool> IsPublicAsync([NotNull] TApplication application, CancellationToken cancellationToken = default)
{
if (application == null)
{
@ -717,15 +673,10 @@ namespace OpenIddict.Core
/// <param name="count">The number of results to return.</param>
/// <param name="offset">The number of results to skip.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the elements returned when executing the specified query.
/// </returns>
public virtual Task<ImmutableArray<TApplication>> ListAsync(
/// <returns>All the elements returned when executing the specified query.</returns>
public virtual IAsyncEnumerable<TApplication> ListAsync(
[CanBeNull] int? count = null, [CanBeNull] int? offset = null, CancellationToken cancellationToken = default)
{
return Store.ListAsync(count, offset, cancellationToken);
}
=> Store.ListAsync(count, offset, cancellationToken);
/// <summary>
/// Executes the specified query and returns all the corresponding elements.
@ -733,11 +684,8 @@ namespace OpenIddict.Core
/// <typeparam name="TResult">The result type.</typeparam>
/// <param name="query">The query to execute.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the elements returned when executing the specified query.
/// </returns>
public virtual Task<ImmutableArray<TResult>> ListAsync<TResult>(
/// <returns>All the elements returned when executing the specified query.</returns>
public virtual IAsyncEnumerable<TResult> ListAsync<TResult>(
[NotNull] Func<IQueryable<TApplication>, IQueryable<TResult>> query, CancellationToken cancellationToken = default)
{
if (query == null)
@ -756,11 +704,8 @@ namespace OpenIddict.Core
/// <param name="query">The query to execute.</param>
/// <param name="state">The optional state.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the elements returned when executing the specified query.
/// </returns>
public virtual Task<ImmutableArray<TResult>> ListAsync<TState, TResult>(
/// <returns>All the elements returned when executing the specified query.</returns>
public virtual IAsyncEnumerable<TResult> ListAsync<TState, TResult>(
[NotNull] Func<IQueryable<TApplication>, TState, IQueryable<TResult>> query,
[CanBeNull] TState state, CancellationToken cancellationToken = default)
{
@ -779,9 +724,9 @@ namespace OpenIddict.Core
/// <param name="descriptor">The descriptor.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual async Task PopulateAsync([NotNull] TApplication application,
public virtual async ValueTask PopulateAsync([NotNull] TApplication application,
[NotNull] OpenIddictApplicationDescriptor descriptor, CancellationToken cancellationToken = default)
{
if (application == null)
@ -813,9 +758,9 @@ namespace OpenIddict.Core
/// <param name="application">The application.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual async Task PopulateAsync(
public virtual async ValueTask PopulateAsync(
[NotNull] OpenIddictApplicationDescriptor descriptor,
[NotNull] TApplication application, CancellationToken cancellationToken = default)
{
@ -880,16 +825,16 @@ namespace OpenIddict.Core
/// <param name="application">The application to update.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual async Task UpdateAsync([NotNull] TApplication application, CancellationToken cancellationToken = default)
public virtual async ValueTask UpdateAsync([NotNull] TApplication application, CancellationToken cancellationToken = default)
{
if (application == null)
{
throw new ArgumentNullException(nameof(application));
}
var results = await ValidateAsync(application, cancellationToken);
var results = await ValidateAsync(application, cancellationToken).ToListAsync(cancellationToken);
if (results.Any(result => result != ValidationResult.Success))
{
var builder = new StringBuilder();
@ -901,7 +846,7 @@ namespace OpenIddict.Core
builder.AppendLine(result.ErrorMessage);
}
throw new OpenIddictExceptions.ValidationException(builder.ToString(), results);
throw new OpenIddictExceptions.ValidationException(builder.ToString(), results.ToImmutableArray());
}
await Store.UpdateAsync(application, cancellationToken);
@ -922,9 +867,9 @@ namespace OpenIddict.Core
/// <param name="secret">The client secret associated with the application.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual async Task UpdateAsync([NotNull] TApplication application,
public virtual async ValueTask UpdateAsync([NotNull] TApplication application,
[CanBeNull] string secret, CancellationToken cancellationToken = default)
{
if (application == null)
@ -953,9 +898,9 @@ namespace OpenIddict.Core
/// <param name="descriptor">The descriptor used to update the application.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual async Task UpdateAsync([NotNull] TApplication application,
public virtual async ValueTask UpdateAsync([NotNull] TApplication application,
[NotNull] OpenIddictApplicationDescriptor descriptor, CancellationToken cancellationToken = default)
{
if (application == null)
@ -989,25 +934,20 @@ namespace OpenIddict.Core
/// </summary>
/// <param name="application">The application.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the validation error encountered when validating the application.
/// </returns>
public virtual async Task<ImmutableArray<ValidationResult>> ValidateAsync(
[NotNull] TApplication application, CancellationToken cancellationToken = default)
/// <returns>The validation error encountered when validating the application.</returns>
public virtual async IAsyncEnumerable<ValidationResult> ValidateAsync(
[NotNull] TApplication application, [EnumeratorCancellation] CancellationToken cancellationToken = default)
{
if (application == null)
{
throw new ArgumentNullException(nameof(application));
}
var builder = ImmutableArray.CreateBuilder<ValidationResult>();
// Ensure the client_id is not null or empty and is not already used for a different application.
var identifier = await Store.GetClientIdAsync(application, cancellationToken);
if (string.IsNullOrEmpty(identifier))
{
builder.Add(new ValidationResult("The client identifier cannot be null or empty."));
yield return new ValidationResult("The client identifier cannot be null or empty.");
}
else
@ -1021,14 +961,14 @@ namespace OpenIddict.Core
await Store.GetIdAsync(other, cancellationToken),
await Store.GetIdAsync(application, cancellationToken), StringComparison.Ordinal))
{
builder.Add(new ValidationResult("An application with the same client identifier already exists."));
yield return new ValidationResult("An application with the same client identifier already exists.");
}
}
var type = await Store.GetClientTypeAsync(application, cancellationToken);
if (string.IsNullOrEmpty(type))
{
builder.Add(new ValidationResult("The client type cannot be null or empty."));
yield return new ValidationResult("The client type cannot be null or empty.");
}
else
@ -1038,8 +978,8 @@ namespace OpenIddict.Core
!string.Equals(type, OpenIddictConstants.ClientTypes.Hybrid, StringComparison.OrdinalIgnoreCase) &&
!string.Equals(type, OpenIddictConstants.ClientTypes.Public, StringComparison.OrdinalIgnoreCase))
{
builder.Add(new ValidationResult("Only 'confidential', 'hybrid' or 'public' applications are " +
"supported by the default application manager."));
yield return new ValidationResult("Only 'confidential', 'hybrid' or 'public' applications are " +
"supported by the default application manager.");
}
// Ensure a client secret was specified if the client is a confidential application.
@ -1047,14 +987,14 @@ namespace OpenIddict.Core
if (string.IsNullOrEmpty(secret) &&
string.Equals(type, OpenIddictConstants.ClientTypes.Confidential, StringComparison.OrdinalIgnoreCase))
{
builder.Add(new ValidationResult("The client secret cannot be null or empty for a confidential application."));
yield return new ValidationResult("The client secret cannot be null or empty for a confidential application.");
}
// Ensure no client secret was specified if the client is a public application.
else if (!string.IsNullOrEmpty(secret) &&
string.Equals(type, OpenIddictConstants.ClientTypes.Public, StringComparison.OrdinalIgnoreCase))
{
builder.Add(new ValidationResult("A client secret cannot be associated with a public application."));
yield return new ValidationResult("A client secret cannot be associated with a public application.");
}
}
@ -1067,7 +1007,7 @@ namespace OpenIddict.Core
// Ensure the address is not null or empty.
if (string.IsNullOrEmpty(address))
{
builder.Add(new ValidationResult("Callback URLs cannot be null or empty."));
yield return new ValidationResult("Callback URLs cannot be null or empty.");
break;
}
@ -1075,7 +1015,7 @@ namespace OpenIddict.Core
// Ensure the address is a valid absolute URL.
if (!Uri.TryCreate(address, UriKind.Absolute, out Uri uri) || !uri.IsWellFormedOriginalString())
{
builder.Add(new ValidationResult("Callback URLs must be valid absolute URLs."));
yield return new ValidationResult("Callback URLs must be valid absolute URLs.");
break;
}
@ -1083,15 +1023,11 @@ namespace OpenIddict.Core
// Ensure the address doesn't contain a fragment.
if (!string.IsNullOrEmpty(uri.Fragment))
{
builder.Add(new ValidationResult("Callback URLs cannot contain a fragment."));
yield return new ValidationResult("Callback URLs cannot contain a fragment.");
break;
}
}
return builder.Count == builder.Capacity ?
builder.MoveToImmutable() :
builder.ToImmutable();
}
/// <summary>
@ -1100,12 +1036,12 @@ namespace OpenIddict.Core
/// <param name="application">The application.</param>
/// <param name="secret">The secret that should be compared to the client_secret stored in the database.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>A <see cref="Task"/> that can be used to monitor the asynchronous operation.</returns>
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns a boolean indicating whether the client secret was valid.
/// </returns>
public virtual async Task<bool> ValidateClientSecretAsync(
public virtual async ValueTask<bool> ValidateClientSecretAsync(
[NotNull] TApplication application, string secret, CancellationToken cancellationToken = default)
{
if (application == null)
@ -1147,10 +1083,10 @@ namespace OpenIddict.Core
/// <param name="address">The address that should be compared to one of the redirect_uri stored in the database.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns a boolean indicating whether the redirect_uri was valid.
/// </returns>
public virtual async Task<bool> ValidateRedirectUriAsync(
public virtual async ValueTask<bool> ValidateRedirectUriAsync(
[NotNull] TApplication application, [NotNull] string address, CancellationToken cancellationToken = default)
{
if (application == null)
@ -1186,16 +1122,16 @@ namespace OpenIddict.Core
/// <param name="secret">The client secret.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.
/// </returns>
protected virtual Task<string> ObfuscateClientSecretAsync([NotNull] string secret, CancellationToken cancellationToken = default)
protected virtual ValueTask<string> ObfuscateClientSecretAsync([NotNull] string secret, CancellationToken cancellationToken = default)
{
if (string.IsNullOrEmpty(secret))
{
throw new ArgumentException("The secret cannot be null or empty.", nameof(secret));
}
return Task.FromResult(Crypto.HashPassword(secret));
return new ValueTask<string>(Crypto.HashPassword(secret));
}
/// <summary>
@ -1206,10 +1142,10 @@ namespace OpenIddict.Core
/// <param name="comparand">The value stored in the database, which is usually a hashed representation of the secret.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns a boolean indicating whether the specified value was valid.
/// </returns>
protected virtual Task<bool> ValidateClientSecretAsync(
protected virtual ValueTask<bool> ValidateClientSecretAsync(
[NotNull] string secret, [NotNull] string comparand, CancellationToken cancellationToken = default)
{
if (string.IsNullOrEmpty(secret))
@ -1224,7 +1160,7 @@ namespace OpenIddict.Core
try
{
return Task.FromResult(Crypto.VerifyHashedPassword(comparand, secret));
return new ValueTask<bool>(Crypto.VerifyHashedPassword(comparand, secret));
}
catch (Exception exception)
@ -1232,44 +1168,44 @@ namespace OpenIddict.Core
Logger.LogWarning(exception, "An error occurred while trying to verify a client secret. " +
"This may indicate that the hashed entry is corrupted or malformed.");
return Task.FromResult(false);
return new ValueTask<bool>(false);
}
}
Task<long> IOpenIddictApplicationManager.CountAsync(CancellationToken cancellationToken)
ValueTask<long> IOpenIddictApplicationManager.CountAsync(CancellationToken cancellationToken)
=> CountAsync(cancellationToken);
Task<long> IOpenIddictApplicationManager.CountAsync<TResult>(Func<IQueryable<object>, IQueryable<TResult>> query, CancellationToken cancellationToken)
ValueTask<long> IOpenIddictApplicationManager.CountAsync<TResult>(Func<IQueryable<object>, IQueryable<TResult>> query, CancellationToken cancellationToken)
=> CountAsync(query, cancellationToken);
async Task<object> IOpenIddictApplicationManager.CreateAsync(OpenIddictApplicationDescriptor descriptor, CancellationToken cancellationToken)
async ValueTask<object> IOpenIddictApplicationManager.CreateAsync(OpenIddictApplicationDescriptor descriptor, CancellationToken cancellationToken)
=> await CreateAsync(descriptor, cancellationToken);
Task IOpenIddictApplicationManager.CreateAsync(object application, CancellationToken cancellationToken)
ValueTask IOpenIddictApplicationManager.CreateAsync(object application, CancellationToken cancellationToken)
=> CreateAsync((TApplication) application, cancellationToken);
Task IOpenIddictApplicationManager.CreateAsync(object application, string secret, CancellationToken cancellationToken)
ValueTask IOpenIddictApplicationManager.CreateAsync(object application, string secret, CancellationToken cancellationToken)
=> CreateAsync((TApplication) application, secret, cancellationToken);
Task IOpenIddictApplicationManager.DeleteAsync(object application, CancellationToken cancellationToken)
ValueTask IOpenIddictApplicationManager.DeleteAsync(object application, CancellationToken cancellationToken)
=> DeleteAsync((TApplication) application, cancellationToken);
async Task<object> IOpenIddictApplicationManager.FindByClientIdAsync(string identifier, CancellationToken cancellationToken)
async ValueTask<object> IOpenIddictApplicationManager.FindByClientIdAsync(string identifier, CancellationToken cancellationToken)
=> await FindByClientIdAsync(identifier, cancellationToken);
async Task<object> IOpenIddictApplicationManager.FindByIdAsync(string identifier, CancellationToken cancellationToken)
async ValueTask<object> IOpenIddictApplicationManager.FindByIdAsync(string identifier, CancellationToken cancellationToken)
=> await FindByIdAsync(identifier, cancellationToken);
async Task<ImmutableArray<object>> IOpenIddictApplicationManager.FindByPostLogoutRedirectUriAsync(string address, CancellationToken cancellationToken)
=> (await FindByPostLogoutRedirectUriAsync(address, cancellationToken)).CastArray<object>();
IAsyncEnumerable<object> IOpenIddictApplicationManager.FindByPostLogoutRedirectUriAsync(string address, CancellationToken cancellationToken)
=> FindByPostLogoutRedirectUriAsync(address, cancellationToken).OfType<object>();
async Task<ImmutableArray<object>> IOpenIddictApplicationManager.FindByRedirectUriAsync(string address, CancellationToken cancellationToken)
=> (await FindByRedirectUriAsync(address, cancellationToken)).CastArray<object>();
IAsyncEnumerable<object> IOpenIddictApplicationManager.FindByRedirectUriAsync(string address, CancellationToken cancellationToken)
=> FindByRedirectUriAsync(address, cancellationToken).OfType<object>();
Task<TResult> IOpenIddictApplicationManager.GetAsync<TResult>(Func<IQueryable<object>, IQueryable<TResult>> query, CancellationToken cancellationToken)
ValueTask<TResult> IOpenIddictApplicationManager.GetAsync<TResult>(Func<IQueryable<object>, IQueryable<TResult>> query, CancellationToken cancellationToken)
=> GetAsync(query, cancellationToken);
Task<TResult> IOpenIddictApplicationManager.GetAsync<TState, TResult>(Func<IQueryable<object>, TState, IQueryable<TResult>> query, TState state, CancellationToken cancellationToken)
ValueTask<TResult> IOpenIddictApplicationManager.GetAsync<TState, TResult>(Func<IQueryable<object>, TState, IQueryable<TResult>> query, TState state, CancellationToken cancellationToken)
=> GetAsync(query, state, cancellationToken);
ValueTask<string> IOpenIddictApplicationManager.GetClientIdAsync(object application, CancellationToken cancellationToken)
@ -1296,49 +1232,49 @@ namespace OpenIddict.Core
ValueTask<ImmutableArray<string>> IOpenIddictApplicationManager.GetRedirectUrisAsync(object application, CancellationToken cancellationToken)
=> GetRedirectUrisAsync((TApplication) application, cancellationToken);
Task<bool> IOpenIddictApplicationManager.HasPermissionAsync(object application, string permission, CancellationToken cancellationToken)
ValueTask<bool> IOpenIddictApplicationManager.HasPermissionAsync(object application, string permission, CancellationToken cancellationToken)
=> HasPermissionAsync((TApplication) application, permission, cancellationToken);
Task<bool> IOpenIddictApplicationManager.IsConfidentialAsync(object application, CancellationToken cancellationToken)
ValueTask<bool> IOpenIddictApplicationManager.IsConfidentialAsync(object application, CancellationToken cancellationToken)
=> IsConfidentialAsync((TApplication) application, cancellationToken);
Task<bool> IOpenIddictApplicationManager.IsHybridAsync(object application, CancellationToken cancellationToken)
ValueTask<bool> IOpenIddictApplicationManager.IsHybridAsync(object application, CancellationToken cancellationToken)
=> IsHybridAsync((TApplication) application, cancellationToken);
Task<bool> IOpenIddictApplicationManager.IsPublicAsync(object application, CancellationToken cancellationToken)
ValueTask<bool> IOpenIddictApplicationManager.IsPublicAsync(object application, CancellationToken cancellationToken)
=> IsPublicAsync((TApplication) application, cancellationToken);
async Task<ImmutableArray<object>> IOpenIddictApplicationManager.ListAsync(int? count, int? offset, CancellationToken cancellationToken)
=> (await ListAsync(count, offset, cancellationToken)).CastArray<object>();
IAsyncEnumerable<object> IOpenIddictApplicationManager.ListAsync(int? count, int? offset, CancellationToken cancellationToken)
=> ListAsync(count, offset, cancellationToken).OfType<object>();
Task<ImmutableArray<TResult>> IOpenIddictApplicationManager.ListAsync<TResult>(Func<IQueryable<object>, IQueryable<TResult>> query, CancellationToken cancellationToken)
IAsyncEnumerable<TResult> IOpenIddictApplicationManager.ListAsync<TResult>(Func<IQueryable<object>, IQueryable<TResult>> query, CancellationToken cancellationToken)
=> ListAsync(query, cancellationToken);
Task<ImmutableArray<TResult>> IOpenIddictApplicationManager.ListAsync<TState, TResult>(Func<IQueryable<object>, TState, IQueryable<TResult>> query, TState state, CancellationToken cancellationToken)
IAsyncEnumerable<TResult> IOpenIddictApplicationManager.ListAsync<TState, TResult>(Func<IQueryable<object>, TState, IQueryable<TResult>> query, TState state, CancellationToken cancellationToken)
=> ListAsync(query, state, cancellationToken);
Task IOpenIddictApplicationManager.PopulateAsync(OpenIddictApplicationDescriptor descriptor, object application, CancellationToken cancellationToken)
ValueTask IOpenIddictApplicationManager.PopulateAsync(OpenIddictApplicationDescriptor descriptor, object application, CancellationToken cancellationToken)
=> PopulateAsync(descriptor, (TApplication) application, cancellationToken);
Task IOpenIddictApplicationManager.PopulateAsync(object application, OpenIddictApplicationDescriptor descriptor, CancellationToken cancellationToken)
ValueTask IOpenIddictApplicationManager.PopulateAsync(object application, OpenIddictApplicationDescriptor descriptor, CancellationToken cancellationToken)
=> PopulateAsync((TApplication) application, descriptor, cancellationToken);
Task IOpenIddictApplicationManager.UpdateAsync(object application, CancellationToken cancellationToken)
ValueTask IOpenIddictApplicationManager.UpdateAsync(object application, CancellationToken cancellationToken)
=> UpdateAsync((TApplication) application, cancellationToken);
Task IOpenIddictApplicationManager.UpdateAsync(object application, OpenIddictApplicationDescriptor descriptor, CancellationToken cancellationToken)
ValueTask IOpenIddictApplicationManager.UpdateAsync(object application, OpenIddictApplicationDescriptor descriptor, CancellationToken cancellationToken)
=> UpdateAsync((TApplication) application, descriptor, cancellationToken);
Task IOpenIddictApplicationManager.UpdateAsync(object application, string secret, CancellationToken cancellationToken)
ValueTask IOpenIddictApplicationManager.UpdateAsync(object application, string secret, CancellationToken cancellationToken)
=> UpdateAsync((TApplication) application, secret, cancellationToken);
Task<ImmutableArray<ValidationResult>> IOpenIddictApplicationManager.ValidateAsync(object application, CancellationToken cancellationToken)
IAsyncEnumerable<ValidationResult> IOpenIddictApplicationManager.ValidateAsync(object application, CancellationToken cancellationToken)
=> ValidateAsync((TApplication) application, cancellationToken);
Task<bool> IOpenIddictApplicationManager.ValidateClientSecretAsync(object application, string secret, CancellationToken cancellationToken)
ValueTask<bool> IOpenIddictApplicationManager.ValidateClientSecretAsync(object application, string secret, CancellationToken cancellationToken)
=> ValidateClientSecretAsync((TApplication) application, secret, cancellationToken);
Task<bool> IOpenIddictApplicationManager.ValidateRedirectUriAsync(object application, string address, CancellationToken cancellationToken)
ValueTask<bool> IOpenIddictApplicationManager.ValidateRedirectUriAsync(object application, string address, CancellationToken cancellationToken)
=> ValidateRedirectUriAsync((TApplication) application, address, cancellationToken);
}
}

402
src/OpenIddict.Core/Managers/OpenIddictAuthorizationManager.cs

@ -5,9 +5,11 @@
*/
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
@ -61,10 +63,10 @@ namespace OpenIddict.Core
/// </summary>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the number of authorizations in the database.
/// </returns>
public virtual Task<long> CountAsync(CancellationToken cancellationToken = default)
public virtual ValueTask<long> CountAsync(CancellationToken cancellationToken = default)
=> Store.CountAsync(cancellationToken);
/// <summary>
@ -74,10 +76,10 @@ namespace OpenIddict.Core
/// <param name="query">The query to execute.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the number of authorizations that match the specified query.
/// </returns>
public virtual Task<long> CountAsync<TResult>(
public virtual ValueTask<long> CountAsync<TResult>(
[NotNull] Func<IQueryable<TAuthorization>, IQueryable<TResult>> query, CancellationToken cancellationToken = default)
{
if (query == null)
@ -94,9 +96,9 @@ namespace OpenIddict.Core
/// <param name="authorization">The application to create.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual async Task CreateAsync([NotNull] TAuthorization authorization, CancellationToken cancellationToken = default)
public virtual async ValueTask CreateAsync([NotNull] TAuthorization authorization, CancellationToken cancellationToken = default)
{
if (authorization == null)
{
@ -109,7 +111,7 @@ namespace OpenIddict.Core
await Store.SetStatusAsync(authorization, OpenIddictConstants.Statuses.Valid, cancellationToken);
}
var results = await ValidateAsync(authorization, cancellationToken);
var results = await ValidateAsync(authorization, cancellationToken).ToListAsync(cancellationToken);
if (results.Any(result => result != ValidationResult.Success))
{
var builder = new StringBuilder();
@ -121,7 +123,7 @@ namespace OpenIddict.Core
builder.AppendLine(result.ErrorMessage);
}
throw new OpenIddictExceptions.ValidationException(builder.ToString(), results);
throw new OpenIddictExceptions.ValidationException(builder.ToString(), results.ToImmutableArray());
}
await Store.CreateAsync(authorization, cancellationToken);
@ -138,9 +140,9 @@ namespace OpenIddict.Core
/// <param name="descriptor">The authorization descriptor.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation, whose result returns the authorization.
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation, whose result returns the authorization.
/// </returns>
public virtual async Task<TAuthorization> CreateAsync(
public virtual async ValueTask<TAuthorization> CreateAsync(
[NotNull] OpenIddictAuthorizationDescriptor descriptor, CancellationToken cancellationToken = default)
{
if (descriptor == null)
@ -170,9 +172,9 @@ namespace OpenIddict.Core
/// <param name="scopes">The minimal scopes associated with the authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation, whose result returns the authorization.
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation, whose result returns the authorization.
/// </returns>
public virtual Task<TAuthorization> CreateAsync(
public virtual ValueTask<TAuthorization> CreateAsync(
[NotNull] ImmutableDictionary<string, object> claims, [NotNull] string subject,
[NotNull] string client, [NotNull] string type, ImmutableArray<string> scopes, CancellationToken cancellationToken = default)
{
@ -220,9 +222,9 @@ namespace OpenIddict.Core
/// <param name="authorization">The authorization to delete.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual async Task DeleteAsync([NotNull] TAuthorization authorization, CancellationToken cancellationToken = default)
public virtual async ValueTask DeleteAsync([NotNull] TAuthorization authorization, CancellationToken cancellationToken = default)
{
if (authorization == null)
{
@ -244,11 +246,8 @@ namespace OpenIddict.Core
/// <param name="subject">The subject associated with the authorization.</param>
/// <param name="client">The client associated with the authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the authorizations corresponding to the subject/client.
/// </returns>
public virtual async Task<ImmutableArray<TAuthorization>> FindAsync(
/// <returns>The authorizations corresponding to the subject/client.</returns>
public virtual IAsyncEnumerable<TAuthorization> FindAsync(
[NotNull] string subject, [NotNull] string client, CancellationToken cancellationToken = default)
{
if (string.IsNullOrEmpty(subject))
@ -262,13 +261,8 @@ namespace OpenIddict.Core
}
var authorizations = Options.CurrentValue.DisableEntityCaching ?
await Store.FindAsync(subject, client, cancellationToken) :
await Cache.FindAsync(subject, client, cancellationToken);
if (authorizations.IsEmpty)
{
return ImmutableArray.Create<TAuthorization>();
}
Store.FindAsync(subject, client, cancellationToken) :
Cache.FindAsync(subject, client, cancellationToken);
// SQL engines like Microsoft SQL Server or MySQL are known to use case-insensitive lookups by default.
// To ensure a case-sensitive comparison is enforced independently of the database/table/query collation
@ -279,19 +273,8 @@ namespace OpenIddict.Core
return authorizations;
}
var builder = ImmutableArray.CreateBuilder<TAuthorization>(authorizations.Length);
foreach (var authorization in authorizations)
{
if (string.Equals(await Store.GetSubjectAsync(authorization, cancellationToken), subject, StringComparison.Ordinal))
{
builder.Add(authorization);
}
}
return builder.Count == builder.Capacity ?
builder.MoveToImmutable() :
builder.ToImmutable();
return authorizations.WhereAwait(async authorization => string.Equals(
await Store.GetSubjectAsync(authorization, cancellationToken), subject, StringComparison.Ordinal));
}
/// <summary>
@ -301,11 +284,8 @@ namespace OpenIddict.Core
/// <param name="client">The client associated with the authorization.</param>
/// <param name="status">The authorization status.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the authorizations corresponding to the criteria.
/// </returns>
public virtual async Task<ImmutableArray<TAuthorization>> FindAsync(
/// <returns>The authorizations corresponding to the criteria.</returns>
public virtual IAsyncEnumerable<TAuthorization> FindAsync(
[NotNull] string subject, [NotNull] string client,
[NotNull] string status, CancellationToken cancellationToken = default)
{
@ -325,13 +305,8 @@ namespace OpenIddict.Core
}
var authorizations = Options.CurrentValue.DisableEntityCaching ?
await Store.FindAsync(subject, client, status, cancellationToken) :
await Cache.FindAsync(subject, client, status, cancellationToken);
if (authorizations.IsEmpty)
{
return ImmutableArray.Create<TAuthorization>();
}
Store.FindAsync(subject, client, status, cancellationToken) :
Cache.FindAsync(subject, client, status, cancellationToken);
if (Options.CurrentValue.DisableAdditionalFiltering)
{
@ -342,19 +317,8 @@ namespace OpenIddict.Core
// To ensure a case-sensitive comparison is enforced independently of the database/table/query collation
// used by the store, a second pass using string.Equals(StringComparison.Ordinal) is manually made here.
var builder = ImmutableArray.CreateBuilder<TAuthorization>(authorizations.Length);
foreach (var authorization in authorizations)
{
if (string.Equals(await Store.GetSubjectAsync(authorization, cancellationToken), subject, StringComparison.Ordinal))
{
builder.Add(authorization);
}
}
return builder.Count == builder.Capacity ?
builder.MoveToImmutable() :
builder.ToImmutable();
return authorizations.WhereAwait(async authorization => string.Equals(
await Store.GetSubjectAsync(authorization, cancellationToken), subject, StringComparison.Ordinal));
}
/// <summary>
@ -365,11 +329,8 @@ namespace OpenIddict.Core
/// <param name="status">The authorization status.</param>
/// <param name="type">The authorization type.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the authorizations corresponding to the criteria.
/// </returns>
public virtual async Task<ImmutableArray<TAuthorization>> FindAsync(
/// <returns>The authorizations corresponding to the criteria.</returns>
public virtual IAsyncEnumerable<TAuthorization> FindAsync(
[NotNull] string subject, [NotNull] string client,
[NotNull] string status, [NotNull] string type, CancellationToken cancellationToken = default)
{
@ -394,36 +355,16 @@ namespace OpenIddict.Core
}
var authorizations = Options.CurrentValue.DisableEntityCaching ?
await Store.FindAsync(subject, client, status, type, cancellationToken) :
await Cache.FindAsync(subject, client, status, type, cancellationToken);
if (authorizations.IsEmpty)
{
return ImmutableArray.Create<TAuthorization>();
}
Store.FindAsync(subject, client, status, type, cancellationToken) :
Cache.FindAsync(subject, client, status, type, cancellationToken);
if (Options.CurrentValue.DisableAdditionalFiltering)
{
return authorizations;
}
// SQL engines like Microsoft SQL Server or MySQL are known to use case-insensitive lookups by default.
// To ensure a case-sensitive comparison is enforced independently of the database/table/query collation
// used by the store, a second pass using string.Equals(StringComparison.Ordinal) is manually made here.
var builder = ImmutableArray.CreateBuilder<TAuthorization>(authorizations.Length);
foreach (var authorization in authorizations)
{
if (string.Equals(await Store.GetSubjectAsync(authorization, cancellationToken), subject, StringComparison.Ordinal))
{
builder.Add(authorization);
}
}
return builder.Count == builder.Capacity ?
builder.MoveToImmutable() :
builder.ToImmutable();
return authorizations.WhereAwait(async authorization => string.Equals(
await Store.GetSubjectAsync(authorization, cancellationToken), subject, StringComparison.Ordinal));
}
/// <summary>
@ -435,11 +376,8 @@ namespace OpenIddict.Core
/// <param name="type">The authorization type.</param>
/// <param name="scopes">The minimal scopes associated with the authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the authorizations corresponding to the criteria.
/// </returns>
public virtual async Task<ImmutableArray<TAuthorization>> FindAsync(
/// <returns>The authorizations corresponding to the criteria.</returns>
public virtual IAsyncEnumerable<TAuthorization> FindAsync(
[NotNull] string subject, [NotNull] string client,
[NotNull] string status, [NotNull] string type,
ImmutableArray<string> scopes, CancellationToken cancellationToken = default)
@ -465,13 +403,8 @@ namespace OpenIddict.Core
}
var authorizations = Options.CurrentValue.DisableEntityCaching ?
await Store.FindAsync(subject, client, status, type, scopes, cancellationToken) :
await Cache.FindAsync(subject, client, status, type, scopes, cancellationToken);
if (authorizations.IsEmpty)
{
return ImmutableArray.Create<TAuthorization>();
}
Store.FindAsync(subject, client, status, type, scopes, cancellationToken) :
Cache.FindAsync(subject, client, status, type, scopes, cancellationToken);
if (Options.CurrentValue.DisableAdditionalFiltering)
{
@ -482,20 +415,9 @@ namespace OpenIddict.Core
// To ensure a case-sensitive comparison is enforced independently of the database/table/query collation
// used by the store, a second pass using string.Equals(StringComparison.Ordinal) is manually made here.
var builder = ImmutableArray.CreateBuilder<TAuthorization>(authorizations.Length);
foreach (var authorization in authorizations)
{
if (string.Equals(await Store.GetSubjectAsync(authorization, cancellationToken), subject, StringComparison.Ordinal)
&& await HasScopesAsync(authorization, scopes, cancellationToken))
{
builder.Add(authorization);
}
}
return builder.Count == builder.Capacity ?
builder.MoveToImmutable() :
builder.ToImmutable();
return authorizations.WhereAwait(async authorization => string.Equals(
await Store.GetSubjectAsync(authorization, cancellationToken), subject, StringComparison.Ordinal) &&
await HasScopesAsync(authorization, scopes, cancellationToken));
}
/// <summary>
@ -503,11 +425,8 @@ namespace OpenIddict.Core
/// </summary>
/// <param name="identifier">The application identifier associated with the authorizations.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the authorizations corresponding to the specified application.
/// </returns>
public virtual async Task<ImmutableArray<TAuthorization>> FindByApplicationIdAsync(
/// <returns>The authorizations corresponding to the specified application.</returns>
public virtual IAsyncEnumerable<TAuthorization> FindByApplicationIdAsync(
[NotNull] string identifier, CancellationToken cancellationToken = default)
{
if (string.IsNullOrEmpty(identifier))
@ -516,13 +435,8 @@ namespace OpenIddict.Core
}
var authorizations = Options.CurrentValue.DisableEntityCaching ?
await Store.FindByApplicationIdAsync(identifier, cancellationToken) :
await Cache.FindByApplicationIdAsync(identifier, cancellationToken);
if (authorizations.IsEmpty)
{
return ImmutableArray.Create<TAuthorization>();
}
Store.FindByApplicationIdAsync(identifier, cancellationToken) :
Cache.FindByApplicationIdAsync(identifier, cancellationToken);
if (Options.CurrentValue.DisableAdditionalFiltering)
{
@ -533,19 +447,8 @@ namespace OpenIddict.Core
// To ensure a case-sensitive comparison is enforced independently of the database/table/query collation
// used by the store, a second pass using string.Equals(StringComparison.Ordinal) is manually made here.
var builder = ImmutableArray.CreateBuilder<TAuthorization>(authorizations.Length);
foreach (var authorization in authorizations)
{
if (string.Equals(await Store.GetApplicationIdAsync(authorization, cancellationToken), identifier, StringComparison.Ordinal))
{
builder.Add(authorization);
}
}
return builder.Count == builder.Capacity ?
builder.MoveToImmutable() :
builder.ToImmutable();
return authorizations.WhereAwait(async authorization => string.Equals(
await Store.GetApplicationIdAsync(authorization, cancellationToken), identifier, StringComparison.Ordinal));
}
/// <summary>
@ -554,10 +457,10 @@ namespace OpenIddict.Core
/// <param name="identifier">The unique identifier associated with the authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the authorization corresponding to the identifier.
/// </returns>
public virtual async Task<TAuthorization> FindByIdAsync([NotNull] string identifier, CancellationToken cancellationToken = default)
public virtual async ValueTask<TAuthorization> FindByIdAsync([NotNull] string identifier, CancellationToken cancellationToken = default)
{
if (string.IsNullOrEmpty(identifier))
{
@ -590,11 +493,8 @@ namespace OpenIddict.Core
/// </summary>
/// <param name="subject">The subject associated with the authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the authorizations corresponding to the specified subject.
/// </returns>
public virtual async Task<ImmutableArray<TAuthorization>> FindBySubjectAsync(
/// <returns>The authorizations corresponding to the specified subject.</returns>
public virtual IAsyncEnumerable<TAuthorization> FindBySubjectAsync(
[NotNull] string subject, CancellationToken cancellationToken = default)
{
if (string.IsNullOrEmpty(subject))
@ -603,13 +503,8 @@ namespace OpenIddict.Core
}
var authorizations = Options.CurrentValue.DisableEntityCaching ?
await Store.FindBySubjectAsync(subject, cancellationToken) :
await Cache.FindBySubjectAsync(subject, cancellationToken);
if (authorizations.IsEmpty)
{
return ImmutableArray.Create<TAuthorization>();
}
Store.FindBySubjectAsync(subject, cancellationToken) :
Cache.FindBySubjectAsync(subject, cancellationToken);
if (Options.CurrentValue.DisableAdditionalFiltering)
{
@ -620,19 +515,8 @@ namespace OpenIddict.Core
// To ensure a case-sensitive comparison is enforced independently of the database/table/query collation
// used by the store, a second pass using string.Equals(StringComparison.Ordinal) is manually made here.
var builder = ImmutableArray.CreateBuilder<TAuthorization>(authorizations.Length);
foreach (var authorization in authorizations)
{
if (string.Equals(await Store.GetSubjectAsync(authorization, cancellationToken), subject, StringComparison.Ordinal))
{
builder.Add(authorization);
}
}
return builder.Count == builder.Capacity ?
builder.MoveToImmutable() :
builder.ToImmutable();
return authorizations.WhereAwait(async authorization => string.Equals(
await Store.GetSubjectAsync(authorization, cancellationToken), subject, StringComparison.Ordinal));
}
/// <summary>
@ -662,10 +546,10 @@ namespace OpenIddict.Core
/// <param name="query">The query to execute.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the first element returned when executing the query.
/// </returns>
public virtual Task<TResult> GetAsync<TResult>(
public virtual ValueTask<TResult> GetAsync<TResult>(
[NotNull] Func<IQueryable<TAuthorization>, IQueryable<TResult>> query, CancellationToken cancellationToken = default)
{
if (query == null)
@ -685,10 +569,10 @@ namespace OpenIddict.Core
/// <param name="state">The optional state.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the first element returned when executing the query.
/// </returns>
public virtual Task<TResult> GetAsync<TState, TResult>(
public virtual ValueTask<TResult> GetAsync<TState, TResult>(
[NotNull] Func<IQueryable<TAuthorization>, TState, IQueryable<TResult>> query,
[CanBeNull] TState state, CancellationToken cancellationToken = default)
{
@ -806,7 +690,7 @@ namespace OpenIddict.Core
/// <param name="scopes">The scopes.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns><c>true</c> if the scopes are included in the authorization, <c>false</c> otherwise.</returns>
public virtual async Task<bool> HasScopesAsync([NotNull] TAuthorization authorization,
public virtual async ValueTask<bool> HasScopesAsync([NotNull] TAuthorization authorization,
ImmutableArray<string> scopes, CancellationToken cancellationToken = default)
{
if (authorization == null)
@ -825,7 +709,7 @@ namespace OpenIddict.Core
/// <param name="authorization">The authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns><c>true</c> if the authorization is ad hoc, <c>false</c> otherwise.</returns>
public async Task<bool> IsAdHocAsync([NotNull] TAuthorization authorization, CancellationToken cancellationToken = default)
public async ValueTask<bool> IsAdHocAsync([NotNull] TAuthorization authorization, CancellationToken cancellationToken = default)
{
if (authorization == null)
{
@ -847,7 +731,7 @@ namespace OpenIddict.Core
/// <param name="authorization">The authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns><c>true</c> if the authorization is permanent, <c>false</c> otherwise.</returns>
public async Task<bool> IsPermanentAsync(
public async ValueTask<bool> IsPermanentAsync(
[NotNull] TAuthorization authorization, CancellationToken cancellationToken = default)
{
if (authorization == null)
@ -870,7 +754,7 @@ namespace OpenIddict.Core
/// <param name="authorization">The authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns><c>true</c> if the authorization has been revoked, <c>false</c> otherwise.</returns>
public virtual async Task<bool> IsRevokedAsync(
public virtual async ValueTask<bool> IsRevokedAsync(
[NotNull] TAuthorization authorization, CancellationToken cancellationToken = default)
{
if (authorization == null)
@ -893,7 +777,7 @@ namespace OpenIddict.Core
/// <param name="authorization">The authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns><c>true</c> if the authorization is valid, <c>false</c> otherwise.</returns>
public virtual async Task<bool> IsValidAsync(
public virtual async ValueTask<bool> IsValidAsync(
[NotNull] TAuthorization authorization, CancellationToken cancellationToken = default)
{
if (authorization == null)
@ -916,15 +800,10 @@ namespace OpenIddict.Core
/// <param name="count">The number of results to return.</param>
/// <param name="offset">The number of results to skip.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the elements returned when executing the specified query.
/// </returns>
public virtual Task<ImmutableArray<TAuthorization>> ListAsync(
/// <returns>All the elements returned when executing the specified query.</returns>
public virtual IAsyncEnumerable<TAuthorization> ListAsync(
[CanBeNull] int? count = null, [CanBeNull] int? offset = null, CancellationToken cancellationToken = default)
{
return Store.ListAsync(count, offset, cancellationToken);
}
=> Store.ListAsync(count, offset, cancellationToken);
/// <summary>
/// Executes the specified query and returns all the corresponding elements.
@ -932,11 +811,8 @@ namespace OpenIddict.Core
/// <typeparam name="TResult">The result type.</typeparam>
/// <param name="query">The query to execute.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the elements returned when executing the specified query.
/// </returns>
public virtual Task<ImmutableArray<TResult>> ListAsync<TResult>(
/// <returns>All the elements returned when executing the specified query.</returns>
public virtual IAsyncEnumerable<TResult> ListAsync<TResult>(
[NotNull] Func<IQueryable<TAuthorization>, IQueryable<TResult>> query, CancellationToken cancellationToken = default)
{
if (query == null)
@ -955,11 +831,8 @@ namespace OpenIddict.Core
/// <param name="query">The query to execute.</param>
/// <param name="state">The optional state.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the elements returned when executing the specified query.
/// </returns>
public virtual Task<ImmutableArray<TResult>> ListAsync<TState, TResult>(
/// <returns>All the elements returned when executing the specified query.</returns>
public virtual IAsyncEnumerable<TResult> ListAsync<TState, TResult>(
[NotNull] Func<IQueryable<TAuthorization>, TState, IQueryable<TResult>> query,
[CanBeNull] TState state, CancellationToken cancellationToken = default)
{
@ -978,9 +851,9 @@ namespace OpenIddict.Core
/// <param name="descriptor">The descriptor.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual async Task PopulateAsync([NotNull] TAuthorization authorization,
public virtual async ValueTask PopulateAsync([NotNull] TAuthorization authorization,
[NotNull] OpenIddictAuthorizationDescriptor descriptor, CancellationToken cancellationToken = default)
{
if (authorization == null)
@ -1007,9 +880,9 @@ namespace OpenIddict.Core
/// <param name="authorization">The authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual async Task PopulateAsync(
public virtual async ValueTask PopulateAsync(
[NotNull] OpenIddictAuthorizationDescriptor descriptor,
[NotNull] TAuthorization authorization, CancellationToken cancellationToken = default)
{
@ -1036,9 +909,9 @@ namespace OpenIddict.Core
/// </summary>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task PruneAsync(CancellationToken cancellationToken = default)
public virtual ValueTask PruneAsync(CancellationToken cancellationToken = default)
=> Store.PruneAsync(cancellationToken);
/// <summary>
@ -1046,8 +919,8 @@ namespace OpenIddict.Core
/// </summary>
/// <param name="authorization">The authorization to revoke.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>A <see cref="Task"/> that can be used to monitor the asynchronous operation.</returns>
public virtual async Task RevokeAsync([NotNull] TAuthorization authorization, CancellationToken cancellationToken = default)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual async ValueTask RevokeAsync([NotNull] TAuthorization authorization, CancellationToken cancellationToken = default)
{
if (authorization == null)
{
@ -1069,9 +942,9 @@ namespace OpenIddict.Core
/// <param name="identifier">The unique identifier associated with the client application.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual async Task SetApplicationIdAsync(
public virtual async ValueTask SetApplicationIdAsync(
[NotNull] TAuthorization authorization, [CanBeNull] string identifier, CancellationToken cancellationToken = default)
{
if (authorization == null)
@ -1089,16 +962,16 @@ namespace OpenIddict.Core
/// <param name="authorization">The authorization to update.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual async Task UpdateAsync([NotNull] TAuthorization authorization, CancellationToken cancellationToken = default)
public virtual async ValueTask UpdateAsync([NotNull] TAuthorization authorization, CancellationToken cancellationToken = default)
{
if (authorization == null)
{
throw new ArgumentNullException(nameof(authorization));
}
var results = await ValidateAsync(authorization, cancellationToken);
var results = await ValidateAsync(authorization, cancellationToken).ToListAsync(cancellationToken);
if (results.Any(result => result != ValidationResult.Success))
{
var builder = new StringBuilder();
@ -1110,7 +983,7 @@ namespace OpenIddict.Core
builder.AppendLine(result.ErrorMessage);
}
throw new OpenIddictExceptions.ValidationException(builder.ToString(), results);
throw new OpenIddictExceptions.ValidationException(builder.ToString(), results.ToImmutableArray());
}
await Store.UpdateAsync(authorization, cancellationToken);
@ -1129,9 +1002,9 @@ namespace OpenIddict.Core
/// <param name="descriptor">The descriptor used to update the authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual async Task UpdateAsync([NotNull] TAuthorization authorization,
public virtual async ValueTask UpdateAsync([NotNull] TAuthorization authorization,
[NotNull] OpenIddictAuthorizationDescriptor descriptor, CancellationToken cancellationToken = default)
{
if (authorization == null)
@ -1153,12 +1026,9 @@ namespace OpenIddict.Core
/// </summary>
/// <param name="authorization">The authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the validation error encountered when validating the authorization.
/// </returns>
public virtual async Task<ImmutableArray<ValidationResult>> ValidateAsync(
[NotNull] TAuthorization authorization, CancellationToken cancellationToken = default)
/// <returns>The validation error encountered when validating the authorization.</returns>
public virtual async IAsyncEnumerable<ValidationResult> ValidateAsync(
[NotNull] TAuthorization authorization, [EnumeratorCancellation] CancellationToken cancellationToken = default)
{
if (authorization == null)
{
@ -1170,23 +1040,23 @@ namespace OpenIddict.Core
var type = await Store.GetTypeAsync(authorization, cancellationToken);
if (string.IsNullOrEmpty(type))
{
builder.Add(new ValidationResult("The authorization type cannot be null or empty."));
yield return new ValidationResult("The authorization type cannot be null or empty.");
}
else if (!string.Equals(type, OpenIddictConstants.AuthorizationTypes.AdHoc, StringComparison.OrdinalIgnoreCase) &&
!string.Equals(type, OpenIddictConstants.AuthorizationTypes.Permanent, StringComparison.OrdinalIgnoreCase))
{
builder.Add(new ValidationResult("The specified authorization type is not supported by the default token manager."));
yield return new ValidationResult("The specified authorization type is not supported by the default token manager.");
}
if (string.IsNullOrEmpty(await Store.GetStatusAsync(authorization, cancellationToken)))
{
builder.Add(new ValidationResult("The status cannot be null or empty."));
yield return new ValidationResult("The status cannot be null or empty.");
}
if (string.IsNullOrEmpty(await Store.GetSubjectAsync(authorization, cancellationToken)))
{
builder.Add(new ValidationResult("The subject cannot be null or empty."));
yield return new ValidationResult("The subject cannot be null or empty.");
}
// Ensure that the scopes are not null or empty and do not contain spaces.
@ -1194,70 +1064,66 @@ namespace OpenIddict.Core
{
if (string.IsNullOrEmpty(scope))
{
builder.Add(new ValidationResult("Scopes cannot be null or empty."));
yield return new ValidationResult("Scopes cannot be null or empty.");
break;
}
if (scope.Contains(OpenIddictConstants.Separators.Space[0]))
{
builder.Add(new ValidationResult("Scopes cannot contain spaces."));
yield return new ValidationResult("Scopes cannot contain spaces.");
break;
}
}
return builder.Count == builder.Capacity ?
builder.MoveToImmutable() :
builder.ToImmutable();
}
Task<long> IOpenIddictAuthorizationManager.CountAsync(CancellationToken cancellationToken)
ValueTask<long> IOpenIddictAuthorizationManager.CountAsync(CancellationToken cancellationToken)
=> CountAsync(cancellationToken);
Task<long> IOpenIddictAuthorizationManager.CountAsync<TResult>(Func<IQueryable<object>, IQueryable<TResult>> query, CancellationToken cancellationToken)
ValueTask<long> IOpenIddictAuthorizationManager.CountAsync<TResult>(Func<IQueryable<object>, IQueryable<TResult>> query, CancellationToken cancellationToken)
=> CountAsync(query, cancellationToken);
async Task<object> IOpenIddictAuthorizationManager.CreateAsync(ImmutableDictionary<string, object> claims, string subject, string client, string type, ImmutableArray<string> scopes, CancellationToken cancellationToken)
async ValueTask<object> IOpenIddictAuthorizationManager.CreateAsync(ImmutableDictionary<string, object> claims, string subject, string client, string type, ImmutableArray<string> scopes, CancellationToken cancellationToken)
=> await CreateAsync(claims, subject, client, type, scopes, cancellationToken);
async Task<object> IOpenIddictAuthorizationManager.CreateAsync(OpenIddictAuthorizationDescriptor descriptor, CancellationToken cancellationToken)
async ValueTask<object> IOpenIddictAuthorizationManager.CreateAsync(OpenIddictAuthorizationDescriptor descriptor, CancellationToken cancellationToken)
=> await CreateAsync(descriptor, cancellationToken);
Task IOpenIddictAuthorizationManager.CreateAsync(object authorization, CancellationToken cancellationToken)
ValueTask IOpenIddictAuthorizationManager.CreateAsync(object authorization, CancellationToken cancellationToken)
=> CreateAsync((TAuthorization) authorization, cancellationToken);
Task IOpenIddictAuthorizationManager.DeleteAsync(object authorization, CancellationToken cancellationToken)
ValueTask IOpenIddictAuthorizationManager.DeleteAsync(object authorization, CancellationToken cancellationToken)
=> DeleteAsync((TAuthorization) authorization, cancellationToken);
async Task<ImmutableArray<object>> IOpenIddictAuthorizationManager.FindAsync(string subject, string client, CancellationToken cancellationToken)
=> (await FindAsync(subject, client, cancellationToken)).CastArray<object>();
IAsyncEnumerable<object> IOpenIddictAuthorizationManager.FindAsync(string subject, string client, CancellationToken cancellationToken)
=> FindAsync(subject, client, cancellationToken).OfType<object>();
async Task<ImmutableArray<object>> IOpenIddictAuthorizationManager.FindAsync(string subject, string client, string status, CancellationToken cancellationToken)
=> (await FindAsync(subject, client, status, cancellationToken)).CastArray<object>();
IAsyncEnumerable<object> IOpenIddictAuthorizationManager.FindAsync(string subject, string client, string status, CancellationToken cancellationToken)
=> FindAsync(subject, client, status, cancellationToken).OfType<object>();
async Task<ImmutableArray<object>> IOpenIddictAuthorizationManager.FindAsync(string subject, string client, string status, string type, CancellationToken cancellationToken)
=> (await FindAsync(subject, client, status, type, cancellationToken)).CastArray<object>();
IAsyncEnumerable<object> IOpenIddictAuthorizationManager.FindAsync(string subject, string client, string status, string type, CancellationToken cancellationToken)
=> FindAsync(subject, client, status, type, cancellationToken).OfType<object>();
async Task<ImmutableArray<object>> IOpenIddictAuthorizationManager.FindAsync(string subject, string client, string status, string type, ImmutableArray<string> scopes, CancellationToken cancellationToken)
=> (await FindAsync(subject, client, status, type, scopes, cancellationToken)).CastArray<object>();
IAsyncEnumerable<object> IOpenIddictAuthorizationManager.FindAsync(string subject, string client, string status, string type, ImmutableArray<string> scopes, CancellationToken cancellationToken)
=> FindAsync(subject, client, status, type, scopes, cancellationToken).OfType<object>();
async Task<ImmutableArray<object>> IOpenIddictAuthorizationManager.FindByApplicationIdAsync(string identifier, CancellationToken cancellationToken)
=> (await FindByApplicationIdAsync(identifier, cancellationToken)).CastArray<object>();
IAsyncEnumerable<object> IOpenIddictAuthorizationManager.FindByApplicationIdAsync(string identifier, CancellationToken cancellationToken)
=> FindByApplicationIdAsync(identifier, cancellationToken).OfType<object>();
async Task<object> IOpenIddictAuthorizationManager.FindByIdAsync(string identifier, CancellationToken cancellationToken)
async ValueTask<object> IOpenIddictAuthorizationManager.FindByIdAsync(string identifier, CancellationToken cancellationToken)
=> await FindByIdAsync(identifier, cancellationToken);
async Task<ImmutableArray<object>> IOpenIddictAuthorizationManager.FindBySubjectAsync(string subject, CancellationToken cancellationToken)
=> (await FindBySubjectAsync(subject, cancellationToken)).CastArray<object>();
IAsyncEnumerable<object> IOpenIddictAuthorizationManager.FindBySubjectAsync(string subject, CancellationToken cancellationToken)
=> FindBySubjectAsync(subject, cancellationToken).OfType<object>();
ValueTask<string> IOpenIddictAuthorizationManager.GetApplicationIdAsync(object authorization, CancellationToken cancellationToken)
=> GetApplicationIdAsync((TAuthorization) authorization, cancellationToken);
Task<TResult> IOpenIddictAuthorizationManager.GetAsync<TResult>(Func<IQueryable<object>, IQueryable<TResult>> query, CancellationToken cancellationToken)
ValueTask<TResult> IOpenIddictAuthorizationManager.GetAsync<TResult>(Func<IQueryable<object>, IQueryable<TResult>> query, CancellationToken cancellationToken)
=> GetAsync(query, cancellationToken);
Task<TResult> IOpenIddictAuthorizationManager.GetAsync<TState, TResult>(Func<IQueryable<object>, TState, IQueryable<TResult>> query, TState state, CancellationToken cancellationToken)
ValueTask<TResult> IOpenIddictAuthorizationManager.GetAsync<TState, TResult>(Func<IQueryable<object>, TState, IQueryable<TResult>> query, TState state, CancellationToken cancellationToken)
=> GetAsync(query, state, cancellationToken);
ValueTask<string> IOpenIddictAuthorizationManager.GetIdAsync(object authorization, CancellationToken cancellationToken)
@ -1275,52 +1141,52 @@ namespace OpenIddict.Core
ValueTask<string> IOpenIddictAuthorizationManager.GetTypeAsync(object authorization, CancellationToken cancellationToken)
=> GetTypeAsync((TAuthorization) authorization, cancellationToken);
Task<bool> IOpenIddictAuthorizationManager.HasScopesAsync(object authorization, ImmutableArray<string> scopes, CancellationToken cancellationToken)
ValueTask<bool> IOpenIddictAuthorizationManager.HasScopesAsync(object authorization, ImmutableArray<string> scopes, CancellationToken cancellationToken)
=> HasScopesAsync((TAuthorization) authorization, scopes, cancellationToken);
Task<bool> IOpenIddictAuthorizationManager.IsAdHocAsync(object authorization, CancellationToken cancellationToken)
ValueTask<bool> IOpenIddictAuthorizationManager.IsAdHocAsync(object authorization, CancellationToken cancellationToken)
=> IsAdHocAsync((TAuthorization) authorization, cancellationToken);
Task<bool> IOpenIddictAuthorizationManager.IsPermanentAsync(object authorization, CancellationToken cancellationToken)
ValueTask<bool> IOpenIddictAuthorizationManager.IsPermanentAsync(object authorization, CancellationToken cancellationToken)
=> IsPermanentAsync((TAuthorization) authorization, cancellationToken);
Task<bool> IOpenIddictAuthorizationManager.IsRevokedAsync(object authorization, CancellationToken cancellationToken)
ValueTask<bool> IOpenIddictAuthorizationManager.IsRevokedAsync(object authorization, CancellationToken cancellationToken)
=> IsRevokedAsync((TAuthorization) authorization, cancellationToken);
Task<bool> IOpenIddictAuthorizationManager.IsValidAsync(object authorization, CancellationToken cancellationToken)
ValueTask<bool> IOpenIddictAuthorizationManager.IsValidAsync(object authorization, CancellationToken cancellationToken)
=> IsValidAsync((TAuthorization) authorization, cancellationToken);
async Task<ImmutableArray<object>> IOpenIddictAuthorizationManager.ListAsync(int? count, int? offset, CancellationToken cancellationToken)
=> (await ListAsync(count, offset, cancellationToken)).CastArray<object>();
IAsyncEnumerable<object> IOpenIddictAuthorizationManager.ListAsync(int? count, int? offset, CancellationToken cancellationToken)
=> ListAsync(count, offset, cancellationToken).OfType<object>();
Task<ImmutableArray<TResult>> IOpenIddictAuthorizationManager.ListAsync<TResult>(Func<IQueryable<object>, IQueryable<TResult>> query, CancellationToken cancellationToken)
IAsyncEnumerable<TResult> IOpenIddictAuthorizationManager.ListAsync<TResult>(Func<IQueryable<object>, IQueryable<TResult>> query, CancellationToken cancellationToken)
=> ListAsync(query, cancellationToken);
Task<ImmutableArray<TResult>> IOpenIddictAuthorizationManager.ListAsync<TState, TResult>(Func<IQueryable<object>, TState, IQueryable<TResult>> query, TState state, CancellationToken cancellationToken)
IAsyncEnumerable<TResult> IOpenIddictAuthorizationManager.ListAsync<TState, TResult>(Func<IQueryable<object>, TState, IQueryable<TResult>> query, TState state, CancellationToken cancellationToken)
=> ListAsync(query, state, cancellationToken);
Task IOpenIddictAuthorizationManager.PopulateAsync(OpenIddictAuthorizationDescriptor descriptor, object authorization, CancellationToken cancellationToken)
ValueTask IOpenIddictAuthorizationManager.PopulateAsync(OpenIddictAuthorizationDescriptor descriptor, object authorization, CancellationToken cancellationToken)
=> PopulateAsync(descriptor, (TAuthorization) authorization, cancellationToken);
Task IOpenIddictAuthorizationManager.PopulateAsync(object authorization, OpenIddictAuthorizationDescriptor descriptor, CancellationToken cancellationToken)
ValueTask IOpenIddictAuthorizationManager.PopulateAsync(object authorization, OpenIddictAuthorizationDescriptor descriptor, CancellationToken cancellationToken)
=> PopulateAsync((TAuthorization) authorization, descriptor, cancellationToken);
Task IOpenIddictAuthorizationManager.PruneAsync(CancellationToken cancellationToken)
ValueTask IOpenIddictAuthorizationManager.PruneAsync(CancellationToken cancellationToken)
=> PruneAsync(cancellationToken);
Task IOpenIddictAuthorizationManager.RevokeAsync(object authorization, CancellationToken cancellationToken)
ValueTask IOpenIddictAuthorizationManager.RevokeAsync(object authorization, CancellationToken cancellationToken)
=> RevokeAsync((TAuthorization) authorization, cancellationToken);
Task IOpenIddictAuthorizationManager.SetApplicationIdAsync(object authorization, string identifier, CancellationToken cancellationToken)
ValueTask IOpenIddictAuthorizationManager.SetApplicationIdAsync(object authorization, string identifier, CancellationToken cancellationToken)
=> SetApplicationIdAsync((TAuthorization) authorization, identifier, cancellationToken);
Task IOpenIddictAuthorizationManager.UpdateAsync(object authorization, CancellationToken cancellationToken)
ValueTask IOpenIddictAuthorizationManager.UpdateAsync(object authorization, CancellationToken cancellationToken)
=> UpdateAsync((TAuthorization) authorization, cancellationToken);
Task IOpenIddictAuthorizationManager.UpdateAsync(object authorization, OpenIddictAuthorizationDescriptor descriptor, CancellationToken cancellationToken)
ValueTask IOpenIddictAuthorizationManager.UpdateAsync(object authorization, OpenIddictAuthorizationDescriptor descriptor, CancellationToken cancellationToken)
=> UpdateAsync((TAuthorization) authorization, descriptor, cancellationToken);
Task<ImmutableArray<ValidationResult>> IOpenIddictAuthorizationManager.ValidateAsync(object authorization, CancellationToken cancellationToken)
IAsyncEnumerable<ValidationResult> IOpenIddictAuthorizationManager.ValidateAsync(object authorization, CancellationToken cancellationToken)
=> ValidateAsync((TAuthorization) authorization, cancellationToken);
}
}

246
src/OpenIddict.Core/Managers/OpenIddictScopeManager.cs

@ -9,6 +9,7 @@ using System.Collections.Generic;
using System.Collections.Immutable;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
@ -62,10 +63,10 @@ namespace OpenIddict.Core
/// </summary>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the number of scopes in the database.
/// </returns>
public virtual Task<long> CountAsync(CancellationToken cancellationToken = default)
public virtual ValueTask<long> CountAsync(CancellationToken cancellationToken = default)
=> Store.CountAsync(cancellationToken);
/// <summary>
@ -75,10 +76,10 @@ namespace OpenIddict.Core
/// <param name="query">The query to execute.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the number of scopes that match the specified query.
/// </returns>
public virtual Task<long> CountAsync<TResult>(
public virtual ValueTask<long> CountAsync<TResult>(
[NotNull] Func<IQueryable<TScope>, IQueryable<TResult>> query, CancellationToken cancellationToken = default)
{
if (query == null)
@ -95,16 +96,16 @@ namespace OpenIddict.Core
/// <param name="scope">The scope to create.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual async Task CreateAsync([NotNull] TScope scope, CancellationToken cancellationToken = default)
public virtual async ValueTask CreateAsync([NotNull] TScope scope, CancellationToken cancellationToken = default)
{
if (scope == null)
{
throw new ArgumentNullException(nameof(scope));
}
var results = await ValidateAsync(scope, cancellationToken);
var results = await ValidateAsync(scope, cancellationToken).ToListAsync(cancellationToken);
if (results.Any(result => result != ValidationResult.Success))
{
var builder = new StringBuilder();
@ -116,7 +117,7 @@ namespace OpenIddict.Core
builder.AppendLine(result.ErrorMessage);
}
throw new OpenIddictExceptions.ValidationException(builder.ToString(), results);
throw new OpenIddictExceptions.ValidationException(builder.ToString(), results.ToImmutableArray());
}
await Store.CreateAsync(scope, cancellationToken);
@ -133,9 +134,9 @@ namespace OpenIddict.Core
/// <param name="descriptor">The scope descriptor.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation, whose result returns the scope.
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation, whose result returns the scope.
/// </returns>
public virtual async Task<TScope> CreateAsync(
public virtual async ValueTask<TScope> CreateAsync(
[NotNull] OpenIddictScopeDescriptor descriptor, CancellationToken cancellationToken = default)
{
if (descriptor == null)
@ -161,9 +162,9 @@ namespace OpenIddict.Core
/// <param name="scope">The scope to delete.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual async Task DeleteAsync([NotNull] TScope scope, CancellationToken cancellationToken = default)
public virtual async ValueTask DeleteAsync([NotNull] TScope scope, CancellationToken cancellationToken = default)
{
if (scope == null)
{
@ -184,10 +185,10 @@ namespace OpenIddict.Core
/// <param name="identifier">The unique identifier associated with the scope.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the scope corresponding to the identifier.
/// </returns>
public virtual async Task<TScope> FindByIdAsync([NotNull] string identifier, CancellationToken cancellationToken = default)
public virtual async ValueTask<TScope> FindByIdAsync([NotNull] string identifier, CancellationToken cancellationToken = default)
{
if (string.IsNullOrEmpty(identifier))
{
@ -221,10 +222,10 @@ namespace OpenIddict.Core
/// <param name="name">The name associated with the scope.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the scope corresponding to the specified name.
/// </returns>
public virtual async Task<TScope> FindByNameAsync([NotNull] string name, CancellationToken cancellationToken = default)
public virtual async ValueTask<TScope> FindByNameAsync([NotNull] string name, CancellationToken cancellationToken = default)
{
if (string.IsNullOrEmpty(name))
{
@ -258,16 +259,13 @@ namespace OpenIddict.Core
/// </summary>
/// <param name="names">The names associated with the scopes.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the scopes corresponding to the specified names.
/// </returns>
public virtual async Task<ImmutableArray<TScope>> FindByNamesAsync(
/// <returns>The scopes corresponding to the specified names.</returns>
public virtual IAsyncEnumerable<TScope> FindByNamesAsync(
ImmutableArray<string> names, CancellationToken cancellationToken = default)
{
if (names.IsDefaultOrEmpty)
{
return ImmutableArray.Create<TScope>();
return AsyncEnumerable.Empty<TScope>();
}
if (names.Any(name => string.IsNullOrEmpty(name)))
@ -276,13 +274,8 @@ namespace OpenIddict.Core
}
var scopes = Options.CurrentValue.DisableEntityCaching ?
await Store.FindByNamesAsync(names, cancellationToken) :
await Cache.FindByNamesAsync(names, cancellationToken);
if (scopes.IsEmpty)
{
return ImmutableArray.Create<TScope>();
}
Store.FindByNamesAsync(names, cancellationToken) :
Cache.FindByNamesAsync(names, cancellationToken);
if (Options.CurrentValue.DisableAdditionalFiltering)
{
@ -293,19 +286,7 @@ namespace OpenIddict.Core
// To ensure a case-sensitive comparison is enforced independently of the database/table/query collation
// used by the store, a second pass using string.Equals(StringComparison.Ordinal) is manually made here.
var builder = ImmutableArray.CreateBuilder<TScope>(scopes.Length);
foreach (var scope in scopes)
{
if (names.Contains(await Store.GetNameAsync(scope, cancellationToken)))
{
builder.Add(scope);
}
}
return builder.Count == builder.Capacity ?
builder.MoveToImmutable() :
builder.ToImmutable();
return scopes.WhereAwait(async scope => names.Contains(await Store.GetNameAsync(scope, cancellationToken), StringComparer.Ordinal));
}
/// <summary>
@ -313,11 +294,8 @@ namespace OpenIddict.Core
/// </summary>
/// <param name="resource">The resource associated with the scopes.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the scopes associated with the specified resource.
/// </returns>
public virtual async Task<ImmutableArray<TScope>> FindByResourceAsync(
/// <returns>The scopes associated with the specified resource.</returns>
public virtual IAsyncEnumerable<TScope> FindByResourceAsync(
[NotNull] string resource, CancellationToken cancellationToken = default)
{
if (string.IsNullOrEmpty(resource))
@ -326,13 +304,8 @@ namespace OpenIddict.Core
}
var scopes = Options.CurrentValue.DisableEntityCaching ?
await Store.FindByResourceAsync(resource, cancellationToken) :
await Cache.FindByResourceAsync(resource, cancellationToken);
if (scopes.IsEmpty)
{
return ImmutableArray.Create<TScope>();
}
Store.FindByResourceAsync(resource, cancellationToken) :
Cache.FindByResourceAsync(resource, cancellationToken);
if (Options.CurrentValue.DisableAdditionalFiltering)
{
@ -343,22 +316,8 @@ namespace OpenIddict.Core
// To ensure a case-sensitive comparison is enforced independently of the database/table/query collation
// used by the store, a second pass using string.Equals(StringComparison.Ordinal) is manually made here.
var builder = ImmutableArray.CreateBuilder<TScope>(scopes.Length);
foreach (var scope in scopes)
{
foreach (var value in await Store.GetResourcesAsync(scope, cancellationToken))
{
if (string.Equals(value, resource, StringComparison.Ordinal))
{
builder.Add(scope);
}
}
}
return builder.Count == builder.Capacity ?
builder.MoveToImmutable() :
builder.ToImmutable();
return scopes.WhereAwait(async scope =>
(await Store.GetResourcesAsync(scope, cancellationToken)).Contains(resource, StringComparer.Ordinal));
}
/// <summary>
@ -368,10 +327,10 @@ namespace OpenIddict.Core
/// <param name="query">The query to execute.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the first element returned when executing the query.
/// </returns>
public virtual Task<TResult> GetAsync<TResult>(
public virtual ValueTask<TResult> GetAsync<TResult>(
[NotNull] Func<IQueryable<TScope>, IQueryable<TResult>> query, CancellationToken cancellationToken = default)
{
if (query == null)
@ -391,10 +350,10 @@ namespace OpenIddict.Core
/// <param name="state">The optional state.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the first element returned when executing the query.
/// </returns>
public virtual Task<TResult> GetAsync<TState, TResult>(
public virtual ValueTask<TResult> GetAsync<TState, TResult>(
[NotNull] Func<IQueryable<TScope>, TState, IQueryable<TResult>> query,
[CanBeNull] TState state, CancellationToken cancellationToken = default)
{
@ -508,15 +467,10 @@ namespace OpenIddict.Core
/// <param name="count">The number of results to return.</param>
/// <param name="offset">The number of results to skip.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the elements returned when executing the specified query.
/// </returns>
public virtual Task<ImmutableArray<TScope>> ListAsync(
/// <returns>All the elements returned when executing the specified query.</returns>
public virtual IAsyncEnumerable<TScope> ListAsync(
[CanBeNull] int? count = null, [CanBeNull] int? offset = null, CancellationToken cancellationToken = default)
{
return Store.ListAsync(count, offset, cancellationToken);
}
=> Store.ListAsync(count, offset, cancellationToken);
/// <summary>
/// Executes the specified query and returns all the corresponding elements.
@ -524,11 +478,8 @@ namespace OpenIddict.Core
/// <typeparam name="TResult">The result type.</typeparam>
/// <param name="query">The query to execute.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the elements returned when executing the specified query.
/// </returns>
public virtual Task<ImmutableArray<TResult>> ListAsync<TResult>(
/// <returns>All the elements returned when executing the specified query.</returns>
public virtual IAsyncEnumerable<TResult> ListAsync<TResult>(
[NotNull] Func<IQueryable<TScope>, IQueryable<TResult>> query, CancellationToken cancellationToken = default)
{
if (query == null)
@ -547,11 +498,8 @@ namespace OpenIddict.Core
/// <param name="query">The query to execute.</param>
/// <param name="state">The optional state.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the elements returned when executing the specified query.
/// </returns>
public virtual Task<ImmutableArray<TResult>> ListAsync<TState, TResult>(
/// <returns>All the elements returned when executing the specified query.</returns>
public virtual IAsyncEnumerable<TResult> ListAsync<TState, TResult>(
[NotNull] Func<IQueryable<TScope>, TState, IQueryable<TResult>> query,
[CanBeNull] TState state, CancellationToken cancellationToken = default)
{
@ -568,32 +516,31 @@ namespace OpenIddict.Core
/// </summary>
/// <param name="scopes">The scopes.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the resources associated with the specified scopes.
/// </returns>
public virtual async Task<ImmutableArray<string>> ListResourcesAsync(
/// <returns>All the resources associated with the specified scopes.</returns>
public virtual IAsyncEnumerable<string> ListResourcesAsync(
ImmutableArray<string> scopes, CancellationToken cancellationToken = default)
{
if (scopes.IsDefaultOrEmpty)
{
return ImmutableArray.Create<string>();
return AsyncEnumerable.Empty<string>();
}
var set = new HashSet<string>(StringComparer.Ordinal);
return ExecuteAsync(cancellationToken);
foreach (var scope in await FindByNamesAsync(scopes, cancellationToken))
async IAsyncEnumerable<string> ExecuteAsync(CancellationToken cancellationToken)
{
var resources = await GetResourcesAsync(scope, cancellationToken);
if (resources.IsDefaultOrEmpty)
var resources = new HashSet<string>(StringComparer.Ordinal);
await foreach (var scope in FindByNamesAsync(scopes, cancellationToken))
{
continue;
resources.UnionWith(await GetResourcesAsync(scope, cancellationToken));
}
set.UnionWith(resources);
foreach (var resource in resources)
{
yield return resource;
}
}
return set.ToImmutableArray();
}
/// <summary>
@ -603,9 +550,9 @@ namespace OpenIddict.Core
/// <param name="descriptor">The descriptor.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual async Task PopulateAsync([NotNull] TScope scope,
public virtual async ValueTask PopulateAsync([NotNull] TScope scope,
[NotNull] OpenIddictScopeDescriptor descriptor, CancellationToken cancellationToken = default)
{
if (scope == null)
@ -631,9 +578,9 @@ namespace OpenIddict.Core
/// <param name="scope">The scope.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual async Task PopulateAsync(
public virtual async ValueTask PopulateAsync(
[NotNull] OpenIddictScopeDescriptor descriptor,
[NotNull] TScope scope, CancellationToken cancellationToken = default)
{
@ -660,16 +607,16 @@ namespace OpenIddict.Core
/// <param name="scope">The scope to update.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual async Task UpdateAsync([NotNull] TScope scope, CancellationToken cancellationToken = default)
public virtual async ValueTask UpdateAsync([NotNull] TScope scope, CancellationToken cancellationToken = default)
{
if (scope == null)
{
throw new ArgumentNullException(nameof(scope));
}
var results = await ValidateAsync(scope, cancellationToken);
var results = await ValidateAsync(scope, cancellationToken).ToListAsync(cancellationToken);
if (results.Any(result => result != ValidationResult.Success))
{
var builder = new StringBuilder();
@ -681,7 +628,7 @@ namespace OpenIddict.Core
builder.AppendLine(result.ErrorMessage);
}
throw new OpenIddictExceptions.ValidationException(builder.ToString(), results);
throw new OpenIddictExceptions.ValidationException(builder.ToString(), results.ToImmutableArray());
}
await Store.UpdateAsync(scope, cancellationToken);
@ -700,9 +647,9 @@ namespace OpenIddict.Core
/// <param name="descriptor">The descriptor used to update the scope.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual async Task UpdateAsync([NotNull] TScope scope,
public virtual async ValueTask UpdateAsync([NotNull] TScope scope,
[NotNull] OpenIddictScopeDescriptor descriptor, CancellationToken cancellationToken = default)
{
if (scope == null)
@ -724,31 +671,26 @@ namespace OpenIddict.Core
/// </summary>
/// <param name="scope">The scope.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the validation error encountered when validating the scope.
/// </returns>
public virtual async Task<ImmutableArray<ValidationResult>> ValidateAsync(
[NotNull] TScope scope, CancellationToken cancellationToken = default)
/// <returns>The validation error encountered when validating the scope.</returns>
public virtual async IAsyncEnumerable<ValidationResult> ValidateAsync(
[NotNull] TScope scope, [EnumeratorCancellation] CancellationToken cancellationToken = default)
{
if (scope == null)
{
throw new ArgumentNullException(nameof(scope));
}
var builder = ImmutableArray.CreateBuilder<ValidationResult>();
// Ensure the name is not null or empty, does not contain a
// space and is not already used for a different scope entity.
var name = await Store.GetNameAsync(scope, cancellationToken);
if (string.IsNullOrEmpty(name))
{
builder.Add(new ValidationResult("The scope name cannot be null or empty."));
yield return new ValidationResult("The scope name cannot be null or empty.");
}
else if (name.Contains(OpenIddictConstants.Separators.Space[0]))
{
builder.Add(new ValidationResult("The scope name cannot contain spaces."));
yield return new ValidationResult("The scope name cannot contain spaces.");
}
else
@ -762,46 +704,42 @@ namespace OpenIddict.Core
await Store.GetIdAsync(other, cancellationToken),
await Store.GetIdAsync(scope, cancellationToken), StringComparison.Ordinal))
{
builder.Add(new ValidationResult("A scope with the same name already exists."));
yield return new ValidationResult("A scope with the same name already exists.");
}
}
return builder.Count == builder.Capacity ?
builder.MoveToImmutable() :
builder.ToImmutable();
}
Task<long> IOpenIddictScopeManager.CountAsync(CancellationToken cancellationToken)
ValueTask<long> IOpenIddictScopeManager.CountAsync(CancellationToken cancellationToken)
=> CountAsync(cancellationToken);
Task<long> IOpenIddictScopeManager.CountAsync<TResult>(Func<IQueryable<object>, IQueryable<TResult>> query, CancellationToken cancellationToken)
ValueTask<long> IOpenIddictScopeManager.CountAsync<TResult>(Func<IQueryable<object>, IQueryable<TResult>> query, CancellationToken cancellationToken)
=> CountAsync(query, cancellationToken);
async Task<object> IOpenIddictScopeManager.CreateAsync(OpenIddictScopeDescriptor descriptor, CancellationToken cancellationToken)
async ValueTask<object> IOpenIddictScopeManager.CreateAsync(OpenIddictScopeDescriptor descriptor, CancellationToken cancellationToken)
=> await CreateAsync(descriptor, cancellationToken);
Task IOpenIddictScopeManager.CreateAsync(object scope, CancellationToken cancellationToken)
ValueTask IOpenIddictScopeManager.CreateAsync(object scope, CancellationToken cancellationToken)
=> CreateAsync((TScope) scope, cancellationToken);
Task IOpenIddictScopeManager.DeleteAsync(object scope, CancellationToken cancellationToken)
ValueTask IOpenIddictScopeManager.DeleteAsync(object scope, CancellationToken cancellationToken)
=> DeleteAsync((TScope) scope, cancellationToken);
async Task<object> IOpenIddictScopeManager.FindByIdAsync(string identifier, CancellationToken cancellationToken)
async ValueTask<object> IOpenIddictScopeManager.FindByIdAsync(string identifier, CancellationToken cancellationToken)
=> await FindByIdAsync(identifier, cancellationToken);
async Task<object> IOpenIddictScopeManager.FindByNameAsync(string name, CancellationToken cancellationToken)
async ValueTask<object> IOpenIddictScopeManager.FindByNameAsync(string name, CancellationToken cancellationToken)
=> await FindByNameAsync(name, cancellationToken);
async Task<ImmutableArray<object>> IOpenIddictScopeManager.FindByNamesAsync(ImmutableArray<string> names, CancellationToken cancellationToken)
=> (await FindByNamesAsync(names, cancellationToken)).CastArray<object>();
IAsyncEnumerable<object> IOpenIddictScopeManager.FindByNamesAsync(ImmutableArray<string> names, CancellationToken cancellationToken)
=> FindByNamesAsync(names, cancellationToken).OfType<object>();
async Task<ImmutableArray<object>> IOpenIddictScopeManager.FindByResourceAsync(string resource, CancellationToken cancellationToken)
=> (await FindByResourceAsync(resource, cancellationToken)).CastArray<object>();
IAsyncEnumerable<object> IOpenIddictScopeManager.FindByResourceAsync(string resource, CancellationToken cancellationToken)
=> FindByResourceAsync(resource, cancellationToken).OfType<object>();
Task<TResult> IOpenIddictScopeManager.GetAsync<TResult>(Func<IQueryable<object>, IQueryable<TResult>> query, CancellationToken cancellationToken)
ValueTask<TResult> IOpenIddictScopeManager.GetAsync<TResult>(Func<IQueryable<object>, IQueryable<TResult>> query, CancellationToken cancellationToken)
=> GetAsync(query, cancellationToken);
Task<TResult> IOpenIddictScopeManager.GetAsync<TState, TResult>(Func<IQueryable<object>, TState, IQueryable<TResult>> query, TState state, CancellationToken cancellationToken)
ValueTask<TResult> IOpenIddictScopeManager.GetAsync<TState, TResult>(Func<IQueryable<object>, TState, IQueryable<TResult>> query, TState state, CancellationToken cancellationToken)
=> GetAsync(query, state, cancellationToken);
ValueTask<string> IOpenIddictScopeManager.GetDescriptionAsync(object scope, CancellationToken cancellationToken)
@ -819,31 +757,31 @@ namespace OpenIddict.Core
ValueTask<ImmutableArray<string>> IOpenIddictScopeManager.GetResourcesAsync(object scope, CancellationToken cancellationToken)
=> GetResourcesAsync((TScope) scope, cancellationToken);
async Task<ImmutableArray<object>> IOpenIddictScopeManager.ListAsync(int? count, int? offset, CancellationToken cancellationToken)
=> (await ListAsync(count, offset, cancellationToken)).CastArray<object>();
IAsyncEnumerable<object> IOpenIddictScopeManager.ListAsync(int? count, int? offset, CancellationToken cancellationToken)
=> ListAsync(count, offset, cancellationToken).OfType<object>();
Task<ImmutableArray<TResult>> IOpenIddictScopeManager.ListAsync<TResult>(Func<IQueryable<object>, IQueryable<TResult>> query, CancellationToken cancellationToken)
IAsyncEnumerable<TResult> IOpenIddictScopeManager.ListAsync<TResult>(Func<IQueryable<object>, IQueryable<TResult>> query, CancellationToken cancellationToken)
=> ListAsync(query, cancellationToken);
Task<ImmutableArray<TResult>> IOpenIddictScopeManager.ListAsync<TState, TResult>(Func<IQueryable<object>, TState, IQueryable<TResult>> query, TState state, CancellationToken cancellationToken)
IAsyncEnumerable<TResult> IOpenIddictScopeManager.ListAsync<TState, TResult>(Func<IQueryable<object>, TState, IQueryable<TResult>> query, TState state, CancellationToken cancellationToken)
=> ListAsync(query, state, cancellationToken);
Task<ImmutableArray<string>> IOpenIddictScopeManager.ListResourcesAsync(ImmutableArray<string> scopes, CancellationToken cancellationToken)
IAsyncEnumerable<string> IOpenIddictScopeManager.ListResourcesAsync(ImmutableArray<string> scopes, CancellationToken cancellationToken)
=> ListResourcesAsync(scopes, cancellationToken);
Task IOpenIddictScopeManager.PopulateAsync(OpenIddictScopeDescriptor descriptor, object scope, CancellationToken cancellationToken)
ValueTask IOpenIddictScopeManager.PopulateAsync(OpenIddictScopeDescriptor descriptor, object scope, CancellationToken cancellationToken)
=> PopulateAsync(descriptor, (TScope) scope, cancellationToken);
Task IOpenIddictScopeManager.PopulateAsync(object scope, OpenIddictScopeDescriptor descriptor, CancellationToken cancellationToken)
ValueTask IOpenIddictScopeManager.PopulateAsync(object scope, OpenIddictScopeDescriptor descriptor, CancellationToken cancellationToken)
=> PopulateAsync((TScope) scope, descriptor, cancellationToken);
Task IOpenIddictScopeManager.UpdateAsync(object scope, CancellationToken cancellationToken)
ValueTask IOpenIddictScopeManager.UpdateAsync(object scope, CancellationToken cancellationToken)
=> UpdateAsync((TScope) scope, cancellationToken);
Task IOpenIddictScopeManager.UpdateAsync(object scope, OpenIddictScopeDescriptor descriptor, CancellationToken cancellationToken)
ValueTask IOpenIddictScopeManager.UpdateAsync(object scope, OpenIddictScopeDescriptor descriptor, CancellationToken cancellationToken)
=> UpdateAsync((TScope) scope, descriptor, cancellationToken);
Task<ImmutableArray<ValidationResult>> IOpenIddictScopeManager.ValidateAsync(object scope, CancellationToken cancellationToken)
IAsyncEnumerable<ValidationResult> IOpenIddictScopeManager.ValidateAsync(object scope, CancellationToken cancellationToken)
=> ValidateAsync((TScope) scope, cancellationToken);
}
}

420
src/OpenIddict.Core/Managers/OpenIddictTokenManager.cs

@ -5,9 +5,11 @@
*/
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Security.Cryptography;
using System.Text;
using System.Threading;
@ -62,10 +64,10 @@ namespace OpenIddict.Core
/// </summary>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the number of tokens in the database.
/// </returns>
public virtual Task<long> CountAsync(CancellationToken cancellationToken = default)
public virtual ValueTask<long> CountAsync(CancellationToken cancellationToken = default)
=> Store.CountAsync(cancellationToken);
/// <summary>
@ -75,10 +77,10 @@ namespace OpenIddict.Core
/// <param name="query">The query to execute.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the number of tokens that match the specified query.
/// </returns>
public virtual Task<long> CountAsync<TResult>(
public virtual ValueTask<long> CountAsync<TResult>(
[NotNull] Func<IQueryable<TToken>, IQueryable<TResult>> query, CancellationToken cancellationToken = default)
{
if (query == null)
@ -95,9 +97,9 @@ namespace OpenIddict.Core
/// <param name="token">The token.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual async Task CreateAsync([NotNull] TToken token, CancellationToken cancellationToken = default)
public virtual async ValueTask CreateAsync([NotNull] TToken token, CancellationToken cancellationToken = default)
{
if (token == null)
{
@ -118,7 +120,7 @@ namespace OpenIddict.Core
await Store.SetReferenceIdAsync(token, identifier, cancellationToken);
}
var results = await ValidateAsync(token, cancellationToken);
var results = await ValidateAsync(token, cancellationToken).ToListAsync(cancellationToken);
if (results.Any(result => result != ValidationResult.Success))
{
var builder = new StringBuilder();
@ -130,7 +132,7 @@ namespace OpenIddict.Core
builder.AppendLine(result.ErrorMessage);
}
throw new OpenIddictExceptions.ValidationException(builder.ToString(), results);
throw new OpenIddictExceptions.ValidationException(builder.ToString(), results.ToImmutableArray());
}
await Store.CreateAsync(token, cancellationToken);
@ -147,9 +149,9 @@ namespace OpenIddict.Core
/// <param name="descriptor">The token descriptor.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation, whose result returns the token.
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation, whose result returns the token.
/// </returns>
public virtual async Task<TToken> CreateAsync(
public virtual async ValueTask<TToken> CreateAsync(
[NotNull] OpenIddictTokenDescriptor descriptor, CancellationToken cancellationToken = default)
{
if (descriptor == null)
@ -175,9 +177,9 @@ namespace OpenIddict.Core
/// <param name="token">The token to delete.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual async Task DeleteAsync([NotNull] TToken token, CancellationToken cancellationToken = default)
public virtual async ValueTask DeleteAsync([NotNull] TToken token, CancellationToken cancellationToken = default)
{
if (token == null)
{
@ -199,9 +201,9 @@ namespace OpenIddict.Core
/// <param name="date">The date on which the token will no longer be considered valid.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual async Task ExtendAsync([NotNull] TToken token,
public virtual async ValueTask ExtendAsync([NotNull] TToken token,
[CanBeNull] DateTimeOffset? date, CancellationToken cancellationToken = default)
{
if (token == null)
@ -220,11 +222,8 @@ namespace OpenIddict.Core
/// <param name="subject">The subject associated with the token.</param>
/// <param name="client">The client associated with the token.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the tokens corresponding to the subject/client.
/// </returns>
public virtual async Task<ImmutableArray<TToken>> FindAsync([NotNull] string subject,
/// <returns>The tokens corresponding to the subject/client.</returns>
public virtual IAsyncEnumerable<TToken> FindAsync([NotNull] string subject,
[NotNull] string client, CancellationToken cancellationToken = default)
{
if (string.IsNullOrEmpty(subject))
@ -238,13 +237,8 @@ namespace OpenIddict.Core
}
var tokens = Options.CurrentValue.DisableEntityCaching ?
await Store.FindAsync(subject, client, cancellationToken) :
await Cache.FindAsync(subject, client, cancellationToken);
if (tokens.IsEmpty)
{
return ImmutableArray.Create<TToken>();
}
Store.FindAsync(subject, client, cancellationToken) :
Cache.FindAsync(subject, client, cancellationToken);
if (Options.CurrentValue.DisableAdditionalFiltering)
{
@ -255,19 +249,8 @@ namespace OpenIddict.Core
// To ensure a case-sensitive comparison is enforced independently of the database/table/query collation
// used by the store, a second pass using string.Equals(StringComparison.Ordinal) is manually made here.
var builder = ImmutableArray.CreateBuilder<TToken>(tokens.Length);
foreach (var token in tokens)
{
if (string.Equals(await Store.GetSubjectAsync(token, cancellationToken), subject, StringComparison.Ordinal))
{
builder.Add(token);
}
}
return builder.Count == builder.Capacity ?
builder.MoveToImmutable() :
builder.ToImmutable();
return tokens.WhereAwait(async token => string.Equals(await Store.GetSubjectAsync(
token, cancellationToken), subject, StringComparison.Ordinal));
}
/// <summary>
@ -277,11 +260,8 @@ namespace OpenIddict.Core
/// <param name="client">The client associated with the token.</param>
/// <param name="status">The token status.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the tokens corresponding to the criteria.
/// </returns>
public virtual async Task<ImmutableArray<TToken>> FindAsync(
/// <returns>The tokens corresponding to the criteria.</returns>
public virtual IAsyncEnumerable<TToken> FindAsync(
[NotNull] string subject, [NotNull] string client,
[NotNull] string status, CancellationToken cancellationToken = default)
{
@ -301,13 +281,8 @@ namespace OpenIddict.Core
}
var tokens = Options.CurrentValue.DisableEntityCaching ?
await Store.FindAsync(subject, client, status, cancellationToken) :
await Cache.FindAsync(subject, client, status, cancellationToken);
if (tokens.IsEmpty)
{
return ImmutableArray.Create<TToken>();
}
Store.FindAsync(subject, client, status, cancellationToken) :
Cache.FindAsync(subject, client, status, cancellationToken);
if (Options.CurrentValue.DisableAdditionalFiltering)
{
@ -318,19 +293,8 @@ namespace OpenIddict.Core
// To ensure a case-sensitive comparison is enforced independently of the database/table/query collation
// used by the store, a second pass using string.Equals(StringComparison.Ordinal) is manually made here.
var builder = ImmutableArray.CreateBuilder<TToken>(tokens.Length);
foreach (var token in tokens)
{
if (string.Equals(await Store.GetSubjectAsync(token, cancellationToken), subject, StringComparison.Ordinal))
{
builder.Add(token);
}
}
return builder.Count == builder.Capacity ?
builder.MoveToImmutable() :
builder.ToImmutable();
return tokens.WhereAwait(async token => string.Equals(await Store.GetSubjectAsync(
token, cancellationToken), subject, StringComparison.Ordinal));
}
/// <summary>
@ -341,11 +305,8 @@ namespace OpenIddict.Core
/// <param name="status">The token status.</param>
/// <param name="type">The token type.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the tokens corresponding to the criteria.
/// </returns>
public virtual async Task<ImmutableArray<TToken>> FindAsync(
/// <returns>Tokens corresponding to the criteria.</returns>
public virtual IAsyncEnumerable<TToken> FindAsync(
[NotNull] string subject, [NotNull] string client,
[NotNull] string status, [NotNull] string type, CancellationToken cancellationToken = default)
{
@ -370,13 +331,8 @@ namespace OpenIddict.Core
}
var tokens = Options.CurrentValue.DisableEntityCaching ?
await Store.FindAsync(subject, client, status, type, cancellationToken) :
await Cache.FindAsync(subject, client, status, type, cancellationToken);
if (tokens.IsEmpty)
{
return ImmutableArray.Create<TToken>();
}
Store.FindAsync(subject, client, status, type, cancellationToken) :
Cache.FindAsync(subject, client, status, type, cancellationToken);
if (Options.CurrentValue.DisableAdditionalFiltering)
{
@ -387,19 +343,8 @@ namespace OpenIddict.Core
// To ensure a case-sensitive comparison is enforced independently of the database/table/query collation
// used by the store, a second pass using string.Equals(StringComparison.Ordinal) is manually made here.
var builder = ImmutableArray.CreateBuilder<TToken>(tokens.Length);
foreach (var token in tokens)
{
if (string.Equals(await Store.GetSubjectAsync(token, cancellationToken), subject, StringComparison.Ordinal))
{
builder.Add(token);
}
}
return builder.Count == builder.Capacity ?
builder.MoveToImmutable() :
builder.ToImmutable();
return tokens.WhereAwait(async token => string.Equals(await Store.GetSubjectAsync(
token, cancellationToken), subject, StringComparison.Ordinal));
}
/// <summary>
@ -407,11 +352,8 @@ namespace OpenIddict.Core
/// </summary>
/// <param name="identifier">The application identifier associated with the tokens.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the tokens corresponding to the specified application.
/// </returns>
public virtual async Task<ImmutableArray<TToken>> FindByApplicationIdAsync(
/// <returns>The tokens corresponding to the specified application.</returns>
public virtual IAsyncEnumerable<TToken> FindByApplicationIdAsync(
[NotNull] string identifier, CancellationToken cancellationToken = default)
{
if (string.IsNullOrEmpty(identifier))
@ -420,13 +362,8 @@ namespace OpenIddict.Core
}
var tokens = Options.CurrentValue.DisableEntityCaching ?
await Store.FindByApplicationIdAsync(identifier, cancellationToken) :
await Cache.FindByApplicationIdAsync(identifier, cancellationToken);
if (tokens.IsEmpty)
{
return ImmutableArray.Create<TToken>();
}
Store.FindByApplicationIdAsync(identifier, cancellationToken) :
Cache.FindByApplicationIdAsync(identifier, cancellationToken);
if (Options.CurrentValue.DisableAdditionalFiltering)
{
@ -437,19 +374,8 @@ namespace OpenIddict.Core
// To ensure a case-sensitive comparison is enforced independently of the database/table/query collation
// used by the store, a second pass using string.Equals(StringComparison.Ordinal) is manually made here.
var builder = ImmutableArray.CreateBuilder<TToken>(tokens.Length);
foreach (var token in tokens)
{
if (string.Equals(await Store.GetApplicationIdAsync(token, cancellationToken), identifier, StringComparison.Ordinal))
{
builder.Add(token);
}
}
return builder.Count == builder.Capacity ?
builder.MoveToImmutable() :
builder.ToImmutable();
return tokens.WhereAwait(async token => string.Equals(await Store.GetApplicationIdAsync(
token, cancellationToken), identifier, StringComparison.Ordinal));
}
/// <summary>
@ -457,11 +383,8 @@ namespace OpenIddict.Core
/// </summary>
/// <param name="identifier">The authorization identifier associated with the tokens.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the tokens corresponding to the specified authorization.
/// </returns>
public virtual async Task<ImmutableArray<TToken>> FindByAuthorizationIdAsync(
/// <returns>The tokens corresponding to the specified authorization.</returns>
public virtual IAsyncEnumerable<TToken> FindByAuthorizationIdAsync(
[NotNull] string identifier, CancellationToken cancellationToken = default)
{
if (string.IsNullOrEmpty(identifier))
@ -470,13 +393,8 @@ namespace OpenIddict.Core
}
var tokens = Options.CurrentValue.DisableEntityCaching ?
await Store.FindByAuthorizationIdAsync(identifier, cancellationToken) :
await Cache.FindByAuthorizationIdAsync(identifier, cancellationToken);
if (tokens.IsEmpty)
{
return ImmutableArray.Create<TToken>();
}
Store.FindByAuthorizationIdAsync(identifier, cancellationToken) :
Cache.FindByAuthorizationIdAsync(identifier, cancellationToken);
if (Options.CurrentValue.DisableAdditionalFiltering)
{
@ -487,19 +405,8 @@ namespace OpenIddict.Core
// To ensure a case-sensitive comparison is enforced independently of the database/table/query collation
// used by the store, a second pass using string.Equals(StringComparison.Ordinal) is manually made here.
var builder = ImmutableArray.CreateBuilder<TToken>(tokens.Length);
foreach (var token in tokens)
{
if (string.Equals(await Store.GetAuthorizationIdAsync(token, cancellationToken), identifier, StringComparison.Ordinal))
{
builder.Add(token);
}
}
return builder.Count == builder.Capacity ?
builder.MoveToImmutable() :
builder.ToImmutable();
return tokens.WhereAwait(async token => string.Equals(await Store.GetAuthorizationIdAsync(
token, cancellationToken), identifier, StringComparison.Ordinal));
}
/// <summary>
@ -508,10 +415,10 @@ namespace OpenIddict.Core
/// <param name="identifier">The unique identifier associated with the token.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the token corresponding to the unique identifier.
/// </returns>
public virtual async Task<TToken> FindByIdAsync([NotNull] string identifier, CancellationToken cancellationToken = default)
public virtual async ValueTask<TToken> FindByIdAsync([NotNull] string identifier, CancellationToken cancellationToken = default)
{
if (string.IsNullOrEmpty(identifier))
{
@ -546,10 +453,10 @@ namespace OpenIddict.Core
/// <param name="identifier">The reference identifier associated with the tokens.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the tokens corresponding to the specified reference identifier.
/// </returns>
public virtual async Task<TToken> FindByReferenceIdAsync([NotNull] string identifier, CancellationToken cancellationToken = default)
public virtual async ValueTask<TToken> FindByReferenceIdAsync([NotNull] string identifier, CancellationToken cancellationToken = default)
{
if (string.IsNullOrEmpty(identifier))
{
@ -585,11 +492,8 @@ namespace OpenIddict.Core
/// </summary>
/// <param name="subject">The subject associated with the tokens.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the tokens corresponding to the specified subject.
/// </returns>
public virtual async Task<ImmutableArray<TToken>> FindBySubjectAsync(
/// <returns>The tokens corresponding to the specified subject.</returns>
public virtual IAsyncEnumerable<TToken> FindBySubjectAsync(
[NotNull] string subject, CancellationToken cancellationToken = default)
{
if (string.IsNullOrEmpty(subject))
@ -598,13 +502,8 @@ namespace OpenIddict.Core
}
var tokens = Options.CurrentValue.DisableEntityCaching ?
await Store.FindBySubjectAsync(subject, cancellationToken) :
await Cache.FindBySubjectAsync(subject, cancellationToken);
if (tokens.IsEmpty)
{
return ImmutableArray.Create<TToken>();
}
Store.FindBySubjectAsync(subject, cancellationToken) :
Cache.FindBySubjectAsync(subject, cancellationToken);
if (Options.CurrentValue.DisableAdditionalFiltering)
{
@ -615,19 +514,8 @@ namespace OpenIddict.Core
// To ensure a case-sensitive comparison is enforced independently of the database/table/query collation
// used by the store, a second pass using string.Equals(StringComparison.Ordinal) is manually made here.
var builder = ImmutableArray.CreateBuilder<TToken>(tokens.Length);
foreach (var token in tokens)
{
if (string.Equals(await Store.GetSubjectAsync(token, cancellationToken), subject, StringComparison.Ordinal))
{
builder.Add(token);
}
}
return builder.Count == builder.Capacity ?
builder.MoveToImmutable() :
builder.ToImmutable();
return tokens.WhereAwait(async token => string.Equals(await Store.GetSubjectAsync(
token, cancellationToken), subject, StringComparison.Ordinal));
}
/// <summary>
@ -656,10 +544,10 @@ namespace OpenIddict.Core
/// <param name="query">The query to execute.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the first element returned when executing the query.
/// </returns>
public virtual Task<TResult> GetAsync<TResult>(
public virtual ValueTask<TResult> GetAsync<TResult>(
[NotNull] Func<IQueryable<TToken>, IQueryable<TResult>> query, CancellationToken cancellationToken = default)
{
if (query == null)
@ -679,10 +567,10 @@ namespace OpenIddict.Core
/// <param name="state">The optional state.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the first element returned when executing the query.
/// </returns>
public virtual Task<TResult> GetAsync<TState, TResult>(
public virtual ValueTask<TResult> GetAsync<TState, TResult>(
[NotNull] Func<IQueryable<TToken>, TState, IQueryable<TResult>> query,
[CanBeNull] TState state, CancellationToken cancellationToken = default)
{
@ -873,7 +761,7 @@ namespace OpenIddict.Core
/// <param name="token">The token.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns><c>true</c> if the token has already been redemeed, <c>false</c> otherwise.</returns>
public virtual async Task<bool> IsRedeemedAsync([NotNull] TToken token, CancellationToken cancellationToken = default)
public virtual async ValueTask<bool> IsRedeemedAsync([NotNull] TToken token, CancellationToken cancellationToken = default)
{
if (token == null)
{
@ -895,7 +783,7 @@ namespace OpenIddict.Core
/// <param name="token">The token.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns><c>true</c> if the token has been revoked, <c>false</c> otherwise.</returns>
public virtual async Task<bool> IsRevokedAsync([NotNull] TToken token, CancellationToken cancellationToken = default)
public virtual async ValueTask<bool> IsRevokedAsync([NotNull] TToken token, CancellationToken cancellationToken = default)
{
if (token == null)
{
@ -917,7 +805,7 @@ namespace OpenIddict.Core
/// <param name="token">The token.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns><c>true</c> if the token is valid, <c>false</c> otherwise.</returns>
public virtual async Task<bool> IsValidAsync([NotNull] TToken token, CancellationToken cancellationToken = default)
public virtual async ValueTask<bool> IsValidAsync([NotNull] TToken token, CancellationToken cancellationToken = default)
{
if (token == null)
{
@ -939,15 +827,10 @@ namespace OpenIddict.Core
/// <param name="count">The number of results to return.</param>
/// <param name="offset">The number of results to skip.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the elements returned when executing the specified query.
/// </returns>
public virtual Task<ImmutableArray<TToken>> ListAsync(
/// <returns>All the elements returned when executing the specified query.</returns>
public virtual IAsyncEnumerable<TToken> ListAsync(
[CanBeNull] int? count = null, [CanBeNull] int? offset = null, CancellationToken cancellationToken = default)
{
return Store.ListAsync(count, offset, cancellationToken);
}
=> Store.ListAsync(count, offset, cancellationToken);
/// <summary>
/// Executes the specified query and returns all the corresponding elements.
@ -955,11 +838,8 @@ namespace OpenIddict.Core
/// <typeparam name="TResult">The result type.</typeparam>
/// <param name="query">The query to execute.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the elements returned when executing the specified query.
/// </returns>
public virtual Task<ImmutableArray<TResult>> ListAsync<TResult>(
/// <returns>All the elements returned when executing the specified query.</returns>
public virtual IAsyncEnumerable<TResult> ListAsync<TResult>(
[NotNull] Func<IQueryable<TToken>, IQueryable<TResult>> query, CancellationToken cancellationToken = default)
{
if (query == null)
@ -978,11 +858,8 @@ namespace OpenIddict.Core
/// <param name="query">The query to execute.</param>
/// <param name="state">The optional state.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the elements returned when executing the specified query.
/// </returns>
public virtual Task<ImmutableArray<TResult>> ListAsync<TState, TResult>(
/// <returns>All the elements returned when executing the specified query.</returns>
public virtual IAsyncEnumerable<TResult> ListAsync<TState, TResult>(
[NotNull] Func<IQueryable<TToken>, TState, IQueryable<TResult>> query,
[CanBeNull] TState state, CancellationToken cancellationToken = default)
{
@ -1001,9 +878,9 @@ namespace OpenIddict.Core
/// <param name="descriptor">The descriptor.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual async Task PopulateAsync([NotNull] TToken token,
public virtual async ValueTask PopulateAsync([NotNull] TToken token,
[NotNull] OpenIddictTokenDescriptor descriptor, CancellationToken cancellationToken = default)
{
if (token == null)
@ -1034,9 +911,9 @@ namespace OpenIddict.Core
/// <param name="token">The token.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual async Task PopulateAsync(
public virtual async ValueTask PopulateAsync(
[NotNull] OpenIddictTokenDescriptor descriptor,
[NotNull] TToken token, CancellationToken cancellationToken = default)
{
@ -1066,9 +943,9 @@ namespace OpenIddict.Core
/// </summary>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task PruneAsync(CancellationToken cancellationToken = default)
public virtual ValueTask PruneAsync(CancellationToken cancellationToken = default)
=> Store.PruneAsync(cancellationToken);
/// <summary>
@ -1076,8 +953,8 @@ namespace OpenIddict.Core
/// </summary>
/// <param name="token">The token to redeem.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>A <see cref="Task"/> that can be used to monitor the asynchronous operation.</returns>
public virtual async Task RedeemAsync([NotNull] TToken token, CancellationToken cancellationToken = default)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual async ValueTask RedeemAsync([NotNull] TToken token, CancellationToken cancellationToken = default)
{
if (token == null)
{
@ -1097,8 +974,8 @@ namespace OpenIddict.Core
/// </summary>
/// <param name="token">The token to revoke.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>A <see cref="Task"/> that can be used to monitor the asynchronous operation.</returns>
public virtual async Task RevokeAsync([NotNull] TToken token, CancellationToken cancellationToken = default)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual async ValueTask RevokeAsync([NotNull] TToken token, CancellationToken cancellationToken = default)
{
if (token == null)
{
@ -1120,9 +997,9 @@ namespace OpenIddict.Core
/// <param name="identifier">The unique identifier associated with the client application.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual async Task SetApplicationIdAsync([NotNull] TToken token,
public virtual async ValueTask SetApplicationIdAsync([NotNull] TToken token,
[CanBeNull] string identifier, CancellationToken cancellationToken = default)
{
if (token == null)
@ -1141,9 +1018,9 @@ namespace OpenIddict.Core
/// <param name="identifier">The unique identifier associated with the authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual async Task SetAuthorizationIdAsync([NotNull] TToken token,
public virtual async ValueTask SetAuthorizationIdAsync([NotNull] TToken token,
[CanBeNull] string identifier, CancellationToken cancellationToken = default)
{
if (token == null)
@ -1161,16 +1038,16 @@ namespace OpenIddict.Core
/// <param name="token">The token to update.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual async Task UpdateAsync([NotNull] TToken token, CancellationToken cancellationToken = default)
public virtual async ValueTask UpdateAsync([NotNull] TToken token, CancellationToken cancellationToken = default)
{
if (token == null)
{
throw new ArgumentNullException(nameof(token));
}
var results = await ValidateAsync(token, cancellationToken);
var results = await ValidateAsync(token, cancellationToken).ToListAsync(cancellationToken);
if (results.Any(result => result != ValidationResult.Success))
{
var builder = new StringBuilder();
@ -1182,7 +1059,7 @@ namespace OpenIddict.Core
builder.AppendLine(result.ErrorMessage);
}
throw new OpenIddictExceptions.ValidationException(builder.ToString(), results);
throw new OpenIddictExceptions.ValidationException(builder.ToString(), results.ToImmutableArray());
}
await Store.UpdateAsync(token, cancellationToken);
@ -1201,9 +1078,9 @@ namespace OpenIddict.Core
/// <param name="descriptor">The descriptor used to update the token.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual async Task UpdateAsync([NotNull] TToken token,
public virtual async ValueTask UpdateAsync([NotNull] TToken token,
[NotNull] OpenIddictTokenDescriptor descriptor, CancellationToken cancellationToken = default)
{
if (token == null)
@ -1236,20 +1113,15 @@ namespace OpenIddict.Core
/// </summary>
/// <param name="token">The token.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the validation error encountered when validating the token.
/// </returns>
public virtual async Task<ImmutableArray<ValidationResult>> ValidateAsync(
[NotNull] TToken token, CancellationToken cancellationToken = default)
/// <returns>The validation error encountered when validating the token.</returns>
public virtual async IAsyncEnumerable<ValidationResult> ValidateAsync(
[NotNull] TToken token, [EnumeratorCancellation] CancellationToken cancellationToken = default)
{
if (token == null)
{
throw new ArgumentNullException(nameof(token));
}
var builder = ImmutableArray.CreateBuilder<ValidationResult>();
// If a reference identifier was associated with the token,
// ensure it's not already used for a different token.
var identifier = await Store.GetReferenceIdAsync(token, cancellationToken);
@ -1264,36 +1136,32 @@ namespace OpenIddict.Core
await Store.GetIdAsync(other, cancellationToken),
await Store.GetIdAsync(token, cancellationToken), StringComparison.Ordinal))
{
builder.Add(new ValidationResult("A token with the same reference identifier already exists."));
yield return new ValidationResult("A token with the same reference identifier already exists.");
}
}
var type = await Store.GetTypeAsync(token, cancellationToken);
if (string.IsNullOrEmpty(type))
{
builder.Add(new ValidationResult("The token type cannot be null or empty."));
yield return new ValidationResult("The token type cannot be null or empty.");
}
else if (!string.Equals(type, OpenIddictConstants.TokenUsages.AccessToken, StringComparison.OrdinalIgnoreCase) &&
!string.Equals(type, OpenIddictConstants.TokenUsages.AuthorizationCode, StringComparison.OrdinalIgnoreCase) &&
!string.Equals(type, OpenIddictConstants.TokenUsages.RefreshToken, StringComparison.OrdinalIgnoreCase))
{
builder.Add(new ValidationResult("The specified token type is not supported by the default token manager."));
yield return new ValidationResult("The specified token type is not supported by the default token manager.");
}
if (string.IsNullOrEmpty(await Store.GetStatusAsync(token, cancellationToken)))
{
builder.Add(new ValidationResult("The status cannot be null or empty."));
yield return new ValidationResult("The status cannot be null or empty.");
}
if (string.IsNullOrEmpty(await Store.GetSubjectAsync(token, cancellationToken)))
{
builder.Add(new ValidationResult("The subject cannot be null or empty."));
yield return new ValidationResult("The subject cannot be null or empty.");
}
return builder.Count == builder.Capacity ?
builder.MoveToImmutable() :
builder.ToImmutable();
}
/// <summary>
@ -1303,72 +1171,70 @@ namespace OpenIddict.Core
/// <param name="identifier">The client identifier.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.
/// </returns>
protected virtual Task<string> ObfuscateReferenceIdAsync([NotNull] string identifier, CancellationToken cancellationToken = default)
protected virtual ValueTask<string> ObfuscateReferenceIdAsync([NotNull] string identifier, CancellationToken cancellationToken = default)
{
if (string.IsNullOrEmpty(identifier))
{
throw new ArgumentException("The identifier cannot be null or empty.", nameof(identifier));
}
using (var algorithm = SHA256.Create())
{
// Compute the digest of the generated identifier and use it as the hashed identifier of the reference token.
// Doing that prevents token identifiers stolen from the database from being used as valid reference tokens.
return Task.FromResult(Convert.ToBase64String(algorithm.ComputeHash(Encoding.UTF8.GetBytes(identifier))));
}
// Compute the digest of the generated identifier and use it as the hashed identifier of the reference token.
// Doing that prevents token identifiers stolen from the database from being used as valid reference tokens.
using var algorithm = SHA256.Create();
return new ValueTask<string>(Convert.ToBase64String(algorithm.ComputeHash(Encoding.UTF8.GetBytes(identifier))));
}
Task<long> IOpenIddictTokenManager.CountAsync(CancellationToken cancellationToken)
ValueTask<long> IOpenIddictTokenManager.CountAsync(CancellationToken cancellationToken)
=> CountAsync(cancellationToken);
Task<long> IOpenIddictTokenManager.CountAsync<TResult>(Func<IQueryable<object>, IQueryable<TResult>> query, CancellationToken cancellationToken)
ValueTask<long> IOpenIddictTokenManager.CountAsync<TResult>(Func<IQueryable<object>, IQueryable<TResult>> query, CancellationToken cancellationToken)
=> CountAsync(query, cancellationToken);
async Task<object> IOpenIddictTokenManager.CreateAsync(OpenIddictTokenDescriptor descriptor, CancellationToken cancellationToken)
async ValueTask<object> IOpenIddictTokenManager.CreateAsync(OpenIddictTokenDescriptor descriptor, CancellationToken cancellationToken)
=> await CreateAsync(descriptor, cancellationToken);
Task IOpenIddictTokenManager.CreateAsync(object token, CancellationToken cancellationToken)
ValueTask IOpenIddictTokenManager.CreateAsync(object token, CancellationToken cancellationToken)
=> CreateAsync((TToken) token, cancellationToken);
Task IOpenIddictTokenManager.DeleteAsync(object token, CancellationToken cancellationToken)
ValueTask IOpenIddictTokenManager.DeleteAsync(object token, CancellationToken cancellationToken)
=> DeleteAsync((TToken) token, cancellationToken);
Task IOpenIddictTokenManager.ExtendAsync(object token, DateTimeOffset? date, CancellationToken cancellationToken)
ValueTask IOpenIddictTokenManager.ExtendAsync(object token, DateTimeOffset? date, CancellationToken cancellationToken)
=> ExtendAsync((TToken) token, date, cancellationToken);
async Task<ImmutableArray<object>> IOpenIddictTokenManager.FindAsync(string subject, string client, CancellationToken cancellationToken)
=> (await FindAsync(subject, client, cancellationToken)).CastArray<object>();
IAsyncEnumerable<object> IOpenIddictTokenManager.FindAsync(string subject, string client, CancellationToken cancellationToken)
=> FindAsync(subject, client, cancellationToken).OfType<object>();
async Task<ImmutableArray<object>> IOpenIddictTokenManager.FindAsync(string subject, string client, string status, CancellationToken cancellationToken)
=> (await FindAsync(subject, client, status, cancellationToken)).CastArray<object>();
IAsyncEnumerable<object> IOpenIddictTokenManager.FindAsync(string subject, string client, string status, CancellationToken cancellationToken)
=> FindAsync(subject, client, status, cancellationToken).OfType<object>();
async Task<ImmutableArray<object>> IOpenIddictTokenManager.FindAsync(string subject, string client, string status, string type, CancellationToken cancellationToken)
=> (await FindAsync(subject, client, status, type, cancellationToken)).CastArray<object>();
IAsyncEnumerable<object> IOpenIddictTokenManager.FindAsync(string subject, string client, string status, string type, CancellationToken cancellationToken)
=> FindAsync(subject, client, status, type, cancellationToken).OfType<object>();
async Task<ImmutableArray<object>> IOpenIddictTokenManager.FindByApplicationIdAsync(string identifier, CancellationToken cancellationToken)
=> (await FindByApplicationIdAsync(identifier, cancellationToken)).CastArray<object>();
IAsyncEnumerable<object> IOpenIddictTokenManager.FindByApplicationIdAsync(string identifier, CancellationToken cancellationToken)
=> FindByApplicationIdAsync(identifier, cancellationToken).OfType<object>();
async Task<ImmutableArray<object>> IOpenIddictTokenManager.FindByAuthorizationIdAsync(string identifier, CancellationToken cancellationToken)
=> (await FindByAuthorizationIdAsync(identifier, cancellationToken)).CastArray<object>();
IAsyncEnumerable<object> IOpenIddictTokenManager.FindByAuthorizationIdAsync(string identifier, CancellationToken cancellationToken)
=> FindByAuthorizationIdAsync(identifier, cancellationToken).OfType<object>();
async Task<object> IOpenIddictTokenManager.FindByIdAsync(string identifier, CancellationToken cancellationToken)
async ValueTask<object> IOpenIddictTokenManager.FindByIdAsync(string identifier, CancellationToken cancellationToken)
=> await FindByIdAsync(identifier, cancellationToken);
async Task<object> IOpenIddictTokenManager.FindByReferenceIdAsync(string identifier, CancellationToken cancellationToken)
async ValueTask<object> IOpenIddictTokenManager.FindByReferenceIdAsync(string identifier, CancellationToken cancellationToken)
=> await FindByReferenceIdAsync(identifier, cancellationToken);
async Task<ImmutableArray<object>> IOpenIddictTokenManager.FindBySubjectAsync(string subject, CancellationToken cancellationToken)
=> (await FindBySubjectAsync(subject, cancellationToken)).CastArray<object>();
IAsyncEnumerable<object> IOpenIddictTokenManager.FindBySubjectAsync(string subject, CancellationToken cancellationToken)
=> FindBySubjectAsync(subject, cancellationToken).OfType<object>();
ValueTask<string> IOpenIddictTokenManager.GetApplicationIdAsync(object token, CancellationToken cancellationToken)
=> GetApplicationIdAsync((TToken) token, cancellationToken);
Task<TResult> IOpenIddictTokenManager.GetAsync<TResult>(Func<IQueryable<object>, IQueryable<TResult>> query, CancellationToken cancellationToken)
ValueTask<TResult> IOpenIddictTokenManager.GetAsync<TResult>(Func<IQueryable<object>, IQueryable<TResult>> query, CancellationToken cancellationToken)
=> GetAsync(query, cancellationToken);
Task<TResult> IOpenIddictTokenManager.GetAsync<TState, TResult>(Func<IQueryable<object>, TState, IQueryable<TResult>> query, TState state, CancellationToken cancellationToken)
ValueTask<TResult> IOpenIddictTokenManager.GetAsync<TState, TResult>(Func<IQueryable<object>, TState, IQueryable<TResult>> query, TState state, CancellationToken cancellationToken)
=> GetAsync(query, state, cancellationToken);
ValueTask<string> IOpenIddictTokenManager.GetAuthorizationIdAsync(object token, CancellationToken cancellationToken)
@ -1398,52 +1264,52 @@ namespace OpenIddict.Core
ValueTask<string> IOpenIddictTokenManager.GetTypeAsync(object token, CancellationToken cancellationToken)
=> GetTypeAsync((TToken) token, cancellationToken);
Task<bool> IOpenIddictTokenManager.IsRedeemedAsync(object token, CancellationToken cancellationToken)
ValueTask<bool> IOpenIddictTokenManager.IsRedeemedAsync(object token, CancellationToken cancellationToken)
=> IsRedeemedAsync((TToken) token, cancellationToken);
Task<bool> IOpenIddictTokenManager.IsRevokedAsync(object token, CancellationToken cancellationToken)
ValueTask<bool> IOpenIddictTokenManager.IsRevokedAsync(object token, CancellationToken cancellationToken)
=> IsRevokedAsync((TToken) token, cancellationToken);
Task<bool> IOpenIddictTokenManager.IsValidAsync(object token, CancellationToken cancellationToken)
ValueTask<bool> IOpenIddictTokenManager.IsValidAsync(object token, CancellationToken cancellationToken)
=> IsValidAsync((TToken) token, cancellationToken);
async Task<ImmutableArray<object>> IOpenIddictTokenManager.ListAsync(int? count, int? offset, CancellationToken cancellationToken)
=> (await ListAsync(count, offset, cancellationToken)).CastArray<object>();
IAsyncEnumerable<object> IOpenIddictTokenManager.ListAsync(int? count, int? offset, CancellationToken cancellationToken)
=> ListAsync(count, offset, cancellationToken).OfType<object>();
Task<ImmutableArray<TResult>> IOpenIddictTokenManager.ListAsync<TResult>(Func<IQueryable<object>, IQueryable<TResult>> query, CancellationToken cancellationToken)
IAsyncEnumerable<TResult> IOpenIddictTokenManager.ListAsync<TResult>(Func<IQueryable<object>, IQueryable<TResult>> query, CancellationToken cancellationToken)
=> ListAsync(query, cancellationToken);
Task<ImmutableArray<TResult>> IOpenIddictTokenManager.ListAsync<TState, TResult>(Func<IQueryable<object>, TState, IQueryable<TResult>> query, TState state, CancellationToken cancellationToken)
IAsyncEnumerable<TResult> IOpenIddictTokenManager.ListAsync<TState, TResult>(Func<IQueryable<object>, TState, IQueryable<TResult>> query, TState state, CancellationToken cancellationToken)
=> ListAsync(query, state, cancellationToken);
Task IOpenIddictTokenManager.PopulateAsync(OpenIddictTokenDescriptor descriptor, object token, CancellationToken cancellationToken)
ValueTask IOpenIddictTokenManager.PopulateAsync(OpenIddictTokenDescriptor descriptor, object token, CancellationToken cancellationToken)
=> PopulateAsync(descriptor, (TToken) token, cancellationToken);
Task IOpenIddictTokenManager.PopulateAsync(object token, OpenIddictTokenDescriptor descriptor, CancellationToken cancellationToken)
ValueTask IOpenIddictTokenManager.PopulateAsync(object token, OpenIddictTokenDescriptor descriptor, CancellationToken cancellationToken)
=> PopulateAsync((TToken) token, descriptor, cancellationToken);
Task IOpenIddictTokenManager.PruneAsync(CancellationToken cancellationToken)
ValueTask IOpenIddictTokenManager.PruneAsync(CancellationToken cancellationToken)
=> PruneAsync(cancellationToken);
Task IOpenIddictTokenManager.RedeemAsync(object token, CancellationToken cancellationToken)
ValueTask IOpenIddictTokenManager.RedeemAsync(object token, CancellationToken cancellationToken)
=> RedeemAsync((TToken) token, cancellationToken);
Task IOpenIddictTokenManager.RevokeAsync(object token, CancellationToken cancellationToken)
ValueTask IOpenIddictTokenManager.RevokeAsync(object token, CancellationToken cancellationToken)
=> RevokeAsync((TToken) token, cancellationToken);
Task IOpenIddictTokenManager.SetApplicationIdAsync(object token, string identifier, CancellationToken cancellationToken)
ValueTask IOpenIddictTokenManager.SetApplicationIdAsync(object token, string identifier, CancellationToken cancellationToken)
=> SetApplicationIdAsync((TToken) token, identifier, cancellationToken);
Task IOpenIddictTokenManager.SetAuthorizationIdAsync(object token, string identifier, CancellationToken cancellationToken)
ValueTask IOpenIddictTokenManager.SetAuthorizationIdAsync(object token, string identifier, CancellationToken cancellationToken)
=> SetAuthorizationIdAsync((TToken) token, identifier, cancellationToken);
Task IOpenIddictTokenManager.UpdateAsync(object token, CancellationToken cancellationToken)
ValueTask IOpenIddictTokenManager.UpdateAsync(object token, CancellationToken cancellationToken)
=> UpdateAsync((TToken) token, cancellationToken);
Task IOpenIddictTokenManager.UpdateAsync(object token, OpenIddictTokenDescriptor descriptor, CancellationToken cancellationToken)
ValueTask IOpenIddictTokenManager.UpdateAsync(object token, OpenIddictTokenDescriptor descriptor, CancellationToken cancellationToken)
=> UpdateAsync((TToken) token, descriptor, cancellationToken);
Task<ImmutableArray<ValidationResult>> IOpenIddictTokenManager.ValidateAsync(object token, CancellationToken cancellationToken)
IAsyncEnumerable<ValidationResult> IOpenIddictTokenManager.ValidateAsync(object token, CancellationToken cancellationToken)
=> ValidateAsync((TToken) token, cancellationToken);
}
}

1
src/OpenIddict.Core/OpenIddict.Core.csproj

@ -19,6 +19,7 @@
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="$(ExtensionsVersion)" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="$(ExtensionsVersion)" />
<PackageReference Include="Microsoft.Extensions.Options" Version="$(ExtensionsVersion)" />
<PackageReference Include="System.Linq.Async" Version="$(LinqAsyncVersion)" />
</ItemGroup>
<ItemGroup>

30
src/OpenIddict.EntityFramework/OpenIddictEntityFrameworkHelpers.cs

@ -4,6 +4,9 @@
* the license and the contributors participating to this project.
*/
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using JetBrains.Annotations;
using OpenIddict.EntityFramework;
using OpenIddict.EntityFramework.Models;
@ -11,7 +14,7 @@ using OpenIddict.EntityFramework.Models;
namespace System.Data.Entity
{
/// <summary>
/// Exposes extensions allowing to register the OpenIddict Entity Framework 6.x entity sets.
/// Exposes extensions simplifying the integration between OpenIddict and Entity Framework 6.x.
/// </summary>
public static class OpenIddictEntityFrameworkHelpers
{
@ -55,5 +58,30 @@ namespace System.Data.Entity
return builder;
}
/// <summary>
/// Executes the query and returns the results as a non-streamed async enumeration.
/// </summary>
/// <typeparam name="T">The type of the returned entities.</typeparam>
/// <param name="source">The query source.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>The non-streamed async enumeration containing the results.</returns>
internal static IAsyncEnumerable<T> AsAsyncEnumerable<T>([NotNull] this IQueryable<T> source, CancellationToken cancellationToken)
{
if (source == null)
{
throw new ArgumentNullException(nameof(source));
}
return ExecuteAsync(cancellationToken);
async IAsyncEnumerable<T> ExecuteAsync(CancellationToken cancellationToken)
{
foreach (var element in await source.ToListAsync(cancellationToken))
{
yield return element;
}
}
}
}
}

281
src/OpenIddict.EntityFramework/Stores/OpenIddictApplicationStore.cs

@ -103,11 +103,11 @@ namespace OpenIddict.EntityFramework
/// </summary>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the number of applications in the database.
/// </returns>
public virtual Task<long> CountAsync(CancellationToken cancellationToken)
=> Applications.LongCountAsync();
public virtual ValueTask<long> CountAsync(CancellationToken cancellationToken)
=> new ValueTask<long>(Applications.LongCountAsync());
/// <summary>
/// Determines the number of applications that match the specified query.
@ -116,17 +116,17 @@ namespace OpenIddict.EntityFramework
/// <param name="query">The query to execute.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the number of applications that match the specified query.
/// </returns>
public virtual Task<long> CountAsync<TResult>([NotNull] Func<IQueryable<TApplication>, IQueryable<TResult>> query, CancellationToken cancellationToken)
public virtual ValueTask<long> CountAsync<TResult>([NotNull] Func<IQueryable<TApplication>, IQueryable<TResult>> query, CancellationToken cancellationToken)
{
if (query == null)
{
throw new ArgumentNullException(nameof(query));
}
return query(Applications).LongCountAsync();
return new ValueTask<long>(query(Applications).LongCountAsync());
}
/// <summary>
@ -134,10 +134,8 @@ namespace OpenIddict.EntityFramework
/// </summary>
/// <param name="application">The application to create.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task CreateAsync([NotNull] TApplication application, CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask CreateAsync([NotNull] TApplication application, CancellationToken cancellationToken)
{
if (application == null)
{
@ -146,7 +144,7 @@ namespace OpenIddict.EntityFramework
Applications.Add(application);
return Context.SaveChangesAsync(cancellationToken);
return new ValueTask(Context.SaveChangesAsync(cancellationToken));
}
/// <summary>
@ -154,10 +152,8 @@ namespace OpenIddict.EntityFramework
/// </summary>
/// <param name="application">The application to delete.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual async Task DeleteAsync([NotNull] TApplication application, CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual async ValueTask DeleteAsync([NotNull] TApplication application, CancellationToken cancellationToken)
{
if (application == null)
{
@ -191,41 +187,40 @@ namespace OpenIddict.EntityFramework
// To prevent an SQL exception from being thrown if a new associated entity is
// created after the existing entries have been listed, the following logic is
// executed in a serializable transaction, that will lock the affected tables.
using (var transaction = CreateTransaction())
{
// Remove all the authorizations associated with the application and
// the tokens attached to these implicit or explicit authorizations.
foreach (var authorization in await ListAuthorizationsAsync())
{
foreach (var token in authorization.Tokens)
{
Tokens.Remove(token);
}
Authorizations.Remove(authorization);
}
using var transaction = CreateTransaction();
// Remove all the tokens associated with the application.
foreach (var token in await ListTokensAsync())
// Remove all the authorizations associated with the application and
// the tokens attached to these implicit or explicit authorizations.
foreach (var authorization in await ListAuthorizationsAsync())
{
foreach (var token in authorization.Tokens)
{
Tokens.Remove(token);
}
Applications.Remove(application);
Authorizations.Remove(authorization);
}
try
{
await Context.SaveChangesAsync(cancellationToken);
transaction?.Commit();
}
// Remove all the tokens associated with the application.
foreach (var token in await ListTokensAsync())
{
Tokens.Remove(token);
}
catch (DbUpdateConcurrencyException exception)
{
throw new OpenIddictExceptions.ConcurrencyException(new StringBuilder()
.AppendLine("The application was concurrently updated and cannot be persisted in its current state.")
.Append("Reload the application from the database and retry the operation.")
.ToString(), exception);
}
Applications.Remove(application);
try
{
await Context.SaveChangesAsync(cancellationToken);
transaction?.Commit();
}
catch (DbUpdateConcurrencyException exception)
{
throw new OpenIddictExceptions.ConcurrencyException(new StringBuilder()
.AppendLine("The application was concurrently updated and cannot be persisted in its current state.")
.Append("Reload the application from the database and retry the operation.")
.ToString(), exception);
}
}
@ -235,10 +230,10 @@ namespace OpenIddict.EntityFramework
/// <param name="identifier">The unique identifier associated with the application.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the client application corresponding to the identifier.
/// </returns>
public virtual Task<TApplication> FindByIdAsync([NotNull] string identifier, CancellationToken cancellationToken)
public virtual ValueTask<TApplication> FindByIdAsync([NotNull] string identifier, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(identifier))
{
@ -247,9 +242,9 @@ namespace OpenIddict.EntityFramework
var key = ConvertIdentifierFromString(identifier);
return (from application in Applications
where application.Id.Equals(key)
select application).FirstOrDefaultAsync();
return new ValueTask<TApplication>((from application in Applications
where application.Id.Equals(key)
select application).FirstOrDefaultAsync());
}
/// <summary>
@ -258,19 +253,19 @@ namespace OpenIddict.EntityFramework
/// <param name="identifier">The client identifier associated with the application.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the client application corresponding to the identifier.
/// </returns>
public virtual Task<TApplication> FindByClientIdAsync([NotNull] string identifier, CancellationToken cancellationToken)
public virtual ValueTask<TApplication> FindByClientIdAsync([NotNull] string identifier, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(identifier))
{
throw new ArgumentException("The identifier cannot be null or empty.", nameof(identifier));
}
return (from application in Applications
where application.ClientId == identifier
select application).FirstOrDefaultAsync();
return new ValueTask<TApplication>((from application in Applications
where application.ClientId == identifier
select application).FirstOrDefaultAsync());
}
/// <summary>
@ -278,11 +273,8 @@ namespace OpenIddict.EntityFramework
/// </summary>
/// <param name="address">The post_logout_redirect_uri associated with the applications.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation, whose result
/// returns the client applications corresponding to the specified post_logout_redirect_uri.
/// </returns>
public virtual async Task<ImmutableArray<TApplication>> FindByPostLogoutRedirectUriAsync(
/// <returns>The client applications corresponding to the specified post_logout_redirect_uri.</returns>
public virtual IAsyncEnumerable<TApplication> FindByPostLogoutRedirectUriAsync(
[NotNull] string address, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(address))
@ -295,30 +287,10 @@ namespace OpenIddict.EntityFramework
// are retrieved, a second pass is made to ensure only valid elements are returned.
// Implementers that use this method in a hot path may want to override this method
// to use SQL Server 2016 functions like JSON_VALUE to make the query more efficient.
var applications = await (from application in Applications
where application.PostLogoutRedirectUris.Contains(address)
select application).ToListAsync(cancellationToken);
var builder = ImmutableArray.CreateBuilder<TApplication>(applications.Count);
foreach (var application in applications)
{
foreach (var uri in await GetPostLogoutRedirectUrisAsync(application, cancellationToken))
{
// Note: the post_logout_redirect_uri must be compared
// using case-sensitive "Simple String Comparison".
if (string.Equals(uri, address, StringComparison.Ordinal))
{
builder.Add(application);
break;
}
}
}
return builder.Count == builder.Capacity ?
builder.MoveToImmutable() :
builder.ToImmutable();
return Applications.Where(application => application.PostLogoutRedirectUris.Contains(address))
.AsAsyncEnumerable(cancellationToken)
.WhereAwait(async application => (await GetPostLogoutRedirectUrisAsync(application, cancellationToken))
.Contains(address, StringComparer.Ordinal));
}
/// <summary>
@ -326,11 +298,8 @@ namespace OpenIddict.EntityFramework
/// </summary>
/// <param name="address">The redirect_uri associated with the applications.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation, whose result
/// returns the client applications corresponding to the specified redirect_uri.
/// </returns>
public virtual async Task<ImmutableArray<TApplication>> FindByRedirectUriAsync(
/// <returns>The client applications corresponding to the specified redirect_uri.</returns>
public virtual IAsyncEnumerable<TApplication> FindByRedirectUriAsync(
[NotNull] string address, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(address))
@ -343,30 +312,10 @@ namespace OpenIddict.EntityFramework
// are retrieved, a second pass is made to ensure only valid elements are returned.
// Implementers that use this method in a hot path may want to override this method
// to use SQL Server 2016 functions like JSON_VALUE to make the query more efficient.
var applications = await (from application in Applications
where application.RedirectUris.Contains(address)
select application).ToListAsync(cancellationToken);
var builder = ImmutableArray.CreateBuilder<TApplication>(applications.Count);
foreach (var application in applications)
{
foreach (var uri in await GetRedirectUrisAsync(application, cancellationToken))
{
// Note: the redirect_uri must be compared using case-sensitive "Simple String Comparison".
// See http://openid.net/specs/openid-connect-core-1_0.html#AuthRequest for more information.
if (string.Equals(uri, address, StringComparison.Ordinal))
{
builder.Add(application);
break;
}
}
}
return builder.Count == builder.Capacity ?
builder.MoveToImmutable() :
builder.ToImmutable();
return Applications.Where(application => application.RedirectUris.Contains(address))
.AsAsyncEnumerable(cancellationToken)
.WhereAwait(async application => (await GetRedirectUrisAsync(application, cancellationToken))
.Contains(address, StringComparer.Ordinal));
}
/// <summary>
@ -378,10 +327,10 @@ namespace OpenIddict.EntityFramework
/// <param name="state">The optional state.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the first element returned when executing the query.
/// </returns>
public virtual Task<TResult> GetAsync<TState, TResult>(
public virtual ValueTask<TResult> GetAsync<TState, TResult>(
[NotNull] Func<IQueryable<TApplication>, TState, IQueryable<TResult>> query,
[CanBeNull] TState state, CancellationToken cancellationToken)
{
@ -390,7 +339,7 @@ namespace OpenIddict.EntityFramework
throw new ArgumentNullException(nameof(query));
}
return query(Applications, state).FirstOrDefaultAsync(cancellationToken);
return new ValueTask<TResult>(query(Applications, state).FirstOrDefaultAsync(cancellationToken));
}
/// <summary>
@ -687,11 +636,8 @@ namespace OpenIddict.EntityFramework
/// <param name="count">The number of results to return.</param>
/// <param name="offset">The number of results to skip.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the elements returned when executing the specified query.
/// </returns>
public virtual async Task<ImmutableArray<TApplication>> ListAsync(
/// <returns>All the elements returned when executing the specified query.</returns>
public virtual IAsyncEnumerable<TApplication> ListAsync(
[CanBeNull] int? count, [CanBeNull] int? offset, CancellationToken cancellationToken)
{
var query = Applications.OrderBy(application => application.Id).AsQueryable();
@ -706,7 +652,7 @@ namespace OpenIddict.EntityFramework
query = query.Take(count.Value);
}
return ImmutableArray.CreateRange(await query.ToListAsync(cancellationToken));
return query.AsAsyncEnumerable(cancellationToken);
}
/// <summary>
@ -717,11 +663,8 @@ namespace OpenIddict.EntityFramework
/// <param name="query">The query to execute.</param>
/// <param name="state">The optional state.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the elements returned when executing the specified query.
/// </returns>
public virtual async Task<ImmutableArray<TResult>> ListAsync<TState, TResult>(
/// <returns>All the elements returned when executing the specified query.</returns>
public virtual IAsyncEnumerable<TResult> ListAsync<TState, TResult>(
[NotNull] Func<IQueryable<TApplication>, TState, IQueryable<TResult>> query,
[CanBeNull] TState state, CancellationToken cancellationToken)
{
@ -730,7 +673,7 @@ namespace OpenIddict.EntityFramework
throw new ArgumentNullException(nameof(query));
}
return ImmutableArray.CreateRange(await query(Applications, state).ToListAsync(cancellationToken));
return query(Applications, state).AsAsyncEnumerable(cancellationToken);
}
/// <summary>
@ -739,10 +682,8 @@ namespace OpenIddict.EntityFramework
/// <param name="application">The application.</param>
/// <param name="identifier">The client identifier associated with the application.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetClientIdAsync([NotNull] TApplication application,
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetClientIdAsync([NotNull] TApplication application,
[CanBeNull] string identifier, CancellationToken cancellationToken)
{
if (application == null)
@ -752,7 +693,7 @@ namespace OpenIddict.EntityFramework
application.ClientId = identifier;
return Task.CompletedTask;
return default;
}
/// <summary>
@ -763,10 +704,8 @@ namespace OpenIddict.EntityFramework
/// <param name="application">The application.</param>
/// <param name="secret">The client secret associated with the application.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetClientSecretAsync([NotNull] TApplication application,
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetClientSecretAsync([NotNull] TApplication application,
[CanBeNull] string secret, CancellationToken cancellationToken)
{
if (application == null)
@ -776,7 +715,7 @@ namespace OpenIddict.EntityFramework
application.ClientSecret = secret;
return Task.CompletedTask;
return default;
}
/// <summary>
@ -785,10 +724,8 @@ namespace OpenIddict.EntityFramework
/// <param name="application">The application.</param>
/// <param name="type">The client type associated with the application.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetClientTypeAsync([NotNull] TApplication application,
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetClientTypeAsync([NotNull] TApplication application,
[CanBeNull] string type, CancellationToken cancellationToken)
{
if (application == null)
@ -798,7 +735,7 @@ namespace OpenIddict.EntityFramework
application.Type = type;
return Task.CompletedTask;
return default;
}
/// <summary>
@ -807,10 +744,8 @@ namespace OpenIddict.EntityFramework
/// <param name="application">The application.</param>
/// <param name="type">The consent type associated with the application.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetConsentTypeAsync([NotNull] TApplication application,
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetConsentTypeAsync([NotNull] TApplication application,
[CanBeNull] string type, CancellationToken cancellationToken)
{
if (application == null)
@ -820,7 +755,7 @@ namespace OpenIddict.EntityFramework
application.ConsentType = type;
return Task.CompletedTask;
return default;
}
/// <summary>
@ -829,10 +764,8 @@ namespace OpenIddict.EntityFramework
/// <param name="application">The application.</param>
/// <param name="name">The display name associated with the application.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetDisplayNameAsync([NotNull] TApplication application,
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetDisplayNameAsync([NotNull] TApplication application,
[CanBeNull] string name, CancellationToken cancellationToken)
{
if (application == null)
@ -842,7 +775,7 @@ namespace OpenIddict.EntityFramework
application.DisplayName = name;
return Task.CompletedTask;
return default;
}
/// <summary>
@ -851,10 +784,8 @@ namespace OpenIddict.EntityFramework
/// <param name="application">The application.</param>
/// <param name="permissions">The permissions associated with the application </param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetPermissionsAsync([NotNull] TApplication application, ImmutableArray<string> permissions, CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetPermissionsAsync([NotNull] TApplication application, ImmutableArray<string> permissions, CancellationToken cancellationToken)
{
if (application == null)
{
@ -865,12 +796,12 @@ namespace OpenIddict.EntityFramework
{
application.Permissions = null;
return Task.CompletedTask;
return default;
}
application.Permissions = new JArray(permissions.ToArray()).ToString(Formatting.None);
return Task.CompletedTask;
return default;
}
/// <summary>
@ -879,10 +810,8 @@ namespace OpenIddict.EntityFramework
/// <param name="application">The application.</param>
/// <param name="addresses">The logout callback addresses associated with the application </param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetPostLogoutRedirectUrisAsync([NotNull] TApplication application,
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetPostLogoutRedirectUrisAsync([NotNull] TApplication application,
ImmutableArray<string> addresses, CancellationToken cancellationToken)
{
if (application == null)
@ -894,12 +823,12 @@ namespace OpenIddict.EntityFramework
{
application.PostLogoutRedirectUris = null;
return Task.CompletedTask;
return default;
}
application.PostLogoutRedirectUris = new JArray(addresses.ToArray()).ToString(Formatting.None);
return Task.CompletedTask;
return default;
}
/// <summary>
@ -908,10 +837,8 @@ namespace OpenIddict.EntityFramework
/// <param name="application">The application.</param>
/// <param name="properties">The additional properties associated with the application.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetPropertiesAsync([NotNull] TApplication application, [CanBeNull] JObject properties, CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetPropertiesAsync([NotNull] TApplication application, [CanBeNull] JObject properties, CancellationToken cancellationToken)
{
if (application == null)
{
@ -922,12 +849,12 @@ namespace OpenIddict.EntityFramework
{
application.Properties = null;
return Task.CompletedTask;
return default;
}
application.Properties = properties.ToString(Formatting.None);
return Task.CompletedTask;
return default;
}
/// <summary>
@ -936,10 +863,8 @@ namespace OpenIddict.EntityFramework
/// <param name="application">The application.</param>
/// <param name="addresses">The callback addresses associated with the application </param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetRedirectUrisAsync([NotNull] TApplication application,
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetRedirectUrisAsync([NotNull] TApplication application,
ImmutableArray<string> addresses, CancellationToken cancellationToken)
{
if (application == null)
@ -951,12 +876,12 @@ namespace OpenIddict.EntityFramework
{
application.RedirectUris = null;
return Task.CompletedTask;
return default;
}
application.RedirectUris = new JArray(addresses.ToArray()).ToString(Formatting.None);
return Task.CompletedTask;
return default;
}
/// <summary>
@ -964,10 +889,8 @@ namespace OpenIddict.EntityFramework
/// </summary>
/// <param name="application">The application to update.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual async Task UpdateAsync([NotNull] TApplication application, CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual async ValueTask UpdateAsync([NotNull] TApplication application, CancellationToken cancellationToken)
{
if (application == null)
{

300
src/OpenIddict.EntityFramework/Stores/OpenIddictAuthorizationStore.cs

@ -103,11 +103,11 @@ namespace OpenIddict.EntityFramework
/// </summary>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the number of authorizations in the database.
/// </returns>
public virtual Task<long> CountAsync(CancellationToken cancellationToken)
=> Authorizations.LongCountAsync();
public virtual ValueTask<long> CountAsync(CancellationToken cancellationToken)
=> new ValueTask<long>(Authorizations.LongCountAsync());
/// <summary>
/// Determines the number of authorizations that match the specified query.
@ -116,17 +116,17 @@ namespace OpenIddict.EntityFramework
/// <param name="query">The query to execute.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the number of authorizations that match the specified query.
/// </returns>
public virtual Task<long> CountAsync<TResult>([NotNull] Func<IQueryable<TAuthorization>, IQueryable<TResult>> query, CancellationToken cancellationToken)
public virtual ValueTask<long> CountAsync<TResult>([NotNull] Func<IQueryable<TAuthorization>, IQueryable<TResult>> query, CancellationToken cancellationToken)
{
if (query == null)
{
throw new ArgumentNullException(nameof(query));
}
return query(Authorizations).LongCountAsync();
return new ValueTask<long>(query(Authorizations).LongCountAsync());
}
/// <summary>
@ -134,10 +134,8 @@ namespace OpenIddict.EntityFramework
/// </summary>
/// <param name="authorization">The authorization to create.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task CreateAsync([NotNull] TAuthorization authorization, CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask CreateAsync([NotNull] TAuthorization authorization, CancellationToken cancellationToken)
{
if (authorization == null)
{
@ -146,7 +144,7 @@ namespace OpenIddict.EntityFramework
Authorizations.Add(authorization);
return Context.SaveChangesAsync(cancellationToken);
return new ValueTask(Context.SaveChangesAsync(cancellationToken));
}
/// <summary>
@ -154,10 +152,8 @@ namespace OpenIddict.EntityFramework
/// </summary>
/// <param name="authorization">The authorization to delete.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual async Task DeleteAsync([NotNull] TAuthorization authorization, CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual async ValueTask DeleteAsync([NotNull] TAuthorization authorization, CancellationToken cancellationToken)
{
if (authorization == null)
{
@ -218,11 +214,8 @@ namespace OpenIddict.EntityFramework
/// <param name="subject">The subject associated with the authorization.</param>
/// <param name="client">The client associated with the authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the authorizations corresponding to the subject/client.
/// </returns>
public virtual async Task<ImmutableArray<TAuthorization>> FindAsync(
/// <returns>The authorizations corresponding to the subject/client.</returns>
public virtual IAsyncEnumerable<TAuthorization> FindAsync(
[NotNull] string subject, [NotNull] string client, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(subject))
@ -237,12 +230,11 @@ namespace OpenIddict.EntityFramework
var key = ConvertIdentifierFromString(client);
return ImmutableArray.CreateRange(
await (from authorization in Authorizations.Include(authorization => authorization.Application)
where authorization.Application != null &&
authorization.Application.Id.Equals(key) &&
authorization.Subject == subject
select authorization).ToListAsync(cancellationToken));
return (from authorization in Authorizations.Include(authorization => authorization.Application)
where authorization.Application != null &&
authorization.Application.Id.Equals(key) &&
authorization.Subject == subject
select authorization).AsAsyncEnumerable(cancellationToken);
}
/// <summary>
@ -252,11 +244,8 @@ namespace OpenIddict.EntityFramework
/// <param name="client">The client associated with the authorization.</param>
/// <param name="status">The authorization status.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the authorizations corresponding to the criteria.
/// </returns>
public virtual async Task<ImmutableArray<TAuthorization>> FindAsync(
/// <returns>The authorizations corresponding to the criteria.</returns>
public virtual IAsyncEnumerable<TAuthorization> FindAsync(
[NotNull] string subject, [NotNull] string client,
[NotNull] string status, CancellationToken cancellationToken)
{
@ -277,13 +266,12 @@ namespace OpenIddict.EntityFramework
var key = ConvertIdentifierFromString(client);
return ImmutableArray.CreateRange(
await (from authorization in Authorizations.Include(authorization => authorization.Application)
where authorization.Application != null &&
authorization.Application.Id.Equals(key) &&
authorization.Subject == subject &&
authorization.Status == status
select authorization).ToListAsync(cancellationToken));
return (from authorization in Authorizations.Include(authorization => authorization.Application)
where authorization.Application != null &&
authorization.Application.Id.Equals(key) &&
authorization.Subject == subject &&
authorization.Status == status
select authorization).AsAsyncEnumerable(cancellationToken);
}
/// <summary>
@ -294,11 +282,8 @@ namespace OpenIddict.EntityFramework
/// <param name="status">The authorization status.</param>
/// <param name="type">The authorization type.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the authorizations corresponding to the criteria.
/// </returns>
public virtual async Task<ImmutableArray<TAuthorization>> FindAsync(
/// <returns>The authorizations corresponding to the criteria.</returns>
public virtual IAsyncEnumerable<TAuthorization> FindAsync(
[NotNull] string subject, [NotNull] string client,
[NotNull] string status, [NotNull] string type, CancellationToken cancellationToken)
{
@ -324,14 +309,13 @@ namespace OpenIddict.EntityFramework
var key = ConvertIdentifierFromString(client);
return ImmutableArray.CreateRange(
await (from authorization in Authorizations.Include(authorization => authorization.Application)
where authorization.Application != null &&
authorization.Application.Id.Equals(key) &&
authorization.Subject == subject &&
authorization.Status == status &&
authorization.Type == type
select authorization).ToListAsync(cancellationToken));
return (from authorization in Authorizations.Include(authorization => authorization.Application)
where authorization.Application != null &&
authorization.Application.Id.Equals(key) &&
authorization.Subject == subject &&
authorization.Status == status &&
authorization.Type == type
select authorization).AsAsyncEnumerable(cancellationToken);
}
/// <summary>
@ -343,51 +327,22 @@ namespace OpenIddict.EntityFramework
/// <param name="type">The authorization type.</param>
/// <param name="scopes">The minimal scopes associated with the authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the authorizations corresponding to the criteria.
/// </returns>
public virtual async Task<ImmutableArray<TAuthorization>> FindAsync(
/// <returns>The authorizations corresponding to the criteria.</returns>
public virtual IAsyncEnumerable<TAuthorization> FindAsync(
[NotNull] string subject, [NotNull] string client,
[NotNull] string status, [NotNull] string type,
ImmutableArray<string> scopes, CancellationToken cancellationToken)
{
var authorizations = await FindAsync(subject, client, status, type, cancellationToken);
if (authorizations.IsEmpty)
{
return ImmutableArray.Create<TAuthorization>();
}
var builder = ImmutableArray.CreateBuilder<TAuthorization>(authorizations.Length);
foreach (var authorization in authorizations)
{
async Task<bool> HasScopesAsync()
=> (await GetScopesAsync(authorization, cancellationToken))
.ToImmutableHashSet(StringComparer.Ordinal)
.IsSupersetOf(scopes);
if (await HasScopesAsync())
{
builder.Add(authorization);
}
}
return builder.Count == builder.Capacity ?
builder.MoveToImmutable() :
builder.ToImmutable();
}
=> FindAsync(subject, client, status, type, cancellationToken)
.WhereAwait(async authorization => new HashSet<string>(
await GetScopesAsync(authorization, cancellationToken), StringComparer.Ordinal).IsSupersetOf(scopes));
/// <summary>
/// Retrieves the list of authorizations corresponding to the specified application identifier.
/// </summary>
/// <param name="identifier">The application identifier associated with the authorizations.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the authorizations corresponding to the specified application.
/// </returns>
public virtual async Task<ImmutableArray<TAuthorization>> FindByApplicationIdAsync(
/// <returns>The authorizations corresponding to the specified application.</returns>
public virtual IAsyncEnumerable<TAuthorization> FindByApplicationIdAsync(
[NotNull] string identifier, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(identifier))
@ -397,10 +352,9 @@ namespace OpenIddict.EntityFramework
var key = ConvertIdentifierFromString(identifier);
return ImmutableArray.CreateRange(
await (from authorization in Authorizations.Include(authorization => authorization.Application)
where authorization.Application.Id.Equals(key)
select authorization).ToListAsync(cancellationToken));
return (from authorization in Authorizations.Include(authorization => authorization.Application)
where authorization.Application.Id.Equals(key)
select authorization).AsAsyncEnumerable(cancellationToken);
}
/// <summary>
@ -409,10 +363,10 @@ namespace OpenIddict.EntityFramework
/// <param name="identifier">The unique identifier associated with the authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the authorization corresponding to the identifier.
/// </returns>
public virtual Task<TAuthorization> FindByIdAsync([NotNull] string identifier, CancellationToken cancellationToken)
public virtual ValueTask<TAuthorization> FindByIdAsync([NotNull] string identifier, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(identifier))
{
@ -421,9 +375,9 @@ namespace OpenIddict.EntityFramework
var key = ConvertIdentifierFromString(identifier);
return (from authorization in Authorizations.Include(authorization => authorization.Application)
where authorization.Id.Equals(key)
select authorization).FirstOrDefaultAsync(cancellationToken);
return new ValueTask<TAuthorization>((from authorization in Authorizations.Include(authorization => authorization.Application)
where authorization.Id.Equals(key)
select authorization).FirstOrDefaultAsync(cancellationToken));
}
/// <summary>
@ -431,11 +385,8 @@ namespace OpenIddict.EntityFramework
/// </summary>
/// <param name="subject">The subject associated with the authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the authorizations corresponding to the specified subject.
/// </returns>
public virtual async Task<ImmutableArray<TAuthorization>> FindBySubjectAsync(
/// <returns>The authorizations corresponding to the specified subject.</returns>
public virtual IAsyncEnumerable<TAuthorization> FindBySubjectAsync(
[NotNull] string subject, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(subject))
@ -443,10 +394,9 @@ namespace OpenIddict.EntityFramework
throw new ArgumentException("The subject cannot be null or empty.", nameof(subject));
}
return ImmutableArray.CreateRange(
await (from authorization in Authorizations.Include(authorization => authorization.Application)
where authorization.Subject == subject
select authorization).ToListAsync(cancellationToken));
return (from authorization in Authorizations.Include(authorization => authorization.Application)
where authorization.Subject == subject
select authorization).AsAsyncEnumerable(cancellationToken);
}
/// <summary>
@ -494,10 +444,10 @@ namespace OpenIddict.EntityFramework
/// <param name="state">The optional state.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the first element returned when executing the query.
/// </returns>
public virtual Task<TResult> GetAsync<TState, TResult>(
public virtual ValueTask<TResult> GetAsync<TState, TResult>(
[NotNull] Func<IQueryable<TAuthorization>, TState, IQueryable<TResult>> query,
[CanBeNull] TState state, CancellationToken cancellationToken)
{
@ -506,8 +456,8 @@ namespace OpenIddict.EntityFramework
throw new ArgumentNullException(nameof(query));
}
return query(
Authorizations.Include(authorization => authorization.Application), state).FirstOrDefaultAsync(cancellationToken);
return new ValueTask<TResult>(query(
Authorizations.Include(authorization => authorization.Application), state).FirstOrDefaultAsync(cancellationToken));
}
/// <summary>
@ -690,11 +640,8 @@ namespace OpenIddict.EntityFramework
/// <param name="count">The number of results to return.</param>
/// <param name="offset">The number of results to skip.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the elements returned when executing the specified query.
/// </returns>
public virtual async Task<ImmutableArray<TAuthorization>> ListAsync(
/// <returns>All the elements returned when executing the specified query.</returns>
public virtual IAsyncEnumerable<TAuthorization> ListAsync(
[CanBeNull] int? count, [CanBeNull] int? offset, CancellationToken cancellationToken)
{
var query = Authorizations.Include(authorization => authorization.Application)
@ -711,7 +658,7 @@ namespace OpenIddict.EntityFramework
query = query.Take(count.Value);
}
return ImmutableArray.CreateRange(await query.ToListAsync(cancellationToken));
return query.AsAsyncEnumerable(cancellationToken);
}
/// <summary>
@ -722,11 +669,8 @@ namespace OpenIddict.EntityFramework
/// <param name="query">The query to execute.</param>
/// <param name="state">The optional state.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the elements returned when executing the specified query.
/// </returns>
public virtual async Task<ImmutableArray<TResult>> ListAsync<TState, TResult>(
/// <returns>All the elements returned when executing the specified query.</returns>
public virtual IAsyncEnumerable<TResult> ListAsync<TState, TResult>(
[NotNull] Func<IQueryable<TAuthorization>, TState, IQueryable<TResult>> query,
[CanBeNull] TState state, CancellationToken cancellationToken)
{
@ -735,18 +679,15 @@ namespace OpenIddict.EntityFramework
throw new ArgumentNullException(nameof(query));
}
return ImmutableArray.CreateRange(await query(
Authorizations.Include(authorization => authorization.Application), state).ToListAsync(cancellationToken));
return query(Authorizations.Include(authorization => authorization.Application), state).AsAsyncEnumerable(cancellationToken);
}
/// <summary>
/// Removes the authorizations that are marked as invalid and the ad-hoc ones that have no valid/nonexpired token attached.
/// </summary>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual async Task PruneAsync(CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual async ValueTask PruneAsync(CancellationToken cancellationToken)
{
// Note: Entity Framework 6.x doesn't support set-based deletes, which prevents removing
// entities in a single command without having to retrieve and materialize them first.
@ -770,7 +711,7 @@ namespace OpenIddict.EntityFramework
}
}
for (var offset = 0; offset < 100_000; offset = offset + 1_000)
for (var offset = 0; offset < 100_000; offset += 1_000)
{
cancellationToken.ThrowIfCancellationRequested();
@ -778,44 +719,43 @@ namespace OpenIddict.EntityFramework
// after it was retrieved from the database, the following logic is executed in
// a repeatable read transaction, that will put a lock on the retrieved entries
// and thus prevent them from being concurrently modified outside this block.
using (var transaction = CreateTransaction())
using var transaction = CreateTransaction();
var authorizations =
await (from authorization in Authorizations.Include(authorization => authorization.Tokens)
where authorization.Status != OpenIddictConstants.Statuses.Valid ||
(authorization.Type == OpenIddictConstants.AuthorizationTypes.AdHoc &&
!authorization.Tokens.Any(token => token.Status == OpenIddictConstants.Statuses.Valid &&
token.ExpirationDate > DateTimeOffset.UtcNow))
orderby authorization.Id
select authorization).Skip(offset).Take(1_000).ToListAsync(cancellationToken);
if (authorizations.Count == 0)
{
var authorizations =
await (from authorization in Authorizations.Include(authorization => authorization.Tokens)
where authorization.Status != OpenIddictConstants.Statuses.Valid ||
(authorization.Type == OpenIddictConstants.AuthorizationTypes.AdHoc &&
!authorization.Tokens.Any(token => token.Status == OpenIddictConstants.Statuses.Valid &&
token.ExpirationDate > DateTimeOffset.UtcNow))
orderby authorization.Id
select authorization).Skip(offset).Take(1_000).ToListAsync(cancellationToken);
if (authorizations.Count == 0)
{
break;
}
break;
}
// Note: new tokens may be attached after the authorizations were retrieved
// from the database since the transaction level is deliberately limited to
// repeatable read instead of serializable for performance reasons). In this
// case, the operation will fail, which is considered an acceptable risk.
Authorizations.RemoveRange(authorizations);
Tokens.RemoveRange(authorizations.SelectMany(authorization => authorization.Tokens));
// Note: new tokens may be attached after the authorizations were retrieved
// from the database since the transaction level is deliberately limited to
// repeatable read instead of serializable for performance reasons). In this
// case, the operation will fail, which is considered an acceptable risk.
Authorizations.RemoveRange(authorizations);
Tokens.RemoveRange(authorizations.SelectMany(authorization => authorization.Tokens));
try
{
await Context.SaveChangesAsync(cancellationToken);
transaction?.Commit();
}
try
{
await Context.SaveChangesAsync(cancellationToken);
transaction?.Commit();
}
catch (Exception exception)
catch (Exception exception)
{
if (exceptions == null)
{
if (exceptions == null)
{
exceptions = new List<Exception>(capacity: 1);
}
exceptions.Add(exception);
exceptions = new List<Exception>(capacity: 1);
}
exceptions.Add(exception);
}
}
@ -832,9 +772,9 @@ namespace OpenIddict.EntityFramework
/// <param name="identifier">The unique identifier associated with the client application.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual async Task SetApplicationIdAsync([NotNull] TAuthorization authorization,
public virtual async ValueTask SetApplicationIdAsync([NotNull] TAuthorization authorization,
[CanBeNull] string identifier, CancellationToken cancellationToken)
{
if (authorization == null)
@ -878,9 +818,9 @@ namespace OpenIddict.EntityFramework
/// <param name="properties">The additional properties associated with the authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetPropertiesAsync([NotNull] TAuthorization authorization, [CanBeNull] JObject properties, CancellationToken cancellationToken)
public virtual ValueTask SetPropertiesAsync([NotNull] TAuthorization authorization, [CanBeNull] JObject properties, CancellationToken cancellationToken)
{
if (authorization == null)
{
@ -891,12 +831,12 @@ namespace OpenIddict.EntityFramework
{
authorization.Properties = null;
return Task.CompletedTask;
return default;
}
authorization.Properties = properties.ToString(Formatting.None);
return Task.CompletedTask;
return default;
}
/// <summary>
@ -906,9 +846,9 @@ namespace OpenIddict.EntityFramework
/// <param name="scopes">The scopes associated with the authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetScopesAsync([NotNull] TAuthorization authorization,
public virtual ValueTask SetScopesAsync([NotNull] TAuthorization authorization,
ImmutableArray<string> scopes, CancellationToken cancellationToken)
{
if (authorization == null)
@ -920,12 +860,12 @@ namespace OpenIddict.EntityFramework
{
authorization.Scopes = null;
return Task.CompletedTask;
return default;
}
authorization.Scopes = new JArray(scopes.ToArray()).ToString(Formatting.None);
return Task.CompletedTask;
return default;
}
/// <summary>
@ -935,9 +875,9 @@ namespace OpenIddict.EntityFramework
/// <param name="status">The status associated with the authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetStatusAsync([NotNull] TAuthorization authorization,
public virtual ValueTask SetStatusAsync([NotNull] TAuthorization authorization,
[CanBeNull] string status, CancellationToken cancellationToken)
{
if (authorization == null)
@ -947,7 +887,7 @@ namespace OpenIddict.EntityFramework
authorization.Status = status;
return Task.CompletedTask;
return default;
}
/// <summary>
@ -957,9 +897,9 @@ namespace OpenIddict.EntityFramework
/// <param name="subject">The subject associated with the authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetSubjectAsync([NotNull] TAuthorization authorization,
public virtual ValueTask SetSubjectAsync([NotNull] TAuthorization authorization,
[CanBeNull] string subject, CancellationToken cancellationToken)
{
if (authorization == null)
@ -969,7 +909,7 @@ namespace OpenIddict.EntityFramework
authorization.Subject = subject;
return Task.CompletedTask;
return default;
}
/// <summary>
@ -979,9 +919,9 @@ namespace OpenIddict.EntityFramework
/// <param name="type">The type associated with the authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetTypeAsync([NotNull] TAuthorization authorization,
public virtual ValueTask SetTypeAsync([NotNull] TAuthorization authorization,
[CanBeNull] string type, CancellationToken cancellationToken)
{
if (authorization == null)
@ -991,7 +931,7 @@ namespace OpenIddict.EntityFramework
authorization.Type = type;
return Task.CompletedTask;
return default;
}
/// <summary>
@ -1000,9 +940,9 @@ namespace OpenIddict.EntityFramework
/// <param name="authorization">The authorization to update.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual async Task UpdateAsync([NotNull] TAuthorization authorization, CancellationToken cancellationToken)
public virtual async ValueTask UpdateAsync([NotNull] TAuthorization authorization, CancellationToken cancellationToken)
{
if (authorization == null)
{

161
src/OpenIddict.EntityFramework/Stores/OpenIddictScopeStore.cs

@ -5,6 +5,7 @@
*/
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.ComponentModel;
using System.Data.Entity;
@ -85,11 +86,11 @@ namespace OpenIddict.EntityFramework
/// </summary>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the number of scopes in the database.
/// </returns>
public virtual Task<long> CountAsync(CancellationToken cancellationToken)
=> Scopes.LongCountAsync();
public virtual ValueTask<long> CountAsync(CancellationToken cancellationToken)
=> new ValueTask<long>(Scopes.LongCountAsync());
/// <summary>
/// Determines the number of scopes that match the specified query.
@ -98,17 +99,17 @@ namespace OpenIddict.EntityFramework
/// <param name="query">The query to execute.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the number of scopes that match the specified query.
/// </returns>
public virtual Task<long> CountAsync<TResult>([NotNull] Func<IQueryable<TScope>, IQueryable<TResult>> query, CancellationToken cancellationToken)
public virtual ValueTask<long> CountAsync<TResult>([NotNull] Func<IQueryable<TScope>, IQueryable<TResult>> query, CancellationToken cancellationToken)
{
if (query == null)
{
throw new ArgumentNullException(nameof(query));
}
return query(Scopes).LongCountAsync();
return new ValueTask<long>(query(Scopes).LongCountAsync());
}
/// <summary>
@ -116,10 +117,8 @@ namespace OpenIddict.EntityFramework
/// </summary>
/// <param name="scope">The scope to create.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task CreateAsync([NotNull] TScope scope, CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask CreateAsync([NotNull] TScope scope, CancellationToken cancellationToken)
{
if (scope == null)
{
@ -128,7 +127,7 @@ namespace OpenIddict.EntityFramework
Scopes.Add(scope);
return Context.SaveChangesAsync(cancellationToken);
return new ValueTask(Context.SaveChangesAsync(cancellationToken));
}
/// <summary>
@ -136,10 +135,8 @@ namespace OpenIddict.EntityFramework
/// </summary>
/// <param name="scope">The scope to delete.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual async Task DeleteAsync([NotNull] TScope scope, CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual async ValueTask DeleteAsync([NotNull] TScope scope, CancellationToken cancellationToken)
{
if (scope == null)
{
@ -168,10 +165,10 @@ namespace OpenIddict.EntityFramework
/// <param name="identifier">The unique identifier associated with the scope.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the scope corresponding to the identifier.
/// </returns>
public virtual Task<TScope> FindByIdAsync([NotNull] string identifier, CancellationToken cancellationToken)
public virtual ValueTask<TScope> FindByIdAsync([NotNull] string identifier, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(identifier))
{
@ -180,9 +177,9 @@ namespace OpenIddict.EntityFramework
var key = ConvertIdentifierFromString(identifier);
return (from scope in Scopes
where scope.Id.Equals(key)
select scope).FirstOrDefaultAsync(cancellationToken);
return new ValueTask<TScope>((from scope in Scopes
where scope.Id.Equals(key)
select scope).FirstOrDefaultAsync(cancellationToken));
}
/// <summary>
@ -191,19 +188,19 @@ namespace OpenIddict.EntityFramework
/// <param name="name">The name associated with the scope.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the scope corresponding to the specified name.
/// </returns>
public virtual Task<TScope> FindByNameAsync([NotNull] string name, CancellationToken cancellationToken)
public virtual ValueTask<TScope> FindByNameAsync([NotNull] string name, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(name))
{
throw new ArgumentException("The scope name cannot be null or empty.", nameof(name));
}
return (from scope in Scopes
where scope.Name == name
select scope).FirstOrDefaultAsync(cancellationToken);
return new ValueTask<TScope>((from scope in Scopes
where scope.Name == name
select scope).FirstOrDefaultAsync(cancellationToken));
}
/// <summary>
@ -211,11 +208,8 @@ namespace OpenIddict.EntityFramework
/// </summary>
/// <param name="names">The names associated with the scopes.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the scopes corresponding to the specified names.
/// </returns>
public virtual async Task<ImmutableArray<TScope>> FindByNamesAsync(
/// <returns>The scopes corresponding to the specified names.</returns>
public virtual IAsyncEnumerable<TScope> FindByNamesAsync(
ImmutableArray<string> names, CancellationToken cancellationToken)
{
if (names.Any(name => string.IsNullOrEmpty(name)))
@ -223,10 +217,9 @@ namespace OpenIddict.EntityFramework
throw new ArgumentException("Scope names cannot be null or empty.", nameof(names));
}
return ImmutableArray.CreateRange(
await (from scope in Scopes
where names.Contains(scope.Name)
select scope).ToListAsync(cancellationToken));
return (from scope in Scopes
where names.Contains(scope.Name)
select scope).AsAsyncEnumerable(cancellationToken);
}
/// <summary>
@ -234,11 +227,8 @@ namespace OpenIddict.EntityFramework
/// </summary>
/// <param name="resource">The resource associated with the scopes.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the scopes associated with the specified resource.
/// </returns>
public virtual async Task<ImmutableArray<TScope>> FindByResourceAsync(
/// <returns>The scopes associated with the specified resource.</returns>
public virtual IAsyncEnumerable<TScope> FindByResourceAsync(
[NotNull] string resource, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(resource))
@ -251,22 +241,9 @@ namespace OpenIddict.EntityFramework
// are retrieved, a second pass is made to ensure only valid elements are returned.
// Implementers that use this method in a hot path may want to override this method
// to use SQL Server 2016 functions like JSON_VALUE to make the query more efficient.
var scopes = await (from scope in Scopes
where scope.Resources.Contains(resource)
select scope).ToListAsync(cancellationToken);
var builder = ImmutableArray.CreateBuilder<TScope>();
foreach (var scope in scopes)
{
var resources = await GetResourcesAsync(scope, cancellationToken);
if (resources.Contains(resource, StringComparer.OrdinalIgnoreCase))
{
builder.Add(scope);
}
}
return builder.ToImmutable();
return Scopes.Where(scope => scope.Resources.Contains(resource))
.AsAsyncEnumerable(cancellationToken)
.WhereAwait(async scope => (await GetResourcesAsync(scope, cancellationToken)).Contains(resource, StringComparer.Ordinal));
}
/// <summary>
@ -278,10 +255,10 @@ namespace OpenIddict.EntityFramework
/// <param name="state">The optional state.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the first element returned when executing the query.
/// </returns>
public virtual Task<TResult> GetAsync<TState, TResult>(
public virtual ValueTask<TResult> GetAsync<TState, TResult>(
[NotNull] Func<IQueryable<TScope>, TState, IQueryable<TResult>> query,
[CanBeNull] TState state, CancellationToken cancellationToken)
{
@ -290,7 +267,7 @@ namespace OpenIddict.EntityFramework
throw new ArgumentNullException(nameof(query));
}
return query(Scopes, state).FirstOrDefaultAsync(cancellationToken);
return new ValueTask<TResult>(query(Scopes, state).FirstOrDefaultAsync(cancellationToken));
}
/// <summary>
@ -473,11 +450,8 @@ namespace OpenIddict.EntityFramework
/// <param name="count">The number of results to return.</param>
/// <param name="offset">The number of results to skip.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the elements returned when executing the specified query.
/// </returns>
public virtual async Task<ImmutableArray<TScope>> ListAsync(
/// <returns>All the elements returned when executing the specified query.</returns>
public virtual IAsyncEnumerable<TScope> ListAsync(
[CanBeNull] int? count, [CanBeNull] int? offset, CancellationToken cancellationToken)
{
var query = Scopes.OrderBy(scope => scope.Id).AsQueryable();
@ -492,7 +466,7 @@ namespace OpenIddict.EntityFramework
query = query.Take(count.Value);
}
return ImmutableArray.CreateRange(await query.ToListAsync(cancellationToken));
return query.AsAsyncEnumerable(cancellationToken);
}
/// <summary>
@ -503,11 +477,8 @@ namespace OpenIddict.EntityFramework
/// <param name="query">The query to execute.</param>
/// <param name="state">The optional state.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the elements returned when executing the specified query.
/// </returns>
public virtual async Task<ImmutableArray<TResult>> ListAsync<TState, TResult>(
/// <returns>All the elements returned when executing the specified query.</returns>
public virtual IAsyncEnumerable<TResult> ListAsync<TState, TResult>(
[NotNull] Func<IQueryable<TScope>, TState, IQueryable<TResult>> query,
[CanBeNull] TState state, CancellationToken cancellationToken)
{
@ -516,7 +487,7 @@ namespace OpenIddict.EntityFramework
throw new ArgumentNullException(nameof(query));
}
return ImmutableArray.CreateRange(await query(Scopes, state).ToListAsync(cancellationToken));
return query(Scopes, state).AsAsyncEnumerable(cancellationToken);
}
/// <summary>
@ -525,10 +496,8 @@ namespace OpenIddict.EntityFramework
/// <param name="scope">The scope.</param>
/// <param name="description">The description associated with the authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetDescriptionAsync([NotNull] TScope scope, [CanBeNull] string description, CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetDescriptionAsync([NotNull] TScope scope, [CanBeNull] string description, CancellationToken cancellationToken)
{
if (scope == null)
{
@ -537,7 +506,7 @@ namespace OpenIddict.EntityFramework
scope.Description = description;
return Task.CompletedTask;
return default;
}
/// <summary>
@ -546,10 +515,8 @@ namespace OpenIddict.EntityFramework
/// <param name="scope">The scope.</param>
/// <param name="name">The display name associated with the scope.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetDisplayNameAsync([NotNull] TScope scope, [CanBeNull] string name, CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetDisplayNameAsync([NotNull] TScope scope, [CanBeNull] string name, CancellationToken cancellationToken)
{
if (scope == null)
{
@ -558,7 +525,7 @@ namespace OpenIddict.EntityFramework
scope.DisplayName = name;
return Task.CompletedTask;
return default;
}
/// <summary>
@ -567,10 +534,8 @@ namespace OpenIddict.EntityFramework
/// <param name="scope">The scope.</param>
/// <param name="name">The name associated with the authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetNameAsync([NotNull] TScope scope, [CanBeNull] string name, CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetNameAsync([NotNull] TScope scope, [CanBeNull] string name, CancellationToken cancellationToken)
{
if (scope == null)
{
@ -579,7 +544,7 @@ namespace OpenIddict.EntityFramework
scope.Name = name;
return Task.CompletedTask;
return default;
}
/// <summary>
@ -588,10 +553,8 @@ namespace OpenIddict.EntityFramework
/// <param name="scope">The scope.</param>
/// <param name="properties">The additional properties associated with the scope.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetPropertiesAsync([NotNull] TScope scope, [CanBeNull] JObject properties, CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetPropertiesAsync([NotNull] TScope scope, [CanBeNull] JObject properties, CancellationToken cancellationToken)
{
if (scope == null)
{
@ -602,12 +565,12 @@ namespace OpenIddict.EntityFramework
{
scope.Properties = null;
return Task.CompletedTask;
return default;
}
scope.Properties = properties.ToString(Formatting.None);
return Task.CompletedTask;
return default;
}
/// <summary>
@ -616,10 +579,8 @@ namespace OpenIddict.EntityFramework
/// <param name="scope">The scope.</param>
/// <param name="resources">The resources associated with the scope.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetResourcesAsync([NotNull] TScope scope, ImmutableArray<string> resources, CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetResourcesAsync([NotNull] TScope scope, ImmutableArray<string> resources, CancellationToken cancellationToken)
{
if (scope == null)
{
@ -630,12 +591,12 @@ namespace OpenIddict.EntityFramework
{
scope.Resources = null;
return Task.CompletedTask;
return default;
}
scope.Resources = new JArray(resources.ToArray()).ToString(Formatting.None);
return Task.CompletedTask;
return default;
}
/// <summary>
@ -643,10 +604,8 @@ namespace OpenIddict.EntityFramework
/// </summary>
/// <param name="scope">The scope to update.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual async Task UpdateAsync([NotNull] TScope scope, CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual async ValueTask UpdateAsync([NotNull] TScope scope, CancellationToken cancellationToken)
{
if (scope == null)
{

320
src/OpenIddict.EntityFramework/Stores/OpenIddictTokenStore.cs

@ -103,11 +103,11 @@ namespace OpenIddict.EntityFramework
/// </summary>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the number of applications in the database.
/// </returns>
public virtual Task<long> CountAsync(CancellationToken cancellationToken)
=> Tokens.LongCountAsync();
public virtual ValueTask<long> CountAsync(CancellationToken cancellationToken)
=> new ValueTask<long>(Tokens.LongCountAsync());
/// <summary>
/// Determines the number of tokens that match the specified query.
@ -116,17 +116,17 @@ namespace OpenIddict.EntityFramework
/// <param name="query">The query to execute.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the number of tokens that match the specified query.
/// </returns>
public virtual Task<long> CountAsync<TResult>([NotNull] Func<IQueryable<TToken>, IQueryable<TResult>> query, CancellationToken cancellationToken)
public virtual ValueTask<long> CountAsync<TResult>([NotNull] Func<IQueryable<TToken>, IQueryable<TResult>> query, CancellationToken cancellationToken)
{
if (query == null)
{
throw new ArgumentNullException(nameof(query));
}
return query(Tokens).LongCountAsync();
return new ValueTask<long>(query(Tokens).LongCountAsync());
}
/// <summary>
@ -134,10 +134,8 @@ namespace OpenIddict.EntityFramework
/// </summary>
/// <param name="token">The token to create.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task CreateAsync([NotNull] TToken token, CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask CreateAsync([NotNull] TToken token, CancellationToken cancellationToken)
{
if (token == null)
{
@ -146,7 +144,7 @@ namespace OpenIddict.EntityFramework
Tokens.Add(token);
return Context.SaveChangesAsync(cancellationToken);
return new ValueTask(Context.SaveChangesAsync(cancellationToken));
}
/// <summary>
@ -154,10 +152,8 @@ namespace OpenIddict.EntityFramework
/// </summary>
/// <param name="token">The token to delete.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual async Task DeleteAsync([NotNull] TToken token, CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual async ValueTask DeleteAsync([NotNull] TToken token, CancellationToken cancellationToken)
{
if (token == null)
{
@ -187,11 +183,8 @@ namespace OpenIddict.EntityFramework
/// <param name="subject">The subject associated with the token.</param>
/// <param name="client">The client associated with the token.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the tokens corresponding to the subject/client.
/// </returns>
public virtual async Task<ImmutableArray<TToken>> FindAsync([NotNull] string subject,
/// <returns>The tokens corresponding to the subject/client.</returns>
public virtual IAsyncEnumerable<TToken> FindAsync([NotNull] string subject,
[NotNull] string client, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(subject))
@ -206,12 +199,11 @@ namespace OpenIddict.EntityFramework
var key = ConvertIdentifierFromString(client);
return ImmutableArray.CreateRange(
await (from token in Tokens.Include(token => token.Application).Include(token => token.Authorization)
where token.Application != null &&
token.Application.Id.Equals(key) &&
token.Subject == subject
select token).ToListAsync(cancellationToken));
return (from token in Tokens.Include(token => token.Application).Include(token => token.Authorization)
where token.Application != null &&
token.Application.Id.Equals(key) &&
token.Subject == subject
select token).AsAsyncEnumerable(cancellationToken);
}
/// <summary>
@ -221,11 +213,8 @@ namespace OpenIddict.EntityFramework
/// <param name="client">The client associated with the token.</param>
/// <param name="status">The token status.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the tokens corresponding to the criteria.
/// </returns>
public virtual async Task<ImmutableArray<TToken>> FindAsync(
/// <returns>The tokens corresponding to the criteria.</returns>
public virtual IAsyncEnumerable<TToken> FindAsync(
[NotNull] string subject, [NotNull] string client,
[NotNull] string status, CancellationToken cancellationToken)
{
@ -246,13 +235,12 @@ namespace OpenIddict.EntityFramework
var key = ConvertIdentifierFromString(client);
return ImmutableArray.CreateRange(
await (from token in Tokens.Include(token => token.Application).Include(token => token.Authorization)
where token.Application != null &&
token.Application.Id.Equals(key) &&
token.Subject == subject &&
token.Status == status
select token).ToListAsync(cancellationToken));
return (from token in Tokens.Include(token => token.Application).Include(token => token.Authorization)
where token.Application != null &&
token.Application.Id.Equals(key) &&
token.Subject == subject &&
token.Status == status
select token).AsAsyncEnumerable(cancellationToken);
}
/// <summary>
@ -263,11 +251,8 @@ namespace OpenIddict.EntityFramework
/// <param name="status">The token status.</param>
/// <param name="type">The token type.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the tokens corresponding to the criteria.
/// </returns>
public virtual async Task<ImmutableArray<TToken>> FindAsync(
/// <returns>The tokens corresponding to the criteria.</returns>
public virtual IAsyncEnumerable<TToken> FindAsync(
[NotNull] string subject, [NotNull] string client,
[NotNull] string status, [NotNull] string type, CancellationToken cancellationToken)
{
@ -293,14 +278,13 @@ namespace OpenIddict.EntityFramework
var key = ConvertIdentifierFromString(client);
return ImmutableArray.CreateRange(
await (from token in Tokens.Include(token => token.Application).Include(token => token.Authorization)
where token.Application != null &&
token.Application.Id.Equals(key) &&
token.Subject == subject &&
token.Status == status &&
token.Type == type
select token).ToListAsync(cancellationToken));
return (from token in Tokens.Include(token => token.Application).Include(token => token.Authorization)
where token.Application != null &&
token.Application.Id.Equals(key) &&
token.Subject == subject &&
token.Status == status &&
token.Type == type
select token).AsAsyncEnumerable(cancellationToken);
}
/// <summary>
@ -308,11 +292,8 @@ namespace OpenIddict.EntityFramework
/// </summary>
/// <param name="identifier">The application identifier associated with the tokens.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the tokens corresponding to the specified application.
/// </returns>
public virtual async Task<ImmutableArray<TToken>> FindByApplicationIdAsync([NotNull] string identifier, CancellationToken cancellationToken)
/// <returns>The tokens corresponding to the specified application.</returns>
public virtual IAsyncEnumerable<TToken> FindByApplicationIdAsync([NotNull] string identifier, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(identifier))
{
@ -321,11 +302,10 @@ namespace OpenIddict.EntityFramework
var key = ConvertIdentifierFromString(identifier);
return ImmutableArray.CreateRange(
await (from token in Tokens.Include(token => token.Application).Include(token => token.Authorization)
where token.Application != null &&
token.Application.Id.Equals(key)
select token).ToListAsync(cancellationToken));
return (from token in Tokens.Include(token => token.Application).Include(token => token.Authorization)
where token.Application != null &&
token.Application.Id.Equals(key)
select token).AsAsyncEnumerable(cancellationToken);
}
/// <summary>
@ -333,11 +313,8 @@ namespace OpenIddict.EntityFramework
/// </summary>
/// <param name="identifier">The authorization identifier associated with the tokens.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the tokens corresponding to the specified authorization.
/// </returns>
public virtual async Task<ImmutableArray<TToken>> FindByAuthorizationIdAsync([NotNull] string identifier, CancellationToken cancellationToken)
/// <returns>Tokens corresponding to the specified authorization.</returns>
public virtual IAsyncEnumerable<TToken> FindByAuthorizationIdAsync([NotNull] string identifier, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(identifier))
{
@ -346,11 +323,10 @@ namespace OpenIddict.EntityFramework
var key = ConvertIdentifierFromString(identifier);
return ImmutableArray.CreateRange(
await (from token in Tokens.Include(token => token.Application).Include(token => token.Authorization)
where token.Authorization != null &&
token.Authorization.Id.Equals(key)
select token).ToListAsync(cancellationToken));
return (from token in Tokens.Include(token => token.Application).Include(token => token.Authorization)
where token.Authorization != null &&
token.Authorization.Id.Equals(key)
select token).AsAsyncEnumerable(cancellationToken);
}
/// <summary>
@ -359,10 +335,10 @@ namespace OpenIddict.EntityFramework
/// <param name="identifier">The unique identifier associated with the token.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the token corresponding to the unique identifier.
/// </returns>
public virtual Task<TToken> FindByIdAsync([NotNull] string identifier, CancellationToken cancellationToken)
public virtual ValueTask<TToken> FindByIdAsync([NotNull] string identifier, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(identifier))
{
@ -371,9 +347,9 @@ namespace OpenIddict.EntityFramework
var key = ConvertIdentifierFromString(identifier);
return (from token in Tokens.Include(token => token.Application).Include(token => token.Authorization)
where token.Id.Equals(key)
select token).FirstOrDefaultAsync(cancellationToken);
return new ValueTask<TToken>((from token in Tokens.Include(token => token.Application).Include(token => token.Authorization)
where token.Id.Equals(key)
select token).FirstOrDefaultAsync(cancellationToken));
}
/// <summary>
@ -383,19 +359,19 @@ namespace OpenIddict.EntityFramework
/// <param name="identifier">The reference identifier associated with the tokens.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the tokens corresponding to the specified reference identifier.
/// </returns>
public virtual Task<TToken> FindByReferenceIdAsync([NotNull] string identifier, CancellationToken cancellationToken)
public virtual ValueTask<TToken> FindByReferenceIdAsync([NotNull] string identifier, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(identifier))
{
throw new ArgumentException("The identifier cannot be null or empty.", nameof(identifier));
}
return (from token in Tokens.Include(token => token.Application).Include(token => token.Authorization)
where token.ReferenceId == identifier
select token).FirstOrDefaultAsync(cancellationToken);
return new ValueTask<TToken>((from token in Tokens.Include(token => token.Application).Include(token => token.Authorization)
where token.ReferenceId == identifier
select token).FirstOrDefaultAsync(cancellationToken));
}
/// <summary>
@ -403,21 +379,17 @@ namespace OpenIddict.EntityFramework
/// </summary>
/// <param name="subject">The subject associated with the tokens.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the tokens corresponding to the specified subject.
/// </returns>
public virtual async Task<ImmutableArray<TToken>> FindBySubjectAsync([NotNull] string subject, CancellationToken cancellationToken)
/// <returns>The tokens corresponding to the specified subject.</returns>
public virtual IAsyncEnumerable<TToken> FindBySubjectAsync([NotNull] string subject, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(subject))
{
throw new ArgumentException("The subject cannot be null or empty.", nameof(subject));
}
return ImmutableArray.CreateRange(
await (from token in Tokens.Include(token => token.Application).Include(token => token.Authorization)
where token.Subject == subject
select token).ToListAsync(cancellationToken));
return (from token in Tokens.Include(token => token.Application).Include(token => token.Authorization)
where token.Subject == subject
select token).AsAsyncEnumerable(cancellationToken);
}
/// <summary>
@ -465,10 +437,10 @@ namespace OpenIddict.EntityFramework
/// <param name="state">The optional state.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the first element returned when executing the query.
/// </returns>
public virtual Task<TResult> GetAsync<TState, TResult>(
public virtual ValueTask<TResult> GetAsync<TState, TResult>(
[NotNull] Func<IQueryable<TToken>, TState, IQueryable<TResult>> query,
[CanBeNull] TState state, CancellationToken cancellationToken)
{
@ -477,9 +449,9 @@ namespace OpenIddict.EntityFramework
throw new ArgumentNullException(nameof(query));
}
return query(
return new ValueTask<TResult>(query(
Tokens.Include(token => token.Application)
.Include(token => token.Authorization), state).FirstOrDefaultAsync(cancellationToken);
.Include(token => token.Authorization), state).FirstOrDefaultAsync(cancellationToken));
}
/// <summary>
@ -739,11 +711,8 @@ namespace OpenIddict.EntityFramework
/// <param name="count">The number of results to return.</param>
/// <param name="offset">The number of results to skip.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the elements returned when executing the specified query.
/// </returns>
public virtual async Task<ImmutableArray<TToken>> ListAsync(
/// <returns>All the elements returned when executing the specified query.</returns>
public virtual IAsyncEnumerable<TToken> ListAsync(
[CanBeNull] int? count, [CanBeNull] int? offset, CancellationToken cancellationToken)
{
var query = Tokens.Include(token => token.Application)
@ -761,7 +730,7 @@ namespace OpenIddict.EntityFramework
query = query.Take(count.Value);
}
return ImmutableArray.CreateRange(await query.ToListAsync(cancellationToken));
return query.AsAsyncEnumerable(cancellationToken);
}
/// <summary>
@ -772,11 +741,8 @@ namespace OpenIddict.EntityFramework
/// <param name="query">The query to execute.</param>
/// <param name="state">The optional state.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the elements returned when executing the specified query.
/// </returns>
public virtual async Task<ImmutableArray<TResult>> ListAsync<TState, TResult>(
/// <returns>All the elements returned when executing the specified query.</returns>
public virtual IAsyncEnumerable<TResult> ListAsync<TState, TResult>(
[NotNull] Func<IQueryable<TToken>, TState, IQueryable<TResult>> query,
[CanBeNull] TState state, CancellationToken cancellationToken)
{
@ -785,19 +751,17 @@ namespace OpenIddict.EntityFramework
throw new ArgumentNullException(nameof(query));
}
return ImmutableArray.CreateRange(await query(
return query(
Tokens.Include(token => token.Application)
.Include(token => token.Authorization), state).ToListAsync(cancellationToken));
.Include(token => token.Authorization), state).AsAsyncEnumerable(cancellationToken);
}
/// <summary>
/// Removes the tokens that are marked as expired or invalid.
/// </summary>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual async Task PruneAsync(CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual async ValueTask PruneAsync(CancellationToken cancellationToken)
{
// Note: Entity Framework 6.x doesn't support set-based deletes, which prevents removing
// entities in a single command without having to retrieve and materialize them first.
@ -823,7 +787,7 @@ namespace OpenIddict.EntityFramework
// Note: to avoid sending too many queries, the maximum number of elements
// that can be removed by a single call to PruneAsync() is limited to 50000.
for (var offset = 0; offset < 50_000; offset = offset + 1_000)
for (var offset = 0; offset < 50_000; offset += 1_000)
{
cancellationToken.ThrowIfCancellationRequested();
@ -831,37 +795,35 @@ namespace OpenIddict.EntityFramework
// after it was retrieved from the database, the following logic is executed in
// a repeatable read transaction, that will put a lock on the retrieved entries
// and thus prevent them from being concurrently modified outside this block.
using (var transaction = CreateTransaction())
using var transaction = CreateTransaction();
var tokens = await (from token in Tokens
where token.Status != OpenIddictConstants.Statuses.Valid ||
token.ExpirationDate < DateTimeOffset.UtcNow
orderby token.Id
select token).Skip(offset).Take(1_000).ToListAsync(cancellationToken);
if (tokens.Count == 0)
{
var tokens =
await (from token in Tokens
where token.Status != OpenIddictConstants.Statuses.Valid ||
token.ExpirationDate < DateTimeOffset.UtcNow
orderby token.Id
select token).Skip(offset).Take(1_000).ToListAsync(cancellationToken);
if (tokens.Count == 0)
{
break;
}
break;
}
Tokens.RemoveRange(tokens);
Tokens.RemoveRange(tokens);
try
{
await Context.SaveChangesAsync(cancellationToken);
transaction?.Commit();
}
try
{
await Context.SaveChangesAsync(cancellationToken);
transaction?.Commit();
}
catch (Exception exception)
catch (Exception exception)
{
if (exceptions == null)
{
if (exceptions == null)
{
exceptions = new List<Exception>(capacity: 1);
}
exceptions.Add(exception);
exceptions = new List<Exception>(capacity: 1);
}
exceptions.Add(exception);
}
}
@ -877,10 +839,8 @@ namespace OpenIddict.EntityFramework
/// <param name="token">The token.</param>
/// <param name="identifier">The unique identifier associated with the client application.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual async Task SetApplicationIdAsync([NotNull] TToken token,
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual async ValueTask SetApplicationIdAsync([NotNull] TToken token,
[CanBeNull] string identifier, CancellationToken cancellationToken)
{
if (token == null)
@ -923,10 +883,8 @@ namespace OpenIddict.EntityFramework
/// <param name="token">The token.</param>
/// <param name="identifier">The unique identifier associated with the authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual async Task SetAuthorizationIdAsync([NotNull] TToken token,
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual async ValueTask SetAuthorizationIdAsync([NotNull] TToken token,
[CanBeNull] string identifier, CancellationToken cancellationToken)
{
if (token == null)
@ -969,10 +927,8 @@ namespace OpenIddict.EntityFramework
/// <param name="token">The token.</param>
/// <param name="date">The creation date.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetCreationDateAsync([NotNull] TToken token,
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetCreationDateAsync([NotNull] TToken token,
[CanBeNull] DateTimeOffset? date, CancellationToken cancellationToken)
{
if (token == null)
@ -982,7 +938,7 @@ namespace OpenIddict.EntityFramework
token.CreationDate = date;
return Task.CompletedTask;
return default;
}
/// <summary>
@ -991,10 +947,8 @@ namespace OpenIddict.EntityFramework
/// <param name="token">The token.</param>
/// <param name="date">The expiration date.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetExpirationDateAsync([NotNull] TToken token,
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetExpirationDateAsync([NotNull] TToken token,
[CanBeNull] DateTimeOffset? date, CancellationToken cancellationToken)
{
if (token == null)
@ -1004,7 +958,7 @@ namespace OpenIddict.EntityFramework
token.ExpirationDate = date;
return Task.CompletedTask;
return default;
}
/// <summary>
@ -1013,10 +967,8 @@ namespace OpenIddict.EntityFramework
/// <param name="token">The token.</param>
/// <param name="payload">The payload associated with the token.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetPayloadAsync([NotNull] TToken token, [CanBeNull] string payload, CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetPayloadAsync([NotNull] TToken token, [CanBeNull] string payload, CancellationToken cancellationToken)
{
if (token == null)
{
@ -1025,7 +977,7 @@ namespace OpenIddict.EntityFramework
token.Payload = payload;
return Task.CompletedTask;
return default;
}
/// <summary>
@ -1034,10 +986,8 @@ namespace OpenIddict.EntityFramework
/// <param name="token">The token.</param>
/// <param name="properties">The additional properties associated with the token.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetPropertiesAsync([NotNull] TToken token, [CanBeNull] JObject properties, CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetPropertiesAsync([NotNull] TToken token, [CanBeNull] JObject properties, CancellationToken cancellationToken)
{
if (token == null)
{
@ -1048,12 +998,12 @@ namespace OpenIddict.EntityFramework
{
token.Properties = null;
return Task.CompletedTask;
return default;
}
token.Properties = properties.ToString(Formatting.None);
return Task.CompletedTask;
return default;
}
/// <summary>
@ -1064,10 +1014,8 @@ namespace OpenIddict.EntityFramework
/// <param name="token">The token.</param>
/// <param name="identifier">The reference identifier associated with the token.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetReferenceIdAsync([NotNull] TToken token, [CanBeNull] string identifier, CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetReferenceIdAsync([NotNull] TToken token, [CanBeNull] string identifier, CancellationToken cancellationToken)
{
if (token == null)
{
@ -1076,7 +1024,7 @@ namespace OpenIddict.EntityFramework
token.ReferenceId = identifier;
return Task.CompletedTask;
return default;
}
/// <summary>
@ -1085,10 +1033,8 @@ namespace OpenIddict.EntityFramework
/// <param name="token">The token.</param>
/// <param name="status">The status associated with the authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetStatusAsync([NotNull] TToken token, [CanBeNull] string status, CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetStatusAsync([NotNull] TToken token, [CanBeNull] string status, CancellationToken cancellationToken)
{
if (token == null)
{
@ -1097,7 +1043,7 @@ namespace OpenIddict.EntityFramework
token.Status = status;
return Task.CompletedTask;
return default;
}
/// <summary>
@ -1106,10 +1052,8 @@ namespace OpenIddict.EntityFramework
/// <param name="token">The token.</param>
/// <param name="subject">The subject associated with the token.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetSubjectAsync([NotNull] TToken token, [CanBeNull] string subject, CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetSubjectAsync([NotNull] TToken token, [CanBeNull] string subject, CancellationToken cancellationToken)
{
if (token == null)
{
@ -1118,7 +1062,7 @@ namespace OpenIddict.EntityFramework
token.Subject = subject;
return Task.CompletedTask;
return default;
}
/// <summary>
@ -1127,10 +1071,8 @@ namespace OpenIddict.EntityFramework
/// <param name="token">The token.</param>
/// <param name="type">The token type associated with the token.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetTypeAsync([NotNull] TToken token, [CanBeNull] string type, CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetTypeAsync([NotNull] TToken token, [CanBeNull] string type, CancellationToken cancellationToken)
{
if (token == null)
{
@ -1139,7 +1081,7 @@ namespace OpenIddict.EntityFramework
token.Type = type;
return Task.CompletedTask;
return default;
}
/// <summary>
@ -1147,10 +1089,8 @@ namespace OpenIddict.EntityFramework
/// </summary>
/// <param name="token">The token to update.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual async Task UpdateAsync([NotNull] TToken token, CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual async ValueTask UpdateAsync([NotNull] TToken token, CancellationToken cancellationToken)
{
if (token == null)
{

2
src/OpenIddict.EntityFrameworkCore/OpenIddictEntityFrameworkCoreHelpers.cs

@ -13,7 +13,7 @@ using OpenIddict.EntityFrameworkCore.Models;
namespace Microsoft.EntityFrameworkCore
{
/// <summary>
/// Exposes extensions allowing to register the OpenIddict Entity Framework Core entity sets.
/// Exposes extensions simplifying the integration between OpenIddict and Entity Framework Core.
/// </summary>
public static class OpenIddictEntityFrameworkCoreHelpers
{

263
src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictApplicationStore.cs

@ -124,11 +124,11 @@ namespace OpenIddict.EntityFrameworkCore
/// </summary>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the number of applications in the database.
/// </returns>
public virtual Task<long> CountAsync(CancellationToken cancellationToken)
=> Applications.LongCountAsync();
public virtual ValueTask<long> CountAsync(CancellationToken cancellationToken)
=> new ValueTask<long>(Applications.AsQueryable().LongCountAsync());
/// <summary>
/// Determines the number of applications that match the specified query.
@ -137,17 +137,17 @@ namespace OpenIddict.EntityFrameworkCore
/// <param name="query">The query to execute.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the number of applications that match the specified query.
/// </returns>
public virtual Task<long> CountAsync<TResult>([NotNull] Func<IQueryable<TApplication>, IQueryable<TResult>> query, CancellationToken cancellationToken)
public virtual ValueTask<long> CountAsync<TResult>([NotNull] Func<IQueryable<TApplication>, IQueryable<TResult>> query, CancellationToken cancellationToken)
{
if (query == null)
{
throw new ArgumentNullException(nameof(query));
}
return query(Applications).LongCountAsync();
return new ValueTask<long>(query(Applications).LongCountAsync());
}
/// <summary>
@ -155,10 +155,8 @@ namespace OpenIddict.EntityFrameworkCore
/// </summary>
/// <param name="application">The application to create.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task CreateAsync([NotNull] TApplication application, CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask CreateAsync([NotNull] TApplication application, CancellationToken cancellationToken)
{
if (application == null)
{
@ -167,7 +165,7 @@ namespace OpenIddict.EntityFrameworkCore
Context.Add(application);
return Context.SaveChangesAsync(cancellationToken);
return new ValueTask(Context.SaveChangesAsync(cancellationToken));
}
/// <summary>
@ -175,17 +173,15 @@ namespace OpenIddict.EntityFrameworkCore
/// </summary>
/// <param name="application">The application to delete.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual async Task DeleteAsync([NotNull] TApplication application, CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual async ValueTask DeleteAsync([NotNull] TApplication application, CancellationToken cancellationToken)
{
if (application == null)
{
throw new ArgumentNullException(nameof(application));
}
async Task<IDbContextTransaction> CreateTransactionAsync()
async ValueTask<IDbContextTransaction> CreateTransactionAsync()
{
// Note: transactions that specify an explicit isolation level are only supported by
// relational providers and trying to use them with a different provider results in
@ -234,41 +230,40 @@ namespace OpenIddict.EntityFrameworkCore
// To prevent an SQL exception from being thrown if a new associated entity is
// created after the existing entries have been listed, the following logic is
// executed in a serializable transaction, that will lock the affected tables.
using (var transaction = await CreateTransactionAsync())
{
// Remove all the authorizations associated with the application and
// the tokens attached to these implicit or explicit authorizations.
foreach (var authorization in await ListAuthorizationsAsync())
{
foreach (var token in authorization.Tokens)
{
Context.Remove(token);
}
Context.Remove(authorization);
}
using var transaction = await CreateTransactionAsync();
// Remove all the tokens associated with the application.
foreach (var token in await ListTokensAsync())
// Remove all the authorizations associated with the application and
// the tokens attached to these implicit or explicit authorizations.
foreach (var authorization in await ListAuthorizationsAsync())
{
foreach (var token in authorization.Tokens)
{
Context.Remove(token);
}
Context.Remove(application);
Context.Remove(authorization);
}
try
{
await Context.SaveChangesAsync(cancellationToken);
transaction?.Commit();
}
// Remove all the tokens associated with the application.
foreach (var token in await ListTokensAsync())
{
Context.Remove(token);
}
catch (DbUpdateConcurrencyException exception)
{
throw new OpenIddictExceptions.ConcurrencyException(new StringBuilder()
.AppendLine("The application was concurrently updated and cannot be persisted in its current state.")
.Append("Reload the application from the database and retry the operation.")
.ToString(), exception);
}
Context.Remove(application);
try
{
await Context.SaveChangesAsync(cancellationToken);
transaction?.Commit();
}
catch (DbUpdateConcurrencyException exception)
{
throw new OpenIddictExceptions.ConcurrencyException(new StringBuilder()
.AppendLine("The application was concurrently updated and cannot be persisted in its current state.")
.Append("Reload the application from the database and retry the operation.")
.ToString(), exception);
}
}
@ -287,17 +282,17 @@ namespace OpenIddict.EntityFrameworkCore
/// <param name="identifier">The client identifier associated with the application.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the client application corresponding to the identifier.
/// </returns>
public virtual Task<TApplication> FindByClientIdAsync([NotNull] string identifier, CancellationToken cancellationToken)
public virtual ValueTask<TApplication> FindByClientIdAsync([NotNull] string identifier, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(identifier))
{
throw new ArgumentException("The identifier cannot be null or empty.", nameof(identifier));
}
return FindByClientId(Context, identifier);
return new ValueTask<TApplication>(FindByClientId(Context, identifier));
}
/// <summary>
@ -315,17 +310,17 @@ namespace OpenIddict.EntityFrameworkCore
/// <param name="identifier">The unique identifier associated with the application.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the client application corresponding to the identifier.
/// </returns>
public virtual Task<TApplication> FindByIdAsync([NotNull] string identifier, CancellationToken cancellationToken)
public virtual ValueTask<TApplication> FindByIdAsync([NotNull] string identifier, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(identifier))
{
throw new ArgumentException("The identifier cannot be null or empty.", nameof(identifier));
}
return FindById(Context, ConvertIdentifierFromString(identifier));
return new ValueTask<TApplication>(FindById(Context, ConvertIdentifierFromString(identifier)));
}
/// <summary>
@ -348,11 +343,8 @@ namespace OpenIddict.EntityFrameworkCore
/// </summary>
/// <param name="address">The post_logout_redirect_uri associated with the applications.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation, whose result
/// returns the client applications corresponding to the specified post_logout_redirect_uri.
/// </returns>
public virtual async Task<ImmutableArray<TApplication>> FindByPostLogoutRedirectUriAsync(
/// <returns>The client applications corresponding to the specified post_logout_redirect_uri.</returns>
public virtual IAsyncEnumerable<TApplication> FindByPostLogoutRedirectUriAsync(
[NotNull] string address, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(address))
@ -360,24 +352,9 @@ namespace OpenIddict.EntityFrameworkCore
throw new ArgumentException("The address cannot be null or empty.", nameof(address));
}
var builder = ImmutableArray.CreateBuilder<TApplication>();
await foreach (var application in FindByPostLogoutRedirectUri(Context, address))
{
foreach (var uri in await GetPostLogoutRedirectUrisAsync(application, cancellationToken))
{
// Note: the post_logout_redirect_uri must be compared
// using case-sensitive "Simple String Comparison".
if (string.Equals(uri, address, StringComparison.Ordinal))
{
builder.Add(application);
break;
}
}
}
return builder.ToImmutable();
return FindByPostLogoutRedirectUri(Context, address)
.WhereAwait(async application => (await GetPostLogoutRedirectUrisAsync(application, cancellationToken))
.Contains(address, StringComparer.Ordinal));
}
/// <summary>
@ -400,11 +377,8 @@ namespace OpenIddict.EntityFrameworkCore
/// </summary>
/// <param name="address">The redirect_uri associated with the applications.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation, whose result
/// returns the client applications corresponding to the specified redirect_uri.
/// </returns>
public virtual async Task<ImmutableArray<TApplication>> FindByRedirectUriAsync(
/// <returns>The client applications corresponding to the specified redirect_uri.</returns>
public virtual IAsyncEnumerable<TApplication> FindByRedirectUriAsync(
[NotNull] string address, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(address))
@ -412,24 +386,9 @@ namespace OpenIddict.EntityFrameworkCore
throw new ArgumentException("The address cannot be null or empty.", nameof(address));
}
var builder = ImmutableArray.CreateBuilder<TApplication>();
await foreach (var application in FindByRedirectUri(Context, address))
{
foreach (var uri in await GetRedirectUrisAsync(application, cancellationToken))
{
// Note: the redirect_uri must be compared using case-sensitive "Simple String Comparison".
// See http://openid.net/specs/openid-connect-core-1_0.html#AuthRequest for more information.
if (string.Equals(uri, address, StringComparison.Ordinal))
{
builder.Add(application);
break;
}
}
}
return builder.ToImmutable();
return FindByRedirectUri(Context, address)
.WhereAwait(async application => (await GetRedirectUrisAsync(application, cancellationToken))
.Contains(address, StringComparer.Ordinal));
}
/// <summary>
@ -441,10 +400,10 @@ namespace OpenIddict.EntityFrameworkCore
/// <param name="state">The optional state.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the first element returned when executing the query.
/// </returns>
public virtual Task<TResult> GetAsync<TState, TResult>(
public virtual ValueTask<TResult> GetAsync<TState, TResult>(
[NotNull] Func<IQueryable<TApplication>, TState, IQueryable<TResult>> query,
[CanBeNull] TState state, CancellationToken cancellationToken)
{
@ -453,7 +412,7 @@ namespace OpenIddict.EntityFrameworkCore
throw new ArgumentNullException(nameof(query));
}
return query(Applications.AsTracking(), state).FirstOrDefaultAsync(cancellationToken);
return new ValueTask<TResult>(query(Applications.AsTracking(), state).FirstOrDefaultAsync(cancellationToken));
}
/// <summary>
@ -750,14 +709,11 @@ namespace OpenIddict.EntityFrameworkCore
/// <param name="count">The number of results to return.</param>
/// <param name="offset">The number of results to skip.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the elements returned when executing the specified query.
/// </returns>
public virtual async Task<ImmutableArray<TApplication>> ListAsync(
/// <returns>All the elements returned when executing the specified query.</returns>
public virtual IAsyncEnumerable<TApplication> ListAsync(
[CanBeNull] int? count, [CanBeNull] int? offset, CancellationToken cancellationToken)
{
var query = Applications.OrderBy(application => application.Id).AsTracking();
var query = Applications.AsQueryable().OrderBy(application => application.Id).AsTracking();
if (offset.HasValue)
{
@ -769,7 +725,7 @@ namespace OpenIddict.EntityFrameworkCore
query = query.Take(count.Value);
}
return ImmutableArray.CreateRange(await query.ToListAsync(cancellationToken));
return query.AsAsyncEnumerable();
}
/// <summary>
@ -780,11 +736,8 @@ namespace OpenIddict.EntityFrameworkCore
/// <param name="query">The query to execute.</param>
/// <param name="state">The optional state.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the elements returned when executing the specified query.
/// </returns>
public virtual async Task<ImmutableArray<TResult>> ListAsync<TState, TResult>(
/// <returns>All the elements returned when executing the specified query.</returns>
public virtual IAsyncEnumerable<TResult> ListAsync<TState, TResult>(
[NotNull] Func<IQueryable<TApplication>, TState, IQueryable<TResult>> query,
[CanBeNull] TState state, CancellationToken cancellationToken)
{
@ -793,7 +746,7 @@ namespace OpenIddict.EntityFrameworkCore
throw new ArgumentNullException(nameof(query));
}
return ImmutableArray.CreateRange(await query(Applications.AsTracking(), state).ToListAsync(cancellationToken));
return query(Applications.AsTracking(), state).AsAsyncEnumerable();
}
/// <summary>
@ -802,10 +755,8 @@ namespace OpenIddict.EntityFrameworkCore
/// <param name="application">The application.</param>
/// <param name="identifier">The client identifier associated with the application.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetClientIdAsync([NotNull] TApplication application,
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetClientIdAsync([NotNull] TApplication application,
[CanBeNull] string identifier, CancellationToken cancellationToken)
{
if (application == null)
@ -815,7 +766,7 @@ namespace OpenIddict.EntityFrameworkCore
application.ClientId = identifier;
return Task.CompletedTask;
return default;
}
/// <summary>
@ -826,10 +777,8 @@ namespace OpenIddict.EntityFrameworkCore
/// <param name="application">The application.</param>
/// <param name="secret">The client secret associated with the application.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetClientSecretAsync([NotNull] TApplication application,
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetClientSecretAsync([NotNull] TApplication application,
[CanBeNull] string secret, CancellationToken cancellationToken)
{
if (application == null)
@ -839,7 +788,7 @@ namespace OpenIddict.EntityFrameworkCore
application.ClientSecret = secret;
return Task.CompletedTask;
return default;
}
/// <summary>
@ -848,10 +797,8 @@ namespace OpenIddict.EntityFrameworkCore
/// <param name="application">The application.</param>
/// <param name="type">The client type associated with the application.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetClientTypeAsync([NotNull] TApplication application,
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetClientTypeAsync([NotNull] TApplication application,
[CanBeNull] string type, CancellationToken cancellationToken)
{
if (application == null)
@ -861,7 +808,7 @@ namespace OpenIddict.EntityFrameworkCore
application.Type = type;
return Task.CompletedTask;
return default;
}
/// <summary>
@ -870,10 +817,8 @@ namespace OpenIddict.EntityFrameworkCore
/// <param name="application">The application.</param>
/// <param name="type">The consent type associated with the application.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetConsentTypeAsync([NotNull] TApplication application,
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetConsentTypeAsync([NotNull] TApplication application,
[CanBeNull] string type, CancellationToken cancellationToken)
{
if (application == null)
@ -883,7 +828,7 @@ namespace OpenIddict.EntityFrameworkCore
application.ConsentType = type;
return Task.CompletedTask;
return default;
}
/// <summary>
@ -892,10 +837,8 @@ namespace OpenIddict.EntityFrameworkCore
/// <param name="application">The application.</param>
/// <param name="name">The display name associated with the application.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetDisplayNameAsync([NotNull] TApplication application,
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetDisplayNameAsync([NotNull] TApplication application,
[CanBeNull] string name, CancellationToken cancellationToken)
{
if (application == null)
@ -905,7 +848,7 @@ namespace OpenIddict.EntityFrameworkCore
application.DisplayName = name;
return Task.CompletedTask;
return default;
}
/// <summary>
@ -914,10 +857,8 @@ namespace OpenIddict.EntityFrameworkCore
/// <param name="application">The application.</param>
/// <param name="permissions">The permissions associated with the application </param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetPermissionsAsync([NotNull] TApplication application, ImmutableArray<string> permissions, CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetPermissionsAsync([NotNull] TApplication application, ImmutableArray<string> permissions, CancellationToken cancellationToken)
{
if (application == null)
{
@ -928,12 +869,12 @@ namespace OpenIddict.EntityFrameworkCore
{
application.Permissions = null;
return Task.CompletedTask;
return default;
}
application.Permissions = new JArray(permissions.ToArray()).ToString(Formatting.None);
return Task.CompletedTask;
return default;
}
/// <summary>
@ -942,10 +883,8 @@ namespace OpenIddict.EntityFrameworkCore
/// <param name="application">The application.</param>
/// <param name="addresses">The logout callback addresses associated with the application </param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetPostLogoutRedirectUrisAsync([NotNull] TApplication application,
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetPostLogoutRedirectUrisAsync([NotNull] TApplication application,
ImmutableArray<string> addresses, CancellationToken cancellationToken)
{
if (application == null)
@ -957,12 +896,12 @@ namespace OpenIddict.EntityFrameworkCore
{
application.PostLogoutRedirectUris = null;
return Task.CompletedTask;
return default;
}
application.PostLogoutRedirectUris = new JArray(addresses.ToArray()).ToString(Formatting.None);
return Task.CompletedTask;
return default;
}
/// <summary>
@ -971,10 +910,8 @@ namespace OpenIddict.EntityFrameworkCore
/// <param name="application">The application.</param>
/// <param name="properties">The additional properties associated with the application.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetPropertiesAsync([NotNull] TApplication application, [CanBeNull] JObject properties, CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetPropertiesAsync([NotNull] TApplication application, [CanBeNull] JObject properties, CancellationToken cancellationToken)
{
if (application == null)
{
@ -985,12 +922,12 @@ namespace OpenIddict.EntityFrameworkCore
{
application.Properties = null;
return Task.CompletedTask;
return default;
}
application.Properties = properties.ToString(Formatting.None);
return Task.CompletedTask;
return default;
}
/// <summary>
@ -999,10 +936,8 @@ namespace OpenIddict.EntityFrameworkCore
/// <param name="application">The application.</param>
/// <param name="addresses">The callback addresses associated with the application </param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetRedirectUrisAsync([NotNull] TApplication application,
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetRedirectUrisAsync([NotNull] TApplication application,
ImmutableArray<string> addresses, CancellationToken cancellationToken)
{
if (application == null)
@ -1014,12 +949,12 @@ namespace OpenIddict.EntityFrameworkCore
{
application.RedirectUris = null;
return Task.CompletedTask;
return default;
}
application.RedirectUris = new JArray(addresses.ToArray()).ToString(Formatting.None);
return Task.CompletedTask;
return default;
}
/// <summary>
@ -1027,10 +962,8 @@ namespace OpenIddict.EntityFrameworkCore
/// </summary>
/// <param name="application">The application to update.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual async Task UpdateAsync([NotNull] TApplication application, CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual async ValueTask UpdateAsync([NotNull] TApplication application, CancellationToken cancellationToken)
{
if (application == null)
{

353
src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictAuthorizationStore.cs

@ -124,11 +124,11 @@ namespace OpenIddict.EntityFrameworkCore
/// </summary>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the number of authorizations in the database.
/// </returns>
public virtual Task<long> CountAsync(CancellationToken cancellationToken)
=> Authorizations.LongCountAsync();
public virtual ValueTask<long> CountAsync(CancellationToken cancellationToken)
=> new ValueTask<long>(Authorizations.AsQueryable().LongCountAsync());
/// <summary>
/// Determines the number of authorizations that match the specified query.
@ -137,17 +137,17 @@ namespace OpenIddict.EntityFrameworkCore
/// <param name="query">The query to execute.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the number of authorizations that match the specified query.
/// </returns>
public virtual Task<long> CountAsync<TResult>([NotNull] Func<IQueryable<TAuthorization>, IQueryable<TResult>> query, CancellationToken cancellationToken)
public virtual ValueTask<long> CountAsync<TResult>([NotNull] Func<IQueryable<TAuthorization>, IQueryable<TResult>> query, CancellationToken cancellationToken)
{
if (query == null)
{
throw new ArgumentNullException(nameof(query));
}
return query(Authorizations).LongCountAsync();
return new ValueTask<long>(query(Authorizations).LongCountAsync());
}
/// <summary>
@ -155,10 +155,8 @@ namespace OpenIddict.EntityFrameworkCore
/// </summary>
/// <param name="authorization">The authorization to create.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task CreateAsync([NotNull] TAuthorization authorization, CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask CreateAsync([NotNull] TAuthorization authorization, CancellationToken cancellationToken)
{
if (authorization == null)
{
@ -167,7 +165,7 @@ namespace OpenIddict.EntityFrameworkCore
Context.Add(authorization);
return Context.SaveChangesAsync(cancellationToken);
return new ValueTask(Context.SaveChangesAsync(cancellationToken));
}
/// <summary>
@ -175,17 +173,15 @@ namespace OpenIddict.EntityFrameworkCore
/// </summary>
/// <param name="authorization">The authorization to delete.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual async Task DeleteAsync([NotNull] TAuthorization authorization, CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual async ValueTask DeleteAsync([NotNull] TAuthorization authorization, CancellationToken cancellationToken)
{
if (authorization == null)
{
throw new ArgumentNullException(nameof(authorization));
}
async Task<IDbContextTransaction> CreateTransactionAsync()
async ValueTask<IDbContextTransaction> CreateTransactionAsync()
{
// Note: transactions that specify an explicit isolation level are only supported by
// relational providers and trying to use them with a different provider results in
@ -222,29 +218,28 @@ namespace OpenIddict.EntityFrameworkCore
// To prevent an SQL exception from being thrown if a new associated entity is
// created after the existing entries have been listed, the following logic is
// executed in a serializable transaction, that will lock the affected tables.
using (var transaction = await CreateTransactionAsync())
using var transaction = await CreateTransactionAsync();
// Remove all the tokens associated with the authorization.
foreach (var token in await ListTokensAsync())
{
// Remove all the tokens associated with the authorization.
foreach (var token in await ListTokensAsync())
{
Context.Remove(token);
}
Context.Remove(token);
}
Context.Remove(authorization);
Context.Remove(authorization);
try
{
await Context.SaveChangesAsync(cancellationToken);
transaction?.Commit();
}
try
{
await Context.SaveChangesAsync(cancellationToken);
transaction?.Commit();
}
catch (DbUpdateConcurrencyException exception)
{
throw new OpenIddictExceptions.ConcurrencyException(new StringBuilder()
.AppendLine("The authorization was concurrently updated and cannot be persisted in its current state.")
.Append("Reload the authorization from the database and retry the operation.")
.ToString(), exception);
}
catch (DbUpdateConcurrencyException exception)
{
throw new OpenIddictExceptions.ConcurrencyException(new StringBuilder()
.AppendLine("The authorization was concurrently updated and cannot be persisted in its current state.")
.Append("Reload the authorization from the database and retry the operation.")
.ToString(), exception);
}
}
@ -273,11 +268,8 @@ namespace OpenIddict.EntityFrameworkCore
/// <param name="subject">The subject associated with the authorization.</param>
/// <param name="client">The client associated with the authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the authorizations corresponding to the subject/client.
/// </returns>
public virtual async Task<ImmutableArray<TAuthorization>> FindAsync(
/// <returns>The authorizations corresponding to the subject/client.</returns>
public virtual IAsyncEnumerable<TAuthorization> FindAsync(
[NotNull] string subject, [NotNull] string client, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(subject))
@ -290,15 +282,7 @@ namespace OpenIddict.EntityFrameworkCore
throw new ArgumentException("The client cannot be null or empty.", nameof(client));
}
var builder = ImmutableArray.CreateBuilder<TAuthorization>();
await foreach (var authorization in FindBySubjectAndClient(Context,
ConvertIdentifierFromString(client), subject))
{
builder.Add(authorization);
}
return builder.ToImmutable();
return FindBySubjectAndClient(Context, ConvertIdentifierFromString(client), subject);
}
/// <summary>
@ -325,11 +309,8 @@ namespace OpenIddict.EntityFrameworkCore
/// <param name="client">The client associated with the authorization.</param>
/// <param name="status">The authorization status.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the authorizations corresponding to the criteria.
/// </returns>
public virtual async Task<ImmutableArray<TAuthorization>> FindAsync(
/// <returns>The authorizations corresponding to the criteria.</returns>
public virtual IAsyncEnumerable<TAuthorization> FindAsync(
[NotNull] string subject, [NotNull] string client,
[NotNull] string status, CancellationToken cancellationToken)
{
@ -348,15 +329,7 @@ namespace OpenIddict.EntityFrameworkCore
throw new ArgumentException("The status cannot be null or empty.", nameof(status));
}
var builder = ImmutableArray.CreateBuilder<TAuthorization>();
await foreach (var authorization in FindBySubjectClientAndStatus(Context,
ConvertIdentifierFromString(client), subject, status))
{
builder.Add(authorization);
}
return builder.ToImmutable();
return FindBySubjectClientAndStatus(Context, ConvertIdentifierFromString(client), subject, status);
}
/// <summary>
@ -386,11 +359,8 @@ namespace OpenIddict.EntityFrameworkCore
/// <param name="status">The authorization status.</param>
/// <param name="type">The authorization type.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the authorizations corresponding to the criteria.
/// </returns>
public virtual async Task<ImmutableArray<TAuthorization>> FindAsync(
/// <returns>The authorizations corresponding to the criteria.</returns>
public virtual IAsyncEnumerable<TAuthorization> FindAsync(
[NotNull] string subject, [NotNull] string client,
[NotNull] string status, [NotNull] string type, CancellationToken cancellationToken)
{
@ -414,15 +384,7 @@ namespace OpenIddict.EntityFrameworkCore
throw new ArgumentException("The type cannot be null or empty.", nameof(type));
}
var builder = ImmutableArray.CreateBuilder<TAuthorization>();
await foreach (var authorization in FindBySubjectClientStatusAndType(Context,
ConvertIdentifierFromString(client), subject, status, type))
{
builder.Add(authorization);
}
return builder.ToImmutable();
return FindBySubjectClientStatusAndType(Context, ConvertIdentifierFromString(client), subject, status, type);
}
/// <summary>
@ -434,40 +396,14 @@ namespace OpenIddict.EntityFrameworkCore
/// <param name="type">The authorization type.</param>
/// <param name="scopes">The minimal scopes associated with the authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the authorizations corresponding to the criteria.
/// </returns>
public virtual async Task<ImmutableArray<TAuthorization>> FindAsync(
/// <returns>The authorizations corresponding to the criteria.</returns>
public virtual IAsyncEnumerable<TAuthorization> FindAsync(
[NotNull] string subject, [NotNull] string client,
[NotNull] string status, [NotNull] string type,
ImmutableArray<string> scopes, CancellationToken cancellationToken)
{
var authorizations = await FindAsync(subject, client, status, type, cancellationToken);
if (authorizations.IsEmpty)
{
return ImmutableArray.Create<TAuthorization>();
}
var builder = ImmutableArray.CreateBuilder<TAuthorization>(authorizations.Length);
foreach (var authorization in authorizations)
{
async Task<bool> HasScopesAsync()
=> (await GetScopesAsync(authorization, cancellationToken))
.ToImmutableHashSet(StringComparer.Ordinal)
.IsSupersetOf(scopes);
if (await HasScopesAsync())
{
builder.Add(authorization);
}
}
return builder.Count == builder.Capacity ?
builder.MoveToImmutable() :
builder.ToImmutable();
}
=> FindAsync(subject, client, status, type, cancellationToken)
.WhereAwait(async authorization => new HashSet<string>(
await GetScopesAsync(authorization, cancellationToken), StringComparer.Ordinal).IsSupersetOf(scopes));
/// <summary>
/// Exposes a compiled query allowing to retrieve the list of
@ -491,11 +427,8 @@ namespace OpenIddict.EntityFrameworkCore
/// </summary>
/// <param name="identifier">The application identifier associated with the authorizations.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the authorizations corresponding to the specified application.
/// </returns>
public virtual async Task<ImmutableArray<TAuthorization>> FindByApplicationIdAsync(
/// <returns>The authorizations corresponding to the specified application.</returns>
public virtual IAsyncEnumerable<TAuthorization> FindByApplicationIdAsync(
[NotNull] string identifier, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(identifier))
@ -503,15 +436,7 @@ namespace OpenIddict.EntityFrameworkCore
throw new ArgumentException("The identifier cannot be null or empty.", nameof(identifier));
}
var builder = ImmutableArray.CreateBuilder<TAuthorization>();
await foreach (var authorization in FindByApplicationId(Context,
ConvertIdentifierFromString(identifier)))
{
builder.Add(authorization);
}
return builder.ToImmutable();
return FindByApplicationId(Context, ConvertIdentifierFromString(identifier));
}
/// <summary>
@ -530,18 +455,15 @@ namespace OpenIddict.EntityFrameworkCore
/// </summary>
/// <param name="identifier">The unique identifier associated with the authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the authorization corresponding to the identifier.
/// </returns>
public virtual Task<TAuthorization> FindByIdAsync([NotNull] string identifier, CancellationToken cancellationToken)
/// <returns>The authorization corresponding to the identifier.</returns>
public virtual ValueTask<TAuthorization> FindByIdAsync([NotNull] string identifier, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(identifier))
{
throw new ArgumentException("The identifier cannot be null or empty.", nameof(identifier));
}
return FindById(Context, ConvertIdentifierFromString(identifier));
return new ValueTask<TAuthorization>(FindById(Context, ConvertIdentifierFromString(identifier)));
}
/// <summary>
@ -557,15 +479,12 @@ namespace OpenIddict.EntityFrameworkCore
select authorization);
/// <summary>
/// Retrieves .
/// Retrieves the subject associated with an authorization.
/// </summary>
/// <param name="subject">The subject associated with the authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the authorizations corresponding to the specified subject.
/// </returns>
public virtual async Task<ImmutableArray<TAuthorization>> FindBySubjectAsync(
/// <returns>The authorizations corresponding to the specified subject.</returns>
public virtual IAsyncEnumerable<TAuthorization> FindBySubjectAsync(
[NotNull] string subject, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(subject))
@ -573,14 +492,7 @@ namespace OpenIddict.EntityFrameworkCore
throw new ArgumentException("The subject cannot be null or empty.", nameof(subject));
}
var builder = ImmutableArray.CreateBuilder<TAuthorization>();
await foreach (var authorization in FindBySubject(Context, subject))
{
builder.Add(authorization);
}
return builder.ToImmutable();
return FindBySubject(Context, subject);
}
/// <summary>
@ -628,10 +540,10 @@ namespace OpenIddict.EntityFrameworkCore
/// <param name="state">The optional state.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the first element returned when executing the query.
/// </returns>
public virtual Task<TResult> GetAsync<TState, TResult>(
public virtual ValueTask<TResult> GetAsync<TState, TResult>(
[NotNull] Func<IQueryable<TAuthorization>, TState, IQueryable<TResult>> query,
[CanBeNull] TState state, CancellationToken cancellationToken)
{
@ -640,9 +552,9 @@ namespace OpenIddict.EntityFrameworkCore
throw new ArgumentNullException(nameof(query));
}
return query(
return new ValueTask<TResult>(query(
Authorizations.Include(authorization => authorization.Application)
.AsTracking(), state).FirstOrDefaultAsync(cancellationToken);
.AsTracking(), state).FirstOrDefaultAsync(cancellationToken));
}
/// <summary>
@ -825,11 +737,8 @@ namespace OpenIddict.EntityFrameworkCore
/// <param name="count">The number of results to return.</param>
/// <param name="offset">The number of results to skip.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the elements returned when executing the specified query.
/// </returns>
public virtual async Task<ImmutableArray<TAuthorization>> ListAsync(
/// <returns>All the elements returned when executing the specified query.</returns>
public virtual IAsyncEnumerable<TAuthorization> ListAsync(
[CanBeNull] int? count, [CanBeNull] int? offset, CancellationToken cancellationToken)
{
var query = Authorizations.Include(authorization => authorization.Application)
@ -846,7 +755,7 @@ namespace OpenIddict.EntityFrameworkCore
query = query.Take(count.Value);
}
return ImmutableArray.CreateRange(await query.ToListAsync(cancellationToken));
return query.AsAsyncEnumerable();
}
/// <summary>
@ -857,11 +766,8 @@ namespace OpenIddict.EntityFrameworkCore
/// <param name="query">The query to execute.</param>
/// <param name="state">The optional state.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the elements returned when executing the specified query.
/// </returns>
public virtual async Task<ImmutableArray<TResult>> ListAsync<TState, TResult>(
/// <returns>All the elements returned when executing the specified query.</returns>
public virtual IAsyncEnumerable<TResult> ListAsync<TState, TResult>(
[NotNull] Func<IQueryable<TAuthorization>, TState, IQueryable<TResult>> query,
[CanBeNull] TState state, CancellationToken cancellationToken)
{
@ -870,19 +776,17 @@ namespace OpenIddict.EntityFrameworkCore
throw new ArgumentNullException(nameof(query));
}
return ImmutableArray.CreateRange(await query(
return query(
Authorizations.Include(authorization => authorization.Application)
.AsTracking(), state).ToListAsync(cancellationToken));
.AsTracking(), state).AsAsyncEnumerable();
}
/// <summary>
/// Removes the authorizations that are marked as invalid and the ad-hoc ones that have no valid/nonexpired token attached.
/// </summary>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual async Task PruneAsync(CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual async ValueTask PruneAsync(CancellationToken cancellationToken)
{
// Note: Entity Framework Core doesn't support set-based deletes, which prevents removing
// entities in a single command without having to retrieve and materialize them first.
@ -890,7 +794,7 @@ namespace OpenIddict.EntityFrameworkCore
IList<Exception> exceptions = null;
async Task<IDbContextTransaction> CreateTransactionAsync()
async ValueTask<IDbContextTransaction> CreateTransactionAsync()
{
// Note: transactions that specify an explicit isolation level are only supported by
// relational providers and trying to use them with a different provider results in
@ -916,7 +820,7 @@ namespace OpenIddict.EntityFrameworkCore
return null;
}
for (var offset = 0; offset < 100_000; offset = offset + 1_000)
for (var offset = 0; offset < 100_000; offset += 1_000)
{
cancellationToken.ThrowIfCancellationRequested();
@ -924,44 +828,43 @@ namespace OpenIddict.EntityFrameworkCore
// after it was retrieved from the database, the following logic is executed in
// a repeatable read transaction, that will put a lock on the retrieved entries
// and thus prevent them from being concurrently modified outside this block.
using (var transaction = await CreateTransactionAsync())
using var transaction = await CreateTransactionAsync();
var authorizations =
await (from authorization in Authorizations.Include(authorization => authorization.Tokens).AsTracking()
where authorization.Status != OpenIddictConstants.Statuses.Valid ||
(authorization.Type == OpenIddictConstants.AuthorizationTypes.AdHoc &&
!authorization.Tokens.Any(token => token.Status == OpenIddictConstants.Statuses.Valid &&
token.ExpirationDate > DateTimeOffset.UtcNow))
orderby authorization.Id
select authorization).Skip(offset).Take(1_000).ToListAsync(cancellationToken);
if (authorizations.Count == 0)
{
var authorizations =
await (from authorization in Authorizations.Include(authorization => authorization.Tokens).AsTracking()
where authorization.Status != OpenIddictConstants.Statuses.Valid ||
(authorization.Type == OpenIddictConstants.AuthorizationTypes.AdHoc &&
!authorization.Tokens.Any(token => token.Status == OpenIddictConstants.Statuses.Valid &&
token.ExpirationDate > DateTimeOffset.UtcNow))
orderby authorization.Id
select authorization).Skip(offset).Take(1_000).ToListAsync(cancellationToken);
if (authorizations.Count == 0)
{
break;
}
break;
}
// Note: new tokens may be attached after the authorizations were retrieved
// from the database since the transaction level is deliberately limited to
// repeatable read instead of serializable for performance reasons). In this
// case, the operation will fail, which is considered an acceptable risk.
Context.RemoveRange(authorizations);
Context.RemoveRange(authorizations.SelectMany(authorization => authorization.Tokens));
// Note: new tokens may be attached after the authorizations were retrieved
// from the database since the transaction level is deliberately limited to
// repeatable read instead of serializable for performance reasons). In this
// case, the operation will fail, which is considered an acceptable risk.
Context.RemoveRange(authorizations);
Context.RemoveRange(authorizations.SelectMany(authorization => authorization.Tokens));
try
{
await Context.SaveChangesAsync(cancellationToken);
transaction?.Commit();
}
try
{
await Context.SaveChangesAsync(cancellationToken);
transaction?.Commit();
}
catch (Exception exception)
catch (Exception exception)
{
if (exceptions == null)
{
if (exceptions == null)
{
exceptions = new List<Exception>(capacity: 1);
}
exceptions.Add(exception);
exceptions = new List<Exception>(capacity: 1);
}
exceptions.Add(exception);
}
}
@ -977,10 +880,8 @@ namespace OpenIddict.EntityFrameworkCore
/// <param name="authorization">The authorization.</param>
/// <param name="identifier">The unique identifier associated with the client application.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual async Task SetApplicationIdAsync([NotNull] TAuthorization authorization,
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual async ValueTask SetApplicationIdAsync([NotNull] TAuthorization authorization,
[CanBeNull] string identifier, CancellationToken cancellationToken)
{
if (authorization == null)
@ -1023,10 +924,8 @@ namespace OpenIddict.EntityFrameworkCore
/// <param name="authorization">The authorization.</param>
/// <param name="properties">The additional properties associated with the authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetPropertiesAsync([NotNull] TAuthorization authorization, [CanBeNull] JObject properties, CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetPropertiesAsync([NotNull] TAuthorization authorization, [CanBeNull] JObject properties, CancellationToken cancellationToken)
{
if (authorization == null)
{
@ -1037,12 +936,12 @@ namespace OpenIddict.EntityFrameworkCore
{
authorization.Properties = null;
return Task.CompletedTask;
return default;
}
authorization.Properties = properties.ToString(Formatting.None);
return Task.CompletedTask;
return default;
}
/// <summary>
@ -1051,10 +950,8 @@ namespace OpenIddict.EntityFrameworkCore
/// <param name="authorization">The authorization.</param>
/// <param name="scopes">The scopes associated with the authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetScopesAsync([NotNull] TAuthorization authorization,
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetScopesAsync([NotNull] TAuthorization authorization,
ImmutableArray<string> scopes, CancellationToken cancellationToken)
{
if (authorization == null)
@ -1066,12 +963,12 @@ namespace OpenIddict.EntityFrameworkCore
{
authorization.Scopes = null;
return Task.CompletedTask;
return default;
}
authorization.Scopes = new JArray(scopes.ToArray()).ToString(Formatting.None);
return Task.CompletedTask;
return default;
}
/// <summary>
@ -1080,10 +977,8 @@ namespace OpenIddict.EntityFrameworkCore
/// <param name="authorization">The authorization.</param>
/// <param name="status">The status associated with the authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetStatusAsync([NotNull] TAuthorization authorization,
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetStatusAsync([NotNull] TAuthorization authorization,
[CanBeNull] string status, CancellationToken cancellationToken)
{
if (authorization == null)
@ -1093,7 +988,7 @@ namespace OpenIddict.EntityFrameworkCore
authorization.Status = status;
return Task.CompletedTask;
return default;
}
/// <summary>
@ -1102,10 +997,8 @@ namespace OpenIddict.EntityFrameworkCore
/// <param name="authorization">The authorization.</param>
/// <param name="subject">The subject associated with the authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetSubjectAsync([NotNull] TAuthorization authorization,
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetSubjectAsync([NotNull] TAuthorization authorization,
[CanBeNull] string subject, CancellationToken cancellationToken)
{
if (authorization == null)
@ -1115,7 +1008,7 @@ namespace OpenIddict.EntityFrameworkCore
authorization.Subject = subject;
return Task.CompletedTask;
return default;
}
/// <summary>
@ -1124,10 +1017,8 @@ namespace OpenIddict.EntityFrameworkCore
/// <param name="authorization">The authorization.</param>
/// <param name="type">The type associated with the authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetTypeAsync([NotNull] TAuthorization authorization,
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetTypeAsync([NotNull] TAuthorization authorization,
[CanBeNull] string type, CancellationToken cancellationToken)
{
if (authorization == null)
@ -1137,7 +1028,7 @@ namespace OpenIddict.EntityFrameworkCore
authorization.Type = type;
return Task.CompletedTask;
return default;
}
/// <summary>
@ -1145,10 +1036,8 @@ namespace OpenIddict.EntityFrameworkCore
/// </summary>
/// <param name="authorization">The authorization to update.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual async Task UpdateAsync([NotNull] TAuthorization authorization, CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual async ValueTask UpdateAsync([NotNull] TAuthorization authorization, CancellationToken cancellationToken)
{
if (authorization == null)
{

151
src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictScopeStore.cs

@ -103,11 +103,11 @@ namespace OpenIddict.EntityFrameworkCore
/// </summary>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the number of scopes in the database.
/// </returns>
public virtual Task<long> CountAsync(CancellationToken cancellationToken)
=> Scopes.LongCountAsync();
public virtual ValueTask<long> CountAsync(CancellationToken cancellationToken)
=> new ValueTask<long>(Scopes.AsQueryable().LongCountAsync());
/// <summary>
/// Determines the number of scopes that match the specified query.
@ -116,17 +116,17 @@ namespace OpenIddict.EntityFrameworkCore
/// <param name="query">The query to execute.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the number of scopes that match the specified query.
/// </returns>
public virtual Task<long> CountAsync<TResult>([NotNull] Func<IQueryable<TScope>, IQueryable<TResult>> query, CancellationToken cancellationToken)
public virtual ValueTask<long> CountAsync<TResult>([NotNull] Func<IQueryable<TScope>, IQueryable<TResult>> query, CancellationToken cancellationToken)
{
if (query == null)
{
throw new ArgumentNullException(nameof(query));
}
return query(Scopes).LongCountAsync();
return new ValueTask<long>(query(Scopes).LongCountAsync());
}
/// <summary>
@ -134,10 +134,8 @@ namespace OpenIddict.EntityFrameworkCore
/// </summary>
/// <param name="scope">The scope to create.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task CreateAsync([NotNull] TScope scope, CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask CreateAsync([NotNull] TScope scope, CancellationToken cancellationToken)
{
if (scope == null)
{
@ -146,7 +144,7 @@ namespace OpenIddict.EntityFrameworkCore
Scopes.Add(scope);
return Context.SaveChangesAsync(cancellationToken);
return new ValueTask(Context.SaveChangesAsync(cancellationToken));
}
/// <summary>
@ -154,10 +152,8 @@ namespace OpenIddict.EntityFrameworkCore
/// </summary>
/// <param name="scope">The scope to delete.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual async Task DeleteAsync([NotNull] TScope scope, CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual async ValueTask DeleteAsync([NotNull] TScope scope, CancellationToken cancellationToken)
{
if (scope == null)
{
@ -195,17 +191,17 @@ namespace OpenIddict.EntityFrameworkCore
/// <param name="identifier">The unique identifier associated with the scope.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the scope corresponding to the identifier.
/// </returns>
public virtual Task<TScope> FindByIdAsync([NotNull] string identifier, CancellationToken cancellationToken)
public virtual ValueTask<TScope> FindByIdAsync([NotNull] string identifier, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(identifier))
{
throw new ArgumentException("The identifier cannot be null or empty.", nameof(identifier));
}
return FindById(Context, ConvertIdentifierFromString(identifier));
return new ValueTask<TScope>(FindById(Context, ConvertIdentifierFromString(identifier)));
}
/// <summary>
@ -223,17 +219,17 @@ namespace OpenIddict.EntityFrameworkCore
/// <param name="name">The name associated with the scope.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the scope corresponding to the specified name.
/// </returns>
public virtual Task<TScope> FindByNameAsync([NotNull] string name, CancellationToken cancellationToken)
public virtual ValueTask<TScope> FindByNameAsync([NotNull] string name, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(name))
{
throw new ArgumentException("The scope name cannot be null or empty.", nameof(name));
}
return FindByName(Context, name);
return new ValueTask<TScope>(FindByName(Context, name));
}
/// <summary>
@ -250,11 +246,8 @@ namespace OpenIddict.EntityFrameworkCore
/// </summary>
/// <param name="names">The names associated with the scopes.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the scopes corresponding to the specified names.
/// </returns>
public virtual async Task<ImmutableArray<TScope>> FindByNamesAsync(
/// <returns>The scopes corresponding to the specified names.</returns>
public virtual IAsyncEnumerable<TScope> FindByNamesAsync(
ImmutableArray<string> names, CancellationToken cancellationToken)
{
if (names.Any(name => string.IsNullOrEmpty(name)))
@ -262,14 +255,7 @@ namespace OpenIddict.EntityFrameworkCore
throw new ArgumentException("Scope names cannot be null or empty.", nameof(names));
}
var builder = ImmutableArray.CreateBuilder<TScope>();
await foreach (var scope in FindByNames(Context, names))
{
builder.Add(scope);
}
return builder.ToImmutable();
return FindByNames(Context, names);
}
/// <summary>
@ -291,11 +277,8 @@ namespace OpenIddict.EntityFrameworkCore
/// </summary>
/// <param name="resource">The resource associated with the scopes.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the scopes associated with the specified resource.
/// </returns>
public virtual async Task<ImmutableArray<TScope>> FindByResourceAsync(
/// <returns>The scopes associated with the specified resource.</returns>
public virtual IAsyncEnumerable<TScope> FindByResourceAsync(
[NotNull] string resource, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(resource))
@ -303,18 +286,8 @@ namespace OpenIddict.EntityFrameworkCore
throw new ArgumentException("The resource cannot be null or empty.", nameof(resource));
}
var builder = ImmutableArray.CreateBuilder<TScope>();
await foreach (var scope in FindByResource(Context, resource))
{
var resources = await GetResourcesAsync(scope, cancellationToken);
if (resources.Contains(resource, StringComparer.Ordinal))
{
builder.Add(scope);
}
}
return builder.ToImmutable();
return FindByResource(Context, resource)
.WhereAwait(async scope => (await GetResourcesAsync(scope, cancellationToken)).Contains(resource, StringComparer.Ordinal));
}
/// <summary>
@ -326,10 +299,10 @@ namespace OpenIddict.EntityFrameworkCore
/// <param name="state">The optional state.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the first element returned when executing the query.
/// </returns>
public virtual Task<TResult> GetAsync<TState, TResult>(
public virtual ValueTask<TResult> GetAsync<TState, TResult>(
[NotNull] Func<IQueryable<TScope>, TState, IQueryable<TResult>> query,
[CanBeNull] TState state, CancellationToken cancellationToken)
{
@ -338,7 +311,7 @@ namespace OpenIddict.EntityFrameworkCore
throw new ArgumentNullException(nameof(query));
}
return query(Scopes.AsTracking(), state).FirstOrDefaultAsync(cancellationToken);
return new ValueTask<TResult>(query(Scopes.AsTracking(), state).FirstOrDefaultAsync(cancellationToken));
}
/// <summary>
@ -521,14 +494,11 @@ namespace OpenIddict.EntityFrameworkCore
/// <param name="count">The number of results to return.</param>
/// <param name="offset">The number of results to skip.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the elements returned when executing the specified query.
/// </returns>
public virtual async Task<ImmutableArray<TScope>> ListAsync(
/// <returns>All the elements returned when executing the specified query.</returns>
public virtual IAsyncEnumerable<TScope> ListAsync(
[CanBeNull] int? count, [CanBeNull] int? offset, CancellationToken cancellationToken)
{
var query = Scopes.OrderBy(scope => scope.Id).AsTracking();
var query = Scopes.AsQueryable().OrderBy(scope => scope.Id).AsTracking();
if (offset.HasValue)
{
@ -540,7 +510,7 @@ namespace OpenIddict.EntityFrameworkCore
query = query.Take(count.Value);
}
return ImmutableArray.CreateRange(await query.ToListAsync(cancellationToken));
return query.AsAsyncEnumerable();
}
/// <summary>
@ -551,11 +521,8 @@ namespace OpenIddict.EntityFrameworkCore
/// <param name="query">The query to execute.</param>
/// <param name="state">The optional state.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the elements returned when executing the specified query.
/// </returns>
public virtual async Task<ImmutableArray<TResult>> ListAsync<TState, TResult>(
/// <returns>All the elements returned when executing the specified query.</returns>
public virtual IAsyncEnumerable<TResult> ListAsync<TState, TResult>(
[NotNull] Func<IQueryable<TScope>, TState, IQueryable<TResult>> query,
[CanBeNull] TState state, CancellationToken cancellationToken)
{
@ -564,7 +531,7 @@ namespace OpenIddict.EntityFrameworkCore
throw new ArgumentNullException(nameof(query));
}
return ImmutableArray.CreateRange(await query(Scopes.AsTracking(), state).ToListAsync(cancellationToken));
return query(Scopes.AsTracking(), state).AsAsyncEnumerable();
}
/// <summary>
@ -573,10 +540,8 @@ namespace OpenIddict.EntityFrameworkCore
/// <param name="scope">The scope.</param>
/// <param name="description">The description associated with the authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetDescriptionAsync([NotNull] TScope scope, [CanBeNull] string description, CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetDescriptionAsync([NotNull] TScope scope, [CanBeNull] string description, CancellationToken cancellationToken)
{
if (scope == null)
{
@ -585,7 +550,7 @@ namespace OpenIddict.EntityFrameworkCore
scope.Description = description;
return Task.CompletedTask;
return default;
}
/// <summary>
@ -594,10 +559,8 @@ namespace OpenIddict.EntityFrameworkCore
/// <param name="scope">The scope.</param>
/// <param name="name">The display name associated with the scope.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetDisplayNameAsync([NotNull] TScope scope, [CanBeNull] string name, CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetDisplayNameAsync([NotNull] TScope scope, [CanBeNull] string name, CancellationToken cancellationToken)
{
if (scope == null)
{
@ -606,7 +569,7 @@ namespace OpenIddict.EntityFrameworkCore
scope.DisplayName = name;
return Task.CompletedTask;
return default;
}
/// <summary>
@ -615,10 +578,8 @@ namespace OpenIddict.EntityFrameworkCore
/// <param name="scope">The scope.</param>
/// <param name="name">The name associated with the authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetNameAsync([NotNull] TScope scope, [CanBeNull] string name, CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetNameAsync([NotNull] TScope scope, [CanBeNull] string name, CancellationToken cancellationToken)
{
if (scope == null)
{
@ -627,7 +588,7 @@ namespace OpenIddict.EntityFrameworkCore
scope.Name = name;
return Task.CompletedTask;
return default;
}
/// <summary>
@ -636,10 +597,8 @@ namespace OpenIddict.EntityFrameworkCore
/// <param name="scope">The scope.</param>
/// <param name="properties">The additional properties associated with the scope.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetPropertiesAsync([NotNull] TScope scope, [CanBeNull] JObject properties, CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetPropertiesAsync([NotNull] TScope scope, [CanBeNull] JObject properties, CancellationToken cancellationToken)
{
if (scope == null)
{
@ -650,12 +609,12 @@ namespace OpenIddict.EntityFrameworkCore
{
scope.Properties = null;
return Task.CompletedTask;
return default;
}
scope.Properties = properties.ToString(Formatting.None);
return Task.CompletedTask;
return default;
}
/// <summary>
@ -664,10 +623,8 @@ namespace OpenIddict.EntityFrameworkCore
/// <param name="scope">The scope.</param>
/// <param name="resources">The resources associated with the scope.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetResourcesAsync([NotNull] TScope scope, ImmutableArray<string> resources, CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetResourcesAsync([NotNull] TScope scope, ImmutableArray<string> resources, CancellationToken cancellationToken)
{
if (scope == null)
{
@ -678,12 +635,12 @@ namespace OpenIddict.EntityFrameworkCore
{
scope.Resources = null;
return Task.CompletedTask;
return default;
}
scope.Resources = new JArray(resources.ToArray()).ToString(Formatting.None);
return Task.CompletedTask;
return default;
}
/// <summary>
@ -691,10 +648,8 @@ namespace OpenIddict.EntityFrameworkCore
/// </summary>
/// <param name="scope">The scope to update.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual async Task UpdateAsync([NotNull] TScope scope, CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual async ValueTask UpdateAsync([NotNull] TScope scope, CancellationToken cancellationToken)
{
if (scope == null)
{

285
src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictTokenStore.cs

@ -124,11 +124,11 @@ namespace OpenIddict.EntityFrameworkCore
/// </summary>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the number of applications in the database.
/// </returns>
public virtual Task<long> CountAsync(CancellationToken cancellationToken)
=> Tokens.LongCountAsync();
public virtual ValueTask<long> CountAsync(CancellationToken cancellationToken)
=> new ValueTask<long>(Tokens.AsQueryable().LongCountAsync());
/// <summary>
/// Determines the number of tokens that match the specified query.
@ -137,17 +137,17 @@ namespace OpenIddict.EntityFrameworkCore
/// <param name="query">The query to execute.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the number of tokens that match the specified query.
/// </returns>
public virtual Task<long> CountAsync<TResult>([NotNull] Func<IQueryable<TToken>, IQueryable<TResult>> query, CancellationToken cancellationToken)
public virtual ValueTask<long> CountAsync<TResult>([NotNull] Func<IQueryable<TToken>, IQueryable<TResult>> query, CancellationToken cancellationToken)
{
if (query == null)
{
throw new ArgumentNullException(nameof(query));
}
return query(Tokens).LongCountAsync();
return new ValueTask<long>(query(Tokens).LongCountAsync());
}
/// <summary>
@ -155,10 +155,8 @@ namespace OpenIddict.EntityFrameworkCore
/// </summary>
/// <param name="token">The token to create.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task CreateAsync([NotNull] TToken token, CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask CreateAsync([NotNull] TToken token, CancellationToken cancellationToken)
{
if (token == null)
{
@ -167,7 +165,7 @@ namespace OpenIddict.EntityFrameworkCore
Context.Add(token);
return Context.SaveChangesAsync(cancellationToken);
return new ValueTask(Context.SaveChangesAsync(cancellationToken));
}
/// <summary>
@ -175,10 +173,8 @@ namespace OpenIddict.EntityFrameworkCore
/// </summary>
/// <param name="token">The token to delete.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual async Task DeleteAsync([NotNull] TToken token, CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual async ValueTask DeleteAsync([NotNull] TToken token, CancellationToken cancellationToken)
{
if (token == null)
{
@ -227,11 +223,8 @@ namespace OpenIddict.EntityFrameworkCore
/// <param name="subject">The subject associated with the token.</param>
/// <param name="client">The client associated with the token.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the tokens corresponding to the subject/client.
/// </returns>
public virtual async Task<ImmutableArray<TToken>> FindAsync([NotNull] string subject,
/// <returns>The tokens corresponding to the subject/client.</returns>
public virtual IAsyncEnumerable<TToken> FindAsync([NotNull] string subject,
[NotNull] string client, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(subject))
@ -244,15 +237,7 @@ namespace OpenIddict.EntityFrameworkCore
throw new ArgumentException("The client cannot be null or empty.", nameof(client));
}
var builder = ImmutableArray.CreateBuilder<TToken>();
await foreach (var token in FindBySubjectAndClient(Context,
ConvertIdentifierFromString(client), subject))
{
builder.Add(token);
}
return builder.ToImmutable();
return FindBySubjectAndClient(Context, ConvertIdentifierFromString(client), subject);
}
/// <summary>
@ -280,11 +265,8 @@ namespace OpenIddict.EntityFrameworkCore
/// <param name="client">The client associated with the token.</param>
/// <param name="status">The token status.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the tokens corresponding to the criteria.
/// </returns>
public virtual async Task<ImmutableArray<TToken>> FindAsync(
/// <returns>The tokens corresponding to the criteria.</returns>
public virtual IAsyncEnumerable<TToken> FindAsync(
[NotNull] string subject, [NotNull] string client,
[NotNull] string status, CancellationToken cancellationToken)
{
@ -303,15 +285,7 @@ namespace OpenIddict.EntityFrameworkCore
throw new ArgumentException("The status cannot be null or empty.", nameof(status));
}
var builder = ImmutableArray.CreateBuilder<TToken>();
await foreach (var token in FindBySubjectClientAndStatus(Context,
ConvertIdentifierFromString(client), subject, status))
{
builder.Add(token);
}
return builder.ToImmutable();
return FindBySubjectClientAndStatus(Context, ConvertIdentifierFromString(client), subject, status);
}
/// <summary>
@ -342,11 +316,8 @@ namespace OpenIddict.EntityFrameworkCore
/// <param name="status">The token status.</param>
/// <param name="type">The token type.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the tokens corresponding to the criteria.
/// </returns>
public virtual async Task<ImmutableArray<TToken>> FindAsync(
/// <returns>The tokens corresponding to the criteria.</returns>
public virtual IAsyncEnumerable<TToken> FindAsync(
[NotNull] string subject, [NotNull] string client,
[NotNull] string status, [NotNull] string type, CancellationToken cancellationToken)
{
@ -370,15 +341,7 @@ namespace OpenIddict.EntityFrameworkCore
throw new ArgumentException("The type cannot be null or empty.", nameof(type));
}
var builder = ImmutableArray.CreateBuilder<TToken>();
await foreach (var token in FindBySubjectClientStatusAndType(Context,
ConvertIdentifierFromString(client), subject, status, type))
{
builder.Add(token);
}
return builder.ToImmutable();
return FindBySubjectClientStatusAndType(Context, ConvertIdentifierFromString(client), subject, status, type);
}
/// <summary>
@ -404,25 +367,15 @@ namespace OpenIddict.EntityFrameworkCore
/// </summary>
/// <param name="identifier">The application identifier associated with the tokens.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the tokens corresponding to the specified application.
/// </returns>
public virtual async Task<ImmutableArray<TToken>> FindByApplicationIdAsync([NotNull] string identifier, CancellationToken cancellationToken)
/// <returns>The tokens corresponding to the specified application.</returns>
public virtual IAsyncEnumerable<TToken> FindByApplicationIdAsync([NotNull] string identifier, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(identifier))
{
throw new ArgumentException("The identifier cannot be null or empty.", nameof(identifier));
}
var builder = ImmutableArray.CreateBuilder<TToken>();
await foreach (var token in FindByApplicationId(Context, ConvertIdentifierFromString(identifier)))
{
builder.Add(token);
}
return builder.ToImmutable();
return FindByApplicationId(Context, ConvertIdentifierFromString(identifier));
}
/// <summary>
@ -448,25 +401,15 @@ namespace OpenIddict.EntityFrameworkCore
/// </summary>
/// <param name="identifier">The authorization identifier associated with the tokens.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the tokens corresponding to the specified authorization.
/// </returns>
public virtual async Task<ImmutableArray<TToken>> FindByAuthorizationIdAsync([NotNull] string identifier, CancellationToken cancellationToken)
/// <returns>The tokens corresponding to the specified authorization.</returns>
public virtual IAsyncEnumerable<TToken> FindByAuthorizationIdAsync([NotNull] string identifier, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(identifier))
{
throw new ArgumentException("The identifier cannot be null or empty.", nameof(identifier));
}
var builder = ImmutableArray.CreateBuilder<TToken>();
await foreach (var token in FindByAuthorizationId(Context, ConvertIdentifierFromString(identifier)))
{
builder.Add(token);
}
return builder.ToImmutable();
return FindByAuthorizationId(Context, ConvertIdentifierFromString(identifier));
}
/// <summary>
@ -487,17 +430,17 @@ namespace OpenIddict.EntityFrameworkCore
/// <param name="identifier">The unique identifier associated with the token.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the token corresponding to the unique identifier.
/// </returns>
public virtual Task<TToken> FindByIdAsync([NotNull] string identifier, CancellationToken cancellationToken)
public virtual ValueTask<TToken> FindByIdAsync([NotNull] string identifier, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(identifier))
{
throw new ArgumentException("The identifier cannot be null or empty.", nameof(identifier));
}
return FindById(Context, ConvertIdentifierFromString(identifier));
return new ValueTask<TToken>(FindById(Context, ConvertIdentifierFromString(identifier)));
}
/// <summary>
@ -520,17 +463,17 @@ namespace OpenIddict.EntityFrameworkCore
/// <param name="identifier">The reference identifier associated with the tokens.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the tokens corresponding to the specified reference identifier.
/// </returns>
public virtual Task<TToken> FindByReferenceIdAsync([NotNull] string identifier, CancellationToken cancellationToken)
public virtual ValueTask<TToken> FindByReferenceIdAsync([NotNull] string identifier, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(identifier))
{
throw new ArgumentException("The identifier cannot be null or empty.", nameof(identifier));
}
return FindByReferenceId(Context, identifier);
return new ValueTask<TToken>(FindByReferenceId(Context, identifier));
}
/// <summary>
@ -551,25 +494,15 @@ namespace OpenIddict.EntityFrameworkCore
/// </summary>
/// <param name="subject">The subject associated with the tokens.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the tokens corresponding to the specified subject.
/// </returns>
public virtual async Task<ImmutableArray<TToken>> FindBySubjectAsync([NotNull] string subject, CancellationToken cancellationToken)
/// <returns>The tokens corresponding to the specified subject.</returns>
public virtual IAsyncEnumerable<TToken> FindBySubjectAsync([NotNull] string subject, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(subject))
{
throw new ArgumentException("The subject cannot be null or empty.", nameof(subject));
}
var builder = ImmutableArray.CreateBuilder<TToken>();
await foreach (var token in FindBySubject(Context, subject))
{
builder.Add(token);
}
return builder.ToImmutable();
return FindBySubject(Context, subject);
}
/// <summary>
@ -617,10 +550,10 @@ namespace OpenIddict.EntityFrameworkCore
/// <param name="state">The optional state.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the first element returned when executing the query.
/// </returns>
public virtual Task<TResult> GetAsync<TState, TResult>(
public virtual ValueTask<TResult> GetAsync<TState, TResult>(
[NotNull] Func<IQueryable<TToken>, TState, IQueryable<TResult>> query,
[CanBeNull] TState state, CancellationToken cancellationToken)
{
@ -629,10 +562,10 @@ namespace OpenIddict.EntityFrameworkCore
throw new ArgumentNullException(nameof(query));
}
return query(
return new ValueTask<TResult>(query(
Tokens.Include(token => token.Application)
.Include(token => token.Authorization)
.AsTracking(), state).FirstOrDefaultAsync(cancellationToken);
.AsTracking(), state).FirstOrDefaultAsync(cancellationToken));
}
/// <summary>
@ -892,11 +825,8 @@ namespace OpenIddict.EntityFrameworkCore
/// <param name="count">The number of results to return.</param>
/// <param name="offset">The number of results to skip.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the elements returned when executing the specified query.
/// </returns>
public virtual async Task<ImmutableArray<TToken>> ListAsync(
/// <returns>All the elements returned when executing the specified query.</returns>
public virtual IAsyncEnumerable<TToken> ListAsync(
[CanBeNull] int? count, [CanBeNull] int? offset, CancellationToken cancellationToken)
{
var query = Tokens.Include(token => token.Application)
@ -914,7 +844,7 @@ namespace OpenIddict.EntityFrameworkCore
query = query.Take(count.Value);
}
return ImmutableArray.CreateRange(await query.ToListAsync(cancellationToken));
return query.AsAsyncEnumerable();
}
/// <summary>
@ -925,11 +855,8 @@ namespace OpenIddict.EntityFrameworkCore
/// <param name="query">The query to execute.</param>
/// <param name="state">The optional state.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the elements returned when executing the specified query.
/// </returns>
public virtual async Task<ImmutableArray<TResult>> ListAsync<TState, TResult>(
/// <returns>All the elements returned when executing the specified query.</returns>
public virtual IAsyncEnumerable<TResult> ListAsync<TState, TResult>(
[NotNull] Func<IQueryable<TToken>, TState, IQueryable<TResult>> query,
[CanBeNull] TState state, CancellationToken cancellationToken)
{
@ -938,20 +865,18 @@ namespace OpenIddict.EntityFrameworkCore
throw new ArgumentNullException(nameof(query));
}
return ImmutableArray.CreateRange(await query(
return query(
Tokens.Include(token => token.Application)
.Include(token => token.Authorization)
.AsTracking(), state).ToListAsync(cancellationToken));
.AsTracking(), state).AsAsyncEnumerable();
}
/// <summary>
/// Removes the tokens that are marked as expired or invalid.
/// </summary>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual async Task PruneAsync(CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual async ValueTask PruneAsync(CancellationToken cancellationToken)
{
// Note: Entity Framework Core doesn't support set-based deletes, which prevents removing
// entities in a single command without having to retrieve and materialize them first.
@ -959,7 +884,7 @@ namespace OpenIddict.EntityFrameworkCore
IList<Exception> exceptions = null;
async Task<IDbContextTransaction> CreateTransactionAsync()
async ValueTask<IDbContextTransaction> CreateTransactionAsync()
{
// Note: transactions that specify an explicit isolation level are only supported by
// relational providers and trying to use them with a different provider results in
@ -987,7 +912,7 @@ namespace OpenIddict.EntityFrameworkCore
// Note: to avoid sending too many queries, the maximum number of elements
// that can be removed by a single call to PruneAsync() is limited to 50000.
for (var offset = 0; offset < 50_000; offset = offset + 1_000)
for (var offset = 0; offset < 50_000; offset += 1_000)
{
cancellationToken.ThrowIfCancellationRequested();
@ -995,37 +920,35 @@ namespace OpenIddict.EntityFrameworkCore
// after it was retrieved from the database, the following logic is executed in
// a repeatable read transaction, that will put a lock on the retrieved entries
// and thus prevent them from being concurrently modified outside this block.
using (var transaction = await CreateTransactionAsync())
using var transaction = await CreateTransactionAsync();
var tokens = await (from token in Tokens.AsTracking()
where token.Status != OpenIddictConstants.Statuses.Valid ||
token.ExpirationDate < DateTimeOffset.UtcNow
orderby token.Id
select token).Skip(offset).Take(1_000).ToListAsync(cancellationToken);
if (tokens.Count == 0)
{
var tokens =
await (from token in Tokens.AsTracking()
where token.Status != OpenIddictConstants.Statuses.Valid ||
token.ExpirationDate < DateTimeOffset.UtcNow
orderby token.Id
select token).Skip(offset).Take(1_000).ToListAsync(cancellationToken);
if (tokens.Count == 0)
{
break;
}
break;
}
Context.RemoveRange(tokens);
Context.RemoveRange(tokens);
try
{
await Context.SaveChangesAsync(cancellationToken);
transaction?.Commit();
}
try
{
await Context.SaveChangesAsync(cancellationToken);
transaction?.Commit();
}
catch (Exception exception)
catch (Exception exception)
{
if (exceptions == null)
{
if (exceptions == null)
{
exceptions = new List<Exception>(capacity: 1);
}
exceptions.Add(exception);
exceptions = new List<Exception>(capacity: 1);
}
exceptions.Add(exception);
}
}
@ -1042,9 +965,9 @@ namespace OpenIddict.EntityFrameworkCore
/// <param name="identifier">The unique identifier associated with the client application.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual async Task SetApplicationIdAsync([NotNull] TToken token,
public virtual async ValueTask SetApplicationIdAsync([NotNull] TToken token,
[CanBeNull] string identifier, CancellationToken cancellationToken)
{
if (token == null)
@ -1088,9 +1011,9 @@ namespace OpenIddict.EntityFrameworkCore
/// <param name="identifier">The unique identifier associated with the authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual async Task SetAuthorizationIdAsync([NotNull] TToken token,
public virtual async ValueTask SetAuthorizationIdAsync([NotNull] TToken token,
[CanBeNull] string identifier, CancellationToken cancellationToken)
{
if (token == null)
@ -1134,9 +1057,9 @@ namespace OpenIddict.EntityFrameworkCore
/// <param name="date">The creation date.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetCreationDateAsync([NotNull] TToken token,
public virtual ValueTask SetCreationDateAsync([NotNull] TToken token,
[CanBeNull] DateTimeOffset? date, CancellationToken cancellationToken)
{
if (token == null)
@ -1146,7 +1069,7 @@ namespace OpenIddict.EntityFrameworkCore
token.CreationDate = date;
return Task.CompletedTask;
return default;
}
/// <summary>
@ -1156,9 +1079,9 @@ namespace OpenIddict.EntityFrameworkCore
/// <param name="date">The expiration date.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetExpirationDateAsync([NotNull] TToken token,
public virtual ValueTask SetExpirationDateAsync([NotNull] TToken token,
[CanBeNull] DateTimeOffset? date, CancellationToken cancellationToken)
{
if (token == null)
@ -1168,7 +1091,7 @@ namespace OpenIddict.EntityFrameworkCore
token.ExpirationDate = date;
return Task.CompletedTask;
return default;
}
/// <summary>
@ -1178,9 +1101,9 @@ namespace OpenIddict.EntityFrameworkCore
/// <param name="payload">The payload associated with the token.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetPayloadAsync([NotNull] TToken token, [CanBeNull] string payload, CancellationToken cancellationToken)
public virtual ValueTask SetPayloadAsync([NotNull] TToken token, [CanBeNull] string payload, CancellationToken cancellationToken)
{
if (token == null)
{
@ -1189,7 +1112,7 @@ namespace OpenIddict.EntityFrameworkCore
token.Payload = payload;
return Task.CompletedTask;
return default;
}
/// <summary>
@ -1199,9 +1122,9 @@ namespace OpenIddict.EntityFrameworkCore
/// <param name="properties">The additional properties associated with the token.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetPropertiesAsync([NotNull] TToken token, [CanBeNull] JObject properties, CancellationToken cancellationToken)
public virtual ValueTask SetPropertiesAsync([NotNull] TToken token, [CanBeNull] JObject properties, CancellationToken cancellationToken)
{
if (token == null)
{
@ -1212,12 +1135,12 @@ namespace OpenIddict.EntityFrameworkCore
{
token.Properties = null;
return Task.CompletedTask;
return default;
}
token.Properties = properties.ToString(Formatting.None);
return Task.CompletedTask;
return default;
}
/// <summary>
@ -1229,9 +1152,9 @@ namespace OpenIddict.EntityFrameworkCore
/// <param name="identifier">The reference identifier associated with the token.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetReferenceIdAsync([NotNull] TToken token, [CanBeNull] string identifier, CancellationToken cancellationToken)
public virtual ValueTask SetReferenceIdAsync([NotNull] TToken token, [CanBeNull] string identifier, CancellationToken cancellationToken)
{
if (token == null)
{
@ -1240,7 +1163,7 @@ namespace OpenIddict.EntityFrameworkCore
token.ReferenceId = identifier;
return Task.CompletedTask;
return default;
}
/// <summary>
@ -1250,9 +1173,9 @@ namespace OpenIddict.EntityFrameworkCore
/// <param name="status">The status associated with the authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetStatusAsync([NotNull] TToken token, [CanBeNull] string status, CancellationToken cancellationToken)
public virtual ValueTask SetStatusAsync([NotNull] TToken token, [CanBeNull] string status, CancellationToken cancellationToken)
{
if (token == null)
{
@ -1261,7 +1184,7 @@ namespace OpenIddict.EntityFrameworkCore
token.Status = status;
return Task.CompletedTask;
return default;
}
/// <summary>
@ -1271,9 +1194,9 @@ namespace OpenIddict.EntityFrameworkCore
/// <param name="subject">The subject associated with the token.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetSubjectAsync([NotNull] TToken token, [CanBeNull] string subject, CancellationToken cancellationToken)
public virtual ValueTask SetSubjectAsync([NotNull] TToken token, [CanBeNull] string subject, CancellationToken cancellationToken)
{
if (token == null)
{
@ -1282,7 +1205,7 @@ namespace OpenIddict.EntityFrameworkCore
token.Subject = subject;
return Task.CompletedTask;
return default;
}
/// <summary>
@ -1292,9 +1215,9 @@ namespace OpenIddict.EntityFrameworkCore
/// <param name="type">The token type associated with the token.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetTypeAsync([NotNull] TToken token, [CanBeNull] string type, CancellationToken cancellationToken)
public virtual ValueTask SetTypeAsync([NotNull] TToken token, [CanBeNull] string type, CancellationToken cancellationToken)
{
if (token == null)
{
@ -1303,7 +1226,7 @@ namespace OpenIddict.EntityFrameworkCore
token.Type = type;
return Task.CompletedTask;
return default;
}
/// <summary>
@ -1312,9 +1235,9 @@ namespace OpenIddict.EntityFrameworkCore
/// <param name="token">The token to update.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual async Task UpdateAsync([NotNull] TToken token, CancellationToken cancellationToken)
public virtual async ValueTask UpdateAsync([NotNull] TToken token, CancellationToken cancellationToken)
{
if (token == null)
{

75
src/OpenIddict.MongoDb/OpenIddictMongoDbHelpers.cs

@ -0,0 +1,75 @@
/*
* Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
* See https://github.com/openiddict/openiddict-core for more information concerning
* the license and the contributors participating to this project.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using JetBrains.Annotations;
namespace MongoDB.Driver
{
/// <summary>
/// Exposes extensions simplifying the integration between OpenIddict and MongoDB.
/// </summary>
internal static class OpenIddictMongoDbHelpers
{
/// <summary>
/// Executes the query and returns the results as a streamed async enumeration.
/// </summary>
/// <typeparam name="T">The type of the returned entities.</typeparam>
/// <param name="source">The query source.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>The streamed async enumeration containing the results.</returns>
internal static IAsyncEnumerable<T> ToAsyncEnumerable<T>([NotNull] this IAsyncCursorSource<T> source, CancellationToken cancellationToken)
{
if (source == null)
{
throw new ArgumentNullException(nameof(source));
}
return ExecuteAsync();
async IAsyncEnumerable<T> ExecuteAsync()
{
using var cursor = await source.ToCursorAsync();
while (await cursor.MoveNextAsync(cancellationToken))
{
foreach (var element in cursor.Current)
{
yield return element;
}
}
}
}
/// <summary>
/// Executes the query and returns the results as a streamed async enumeration.
/// </summary>
/// <typeparam name="T">The type of the returned entities.</typeparam>
/// <param name="source">The query source.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>The streamed async enumeration containing the results.</returns>
internal static IAsyncEnumerable<T> ToAsyncEnumerable<T>([NotNull] this IQueryable<T> source, CancellationToken cancellationToken)
{
if (source == null)
{
throw new ArgumentNullException(nameof(source));
}
return ExecuteAsync();
async IAsyncEnumerable<T> ExecuteAsync()
{
await foreach (var element in ((IAsyncCursorSource<T>) source).ToAsyncEnumerable(cancellationToken))
{
yield return element;
}
}
}
}
}

202
src/OpenIddict.MongoDb/Stores/OpenIddictApplicationStore.cs

@ -5,8 +5,10 @@
*/
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
@ -52,10 +54,10 @@ namespace OpenIddict.MongoDb
/// </summary>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the number of applications in the database.
/// </returns>
public virtual async Task<long> CountAsync(CancellationToken cancellationToken)
public virtual async ValueTask<long> CountAsync(CancellationToken cancellationToken)
{
var database = await Context.GetDatabaseAsync(cancellationToken);
var collection = database.GetCollection<TApplication>(Options.CurrentValue.ApplicationsCollectionName);
@ -70,10 +72,10 @@ namespace OpenIddict.MongoDb
/// <param name="query">The query to execute.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the number of applications that match the specified query.
/// </returns>
public virtual async Task<long> CountAsync<TResult>(
public virtual async ValueTask<long> CountAsync<TResult>(
[NotNull] Func<IQueryable<TApplication>, IQueryable<TResult>> query, CancellationToken cancellationToken)
{
if (query == null)
@ -92,10 +94,8 @@ namespace OpenIddict.MongoDb
/// </summary>
/// <param name="application">The application to create.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual async Task CreateAsync([NotNull] TApplication application, CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual async ValueTask CreateAsync([NotNull] TApplication application, CancellationToken cancellationToken)
{
if (application == null)
{
@ -113,10 +113,8 @@ namespace OpenIddict.MongoDb
/// </summary>
/// <param name="application">The application to delete.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual async Task DeleteAsync([NotNull] TApplication application, CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual async ValueTask DeleteAsync([NotNull] TApplication application, CancellationToken cancellationToken)
{
if (application == null)
{
@ -151,10 +149,10 @@ namespace OpenIddict.MongoDb
/// <param name="identifier">The client identifier associated with the application.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the client application corresponding to the identifier.
/// </returns>
public virtual async Task<TApplication> FindByClientIdAsync([NotNull] string identifier, CancellationToken cancellationToken)
public virtual async ValueTask<TApplication> FindByClientIdAsync([NotNull] string identifier, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(identifier))
{
@ -173,10 +171,10 @@ namespace OpenIddict.MongoDb
/// <param name="identifier">The unique identifier associated with the application.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the client application corresponding to the identifier.
/// </returns>
public virtual async Task<TApplication> FindByIdAsync([NotNull] string identifier, CancellationToken cancellationToken)
public virtual async ValueTask<TApplication> FindByIdAsync([NotNull] string identifier, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(identifier))
{
@ -195,11 +193,8 @@ namespace OpenIddict.MongoDb
/// </summary>
/// <param name="address">The post_logout_redirect_uri associated with the applications.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation, whose result
/// returns the client applications corresponding to the specified post_logout_redirect_uri.
/// </returns>
public virtual async Task<ImmutableArray<TApplication>> FindByPostLogoutRedirectUriAsync(
/// <returns>The client applications corresponding to the specified post_logout_redirect_uri.</returns>
public virtual IAsyncEnumerable<TApplication> FindByPostLogoutRedirectUriAsync(
[NotNull] string address, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(address))
@ -207,11 +202,19 @@ namespace OpenIddict.MongoDb
throw new ArgumentException("The address cannot be null or empty.", nameof(address));
}
var database = await Context.GetDatabaseAsync(cancellationToken);
var collection = database.GetCollection<TApplication>(Options.CurrentValue.ApplicationsCollectionName);
return ExecuteAsync(cancellationToken);
async IAsyncEnumerable<TApplication> ExecuteAsync(CancellationToken cancellationToken)
{
var database = await Context.GetDatabaseAsync(cancellationToken);
var collection = database.GetCollection<TApplication>(Options.CurrentValue.ApplicationsCollectionName);
return ImmutableArray.CreateRange(await collection.Find(application =>
application.PostLogoutRedirectUris.Contains(address)).ToListAsync(cancellationToken));
await foreach (var application in collection.Find(application =>
application.PostLogoutRedirectUris.Contains(address)).ToAsyncEnumerable(cancellationToken))
{
yield return application;
}
}
}
/// <summary>
@ -219,11 +222,8 @@ namespace OpenIddict.MongoDb
/// </summary>
/// <param name="address">The redirect_uri associated with the applications.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation, whose result
/// returns the client applications corresponding to the specified redirect_uri.
/// </returns>
public virtual async Task<ImmutableArray<TApplication>> FindByRedirectUriAsync(
/// <returns>The client applications corresponding to the specified redirect_uri.</returns>
public virtual IAsyncEnumerable<TApplication> FindByRedirectUriAsync(
[NotNull] string address, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(address))
@ -231,11 +231,19 @@ namespace OpenIddict.MongoDb
throw new ArgumentException("The address cannot be null or empty.", nameof(address));
}
var database = await Context.GetDatabaseAsync(cancellationToken);
var collection = database.GetCollection<TApplication>(Options.CurrentValue.ApplicationsCollectionName);
return ExecuteAsync(cancellationToken);
async IAsyncEnumerable<TApplication> ExecuteAsync(CancellationToken cancellationToken)
{
var database = await Context.GetDatabaseAsync(cancellationToken);
var collection = database.GetCollection<TApplication>(Options.CurrentValue.ApplicationsCollectionName);
return ImmutableArray.CreateRange(await collection.Find(application =>
application.RedirectUris.Contains(address)).ToListAsync(cancellationToken));
await foreach (var application in collection.Find(application =>
application.RedirectUris.Contains(address)).ToAsyncEnumerable(cancellationToken))
{
yield return application;
}
}
}
/// <summary>
@ -247,10 +255,10 @@ namespace OpenIddict.MongoDb
/// <param name="state">The optional state.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the first element returned when executing the query.
/// </returns>
public virtual async Task<TResult> GetAsync<TState, TResult>(
public virtual async ValueTask<TResult> GetAsync<TState, TResult>(
[NotNull] Func<IQueryable<TApplication>, TState, IQueryable<TResult>> query,
[CanBeNull] TState state, CancellationToken cancellationToken)
{
@ -512,12 +520,9 @@ namespace OpenIddict.MongoDb
/// <param name="count">The number of results to return.</param>
/// <param name="offset">The number of results to skip.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the elements returned when executing the specified query.
/// </returns>
public virtual async Task<ImmutableArray<TApplication>> ListAsync(
[CanBeNull] int? count, [CanBeNull] int? offset, CancellationToken cancellationToken)
/// <returns>All the elements returned when executing the specified query.</returns>
public virtual async IAsyncEnumerable<TApplication> ListAsync(
[CanBeNull] int? count, [CanBeNull] int? offset, [EnumeratorCancellation] CancellationToken cancellationToken)
{
var database = await Context.GetDatabaseAsync(cancellationToken);
var collection = database.GetCollection<TApplication>(Options.CurrentValue.ApplicationsCollectionName);
@ -534,7 +539,10 @@ namespace OpenIddict.MongoDb
query = query.Take(count.Value);
}
return ImmutableArray.CreateRange(await query.ToListAsync(cancellationToken));
await foreach (var application in ((IAsyncCursorSource<TApplication>) query).ToAsyncEnumerable(cancellationToken))
{
yield return application;
}
}
/// <summary>
@ -545,11 +553,8 @@ namespace OpenIddict.MongoDb
/// <param name="query">The query to execute.</param>
/// <param name="state">The optional state.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the elements returned when executing the specified query.
/// </returns>
public virtual async Task<ImmutableArray<TResult>> ListAsync<TState, TResult>(
/// <returns>All the elements returned when executing the specified query.</returns>
public virtual IAsyncEnumerable<TResult> ListAsync<TState, TResult>(
[NotNull] Func<IQueryable<TApplication>, TState, IQueryable<TResult>> query,
[CanBeNull] TState state, CancellationToken cancellationToken)
{
@ -558,11 +563,18 @@ namespace OpenIddict.MongoDb
throw new ArgumentNullException(nameof(query));
}
var database = await Context.GetDatabaseAsync(cancellationToken);
var collection = database.GetCollection<TApplication>(Options.CurrentValue.ApplicationsCollectionName);
return ExecuteAsync(cancellationToken);
async IAsyncEnumerable<TResult> ExecuteAsync(CancellationToken cancellationToken)
{
var database = await Context.GetDatabaseAsync(cancellationToken);
var collection = database.GetCollection<TApplication>(Options.CurrentValue.ApplicationsCollectionName);
return ImmutableArray.CreateRange(
await ((IMongoQueryable<TResult>) query(collection.AsQueryable(), state)).ToListAsync(cancellationToken));
await foreach (var element in query(collection.AsQueryable(), state).ToAsyncEnumerable(cancellationToken))
{
yield return element;
}
}
}
/// <summary>
@ -571,10 +583,8 @@ namespace OpenIddict.MongoDb
/// <param name="application">The application.</param>
/// <param name="identifier">The client identifier associated with the application.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetClientIdAsync([NotNull] TApplication application,
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetClientIdAsync([NotNull] TApplication application,
[CanBeNull] string identifier, CancellationToken cancellationToken)
{
if (application == null)
@ -584,7 +594,7 @@ namespace OpenIddict.MongoDb
application.ClientId = identifier;
return Task.CompletedTask;
return default;
}
/// <summary>
@ -595,10 +605,8 @@ namespace OpenIddict.MongoDb
/// <param name="application">The application.</param>
/// <param name="secret">The client secret associated with the application.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetClientSecretAsync([NotNull] TApplication application,
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetClientSecretAsync([NotNull] TApplication application,
[CanBeNull] string secret, CancellationToken cancellationToken)
{
if (application == null)
@ -608,7 +616,7 @@ namespace OpenIddict.MongoDb
application.ClientSecret = secret;
return Task.CompletedTask;
return default;
}
/// <summary>
@ -617,10 +625,8 @@ namespace OpenIddict.MongoDb
/// <param name="application">The application.</param>
/// <param name="type">The client type associated with the application.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetClientTypeAsync([NotNull] TApplication application,
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetClientTypeAsync([NotNull] TApplication application,
[CanBeNull] string type, CancellationToken cancellationToken)
{
if (application == null)
@ -630,7 +636,7 @@ namespace OpenIddict.MongoDb
application.Type = type;
return Task.CompletedTask;
return default;
}
/// <summary>
@ -639,10 +645,8 @@ namespace OpenIddict.MongoDb
/// <param name="application">The application.</param>
/// <param name="type">The consent type associated with the application.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetConsentTypeAsync([NotNull] TApplication application,
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetConsentTypeAsync([NotNull] TApplication application,
[CanBeNull] string type, CancellationToken cancellationToken)
{
if (application == null)
@ -652,7 +656,7 @@ namespace OpenIddict.MongoDb
application.ConsentType = type;
return Task.CompletedTask;
return default;
}
/// <summary>
@ -661,10 +665,8 @@ namespace OpenIddict.MongoDb
/// <param name="application">The application.</param>
/// <param name="name">The display name associated with the application.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetDisplayNameAsync([NotNull] TApplication application,
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetDisplayNameAsync([NotNull] TApplication application,
[CanBeNull] string name, CancellationToken cancellationToken)
{
if (application == null)
@ -674,7 +676,7 @@ namespace OpenIddict.MongoDb
application.DisplayName = name;
return Task.CompletedTask;
return default;
}
/// <summary>
@ -683,10 +685,8 @@ namespace OpenIddict.MongoDb
/// <param name="application">The application.</param>
/// <param name="permissions">The permissions associated with the application </param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetPermissionsAsync([NotNull] TApplication application, ImmutableArray<string> permissions, CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetPermissionsAsync([NotNull] TApplication application, ImmutableArray<string> permissions, CancellationToken cancellationToken)
{
if (application == null)
{
@ -697,12 +697,12 @@ namespace OpenIddict.MongoDb
{
application.Permissions = null;
return Task.CompletedTask;
return default;
}
application.Permissions = permissions.ToArray();
return Task.CompletedTask;
return default;
}
/// <summary>
@ -711,10 +711,8 @@ namespace OpenIddict.MongoDb
/// <param name="application">The application.</param>
/// <param name="addresses">The logout callback addresses associated with the application </param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetPostLogoutRedirectUrisAsync([NotNull] TApplication application,
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetPostLogoutRedirectUrisAsync([NotNull] TApplication application,
ImmutableArray<string> addresses, CancellationToken cancellationToken)
{
if (application == null)
@ -726,12 +724,12 @@ namespace OpenIddict.MongoDb
{
application.PostLogoutRedirectUris = null;
return Task.CompletedTask;
return default;
}
application.PostLogoutRedirectUris = addresses.ToArray();
return Task.CompletedTask;
return default;
}
/// <summary>
@ -740,10 +738,8 @@ namespace OpenIddict.MongoDb
/// <param name="application">The application.</param>
/// <param name="properties">The additional properties associated with the application.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetPropertiesAsync([NotNull] TApplication application, [CanBeNull] JObject properties, CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetPropertiesAsync([NotNull] TApplication application, [CanBeNull] JObject properties, CancellationToken cancellationToken)
{
if (application == null)
{
@ -754,12 +750,12 @@ namespace OpenIddict.MongoDb
{
application.Properties = null;
return Task.CompletedTask;
return default;
}
application.Properties = BsonDocument.Parse(properties.ToString(Formatting.None));
return Task.CompletedTask;
return default;
}
/// <summary>
@ -768,10 +764,8 @@ namespace OpenIddict.MongoDb
/// <param name="application">The application.</param>
/// <param name="addresses">The callback addresses associated with the application </param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetRedirectUrisAsync([NotNull] TApplication application,
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetRedirectUrisAsync([NotNull] TApplication application,
ImmutableArray<string> addresses, CancellationToken cancellationToken)
{
if (application == null)
@ -783,12 +777,12 @@ namespace OpenIddict.MongoDb
{
application.RedirectUris = null;
return Task.CompletedTask;
return default;
}
application.RedirectUris = addresses.ToArray();
return Task.CompletedTask;
return default;
}
/// <summary>
@ -796,10 +790,8 @@ namespace OpenIddict.MongoDb
/// </summary>
/// <param name="application">The application to update.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual async Task UpdateAsync([NotNull] TApplication application, CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual async ValueTask UpdateAsync([NotNull] TApplication application, CancellationToken cancellationToken)
{
if (application == null)
{

291
src/OpenIddict.MongoDb/Stores/OpenIddictAuthorizationStore.cs

@ -8,6 +8,7 @@ using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
@ -53,10 +54,10 @@ namespace OpenIddict.MongoDb
/// </summary>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the number of authorizations in the database.
/// </returns>
public virtual async Task<long> CountAsync(CancellationToken cancellationToken)
public virtual async ValueTask<long> CountAsync(CancellationToken cancellationToken)
{
var database = await Context.GetDatabaseAsync(cancellationToken);
var collection = database.GetCollection<TAuthorization>(Options.CurrentValue.AuthorizationsCollectionName);
@ -71,10 +72,10 @@ namespace OpenIddict.MongoDb
/// <param name="query">The query to execute.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the number of authorizations that match the specified query.
/// </returns>
public virtual async Task<long> CountAsync<TResult>(
public virtual async ValueTask<long> CountAsync<TResult>(
[NotNull] Func<IQueryable<TAuthorization>, IQueryable<TResult>> query, CancellationToken cancellationToken)
{
if (query == null)
@ -93,10 +94,8 @@ namespace OpenIddict.MongoDb
/// </summary>
/// <param name="authorization">The authorization to create.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual async Task CreateAsync([NotNull] TAuthorization authorization, CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual async ValueTask CreateAsync([NotNull] TAuthorization authorization, CancellationToken cancellationToken)
{
if (authorization == null)
{
@ -114,10 +113,8 @@ namespace OpenIddict.MongoDb
/// </summary>
/// <param name="authorization">The authorization to delete.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual async Task DeleteAsync([NotNull] TAuthorization authorization, CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual async ValueTask DeleteAsync([NotNull] TAuthorization authorization, CancellationToken cancellationToken)
{
if (authorization == null)
{
@ -149,11 +146,8 @@ namespace OpenIddict.MongoDb
/// <param name="subject">The subject associated with the authorization.</param>
/// <param name="client">The client associated with the authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the authorizations corresponding to the subject/client.
/// </returns>
public virtual async Task<ImmutableArray<TAuthorization>> FindAsync(
/// <returns>The authorizations corresponding to the subject/client.</returns>
public virtual IAsyncEnumerable<TAuthorization> FindAsync(
[NotNull] string subject, [NotNull] string client, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(subject))
@ -166,12 +160,20 @@ namespace OpenIddict.MongoDb
throw new ArgumentException("The client cannot be null or empty.", nameof(client));
}
var database = await Context.GetDatabaseAsync(cancellationToken);
var collection = database.GetCollection<TAuthorization>(Options.CurrentValue.AuthorizationsCollectionName);
return ExecuteAsync(cancellationToken);
return ImmutableArray.CreateRange(await collection.Find(authorization =>
authorization.Subject == subject &&
authorization.ApplicationId == ObjectId.Parse(client)).ToListAsync(cancellationToken));
async IAsyncEnumerable<TAuthorization> ExecuteAsync(CancellationToken cancellationToken)
{
var database = await Context.GetDatabaseAsync(cancellationToken);
var collection = database.GetCollection<TAuthorization>(Options.CurrentValue.AuthorizationsCollectionName);
await foreach (var authorization in collection.Find(authorization =>
authorization.Subject == subject &&
authorization.ApplicationId == ObjectId.Parse(client)).ToAsyncEnumerable(cancellationToken))
{
yield return authorization;
}
}
}
/// <summary>
@ -181,11 +183,8 @@ namespace OpenIddict.MongoDb
/// <param name="client">The client associated with the authorization.</param>
/// <param name="status">The authorization status.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the authorizations corresponding to the criteria.
/// </returns>
public virtual async Task<ImmutableArray<TAuthorization>> FindAsync(
/// <returns>The authorizations corresponding to the criteria.</returns>
public virtual IAsyncEnumerable<TAuthorization> FindAsync(
[NotNull] string subject, [NotNull] string client,
[NotNull] string status, CancellationToken cancellationToken)
{
@ -204,13 +203,21 @@ namespace OpenIddict.MongoDb
throw new ArgumentException("The status cannot be null or empty.", nameof(status));
}
var database = await Context.GetDatabaseAsync(cancellationToken);
var collection = database.GetCollection<TAuthorization>(Options.CurrentValue.AuthorizationsCollectionName);
return ExecuteAsync(cancellationToken);
return ImmutableArray.CreateRange(await collection.Find(authorization =>
authorization.Subject == subject &&
authorization.ApplicationId == ObjectId.Parse(client) &&
authorization.Status == status).ToListAsync(cancellationToken));
async IAsyncEnumerable<TAuthorization> ExecuteAsync(CancellationToken cancellationToken)
{
var database = await Context.GetDatabaseAsync(cancellationToken);
var collection = database.GetCollection<TAuthorization>(Options.CurrentValue.AuthorizationsCollectionName);
await foreach (var authorization in collection.Find(authorization =>
authorization.Subject == subject &&
authorization.ApplicationId == ObjectId.Parse(client) &&
authorization.Status == status).ToAsyncEnumerable(cancellationToken))
{
yield return authorization;
}
}
}
/// <summary>
@ -221,11 +228,8 @@ namespace OpenIddict.MongoDb
/// <param name="status">The authorization status.</param>
/// <param name="type">The authorization type.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the authorizations corresponding to the criteria.
/// </returns>
public virtual async Task<ImmutableArray<TAuthorization>> FindAsync(
/// <returns>The authorizations corresponding to the criteria.</returns>
public virtual IAsyncEnumerable<TAuthorization> FindAsync(
[NotNull] string subject, [NotNull] string client,
[NotNull] string status, [NotNull] string type, CancellationToken cancellationToken)
{
@ -249,14 +253,22 @@ namespace OpenIddict.MongoDb
throw new ArgumentException("The type cannot be null or empty.", nameof(type));
}
var database = await Context.GetDatabaseAsync(cancellationToken);
var collection = database.GetCollection<TAuthorization>(Options.CurrentValue.AuthorizationsCollectionName);
return ExecuteAsync(cancellationToken);
async IAsyncEnumerable<TAuthorization> ExecuteAsync(CancellationToken cancellationToken)
{
var database = await Context.GetDatabaseAsync(cancellationToken);
var collection = database.GetCollection<TAuthorization>(Options.CurrentValue.AuthorizationsCollectionName);
return ImmutableArray.CreateRange(await collection.Find(authorization =>
authorization.Subject == subject &&
authorization.ApplicationId == ObjectId.Parse(client) &&
authorization.Status == status &&
authorization.Type == type).ToListAsync(cancellationToken));
await foreach (var authorization in collection.Find(authorization =>
authorization.Subject == subject &&
authorization.ApplicationId == ObjectId.Parse(client) &&
authorization.Status == status &&
authorization.Type == type).ToAsyncEnumerable(cancellationToken))
{
yield return authorization;
}
}
}
/// <summary>
@ -268,11 +280,8 @@ namespace OpenIddict.MongoDb
/// <param name="type">The authorization type.</param>
/// <param name="scopes">The minimal scopes associated with the authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the authorizations corresponding to the criteria.
/// </returns>
public virtual async Task<ImmutableArray<TAuthorization>> FindAsync(
/// <returns>The authorizations corresponding to the criteria.</returns>
public virtual IAsyncEnumerable<TAuthorization> FindAsync(
[NotNull] string subject, [NotNull] string client,
[NotNull] string status, [NotNull] string type,
ImmutableArray<string> scopes, CancellationToken cancellationToken)
@ -297,17 +306,25 @@ namespace OpenIddict.MongoDb
throw new ArgumentException("The type cannot be null or empty.", nameof(type));
}
var database = await Context.GetDatabaseAsync(cancellationToken);
var collection = database.GetCollection<TAuthorization>(Options.CurrentValue.AuthorizationsCollectionName);
return ExecuteAsync(cancellationToken);
async IAsyncEnumerable<TAuthorization> ExecuteAsync(CancellationToken cancellationToken)
{
var database = await Context.GetDatabaseAsync(cancellationToken);
var collection = database.GetCollection<TAuthorization>(Options.CurrentValue.AuthorizationsCollectionName);
// Note: Enumerable.All() is deliberately used without the extension method syntax to ensure
// ImmutableArrayExtensions.All() (which is not supported by MongoDB) is not used instead.
return ImmutableArray.CreateRange(await collection.Find(authorization =>
authorization.Subject == subject &&
authorization.ApplicationId == ObjectId.Parse(client) &&
authorization.Status == status &&
authorization.Type == type &&
Enumerable.All(scopes, scope => authorization.Scopes.Contains(scope))).ToListAsync(cancellationToken));
// Note: Enumerable.All() is deliberately used without the extension method syntax to ensure
// ImmutableArrayExtensions.All() (which is not supported by MongoDB) is not used instead.
await foreach (var authorization in collection.Find(authorization =>
authorization.Subject == subject &&
authorization.ApplicationId == ObjectId.Parse(client) &&
authorization.Status == status &&
authorization.Type == type &&
Enumerable.All(scopes, scope => authorization.Scopes.Contains(scope))).ToAsyncEnumerable(cancellationToken))
{
yield return authorization;
}
}
}
/// <summary>
@ -315,11 +332,8 @@ namespace OpenIddict.MongoDb
/// </summary>
/// <param name="identifier">The application identifier associated with the authorizations.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the authorizations corresponding to the specified application.
/// </returns>
public virtual async Task<ImmutableArray<TAuthorization>> FindByApplicationIdAsync(
/// <returns>The authorizations corresponding to the specified application.</returns>
public virtual IAsyncEnumerable<TAuthorization> FindByApplicationIdAsync(
[NotNull] string identifier, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(identifier))
@ -327,11 +341,19 @@ namespace OpenIddict.MongoDb
throw new ArgumentException("The identifier cannot be null or empty.", nameof(identifier));
}
var database = await Context.GetDatabaseAsync(cancellationToken);
var collection = database.GetCollection<TAuthorization>(Options.CurrentValue.AuthorizationsCollectionName);
return ExecuteAsync(cancellationToken);
return ImmutableArray.CreateRange(await collection.Find(authorization =>
authorization.ApplicationId == ObjectId.Parse(identifier)).ToListAsync(cancellationToken));
async IAsyncEnumerable<TAuthorization> ExecuteAsync(CancellationToken cancellationToken)
{
var database = await Context.GetDatabaseAsync(cancellationToken);
var collection = database.GetCollection<TAuthorization>(Options.CurrentValue.AuthorizationsCollectionName);
await foreach (var authorization in collection.Find(authorization =>
authorization.ApplicationId == ObjectId.Parse(identifier)).ToAsyncEnumerable(cancellationToken))
{
yield return authorization;
}
}
}
/// <summary>
@ -340,10 +362,10 @@ namespace OpenIddict.MongoDb
/// <param name="identifier">The unique identifier associated with the authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the authorization corresponding to the identifier.
/// </returns>
public virtual async Task<TAuthorization> FindByIdAsync([NotNull] string identifier, CancellationToken cancellationToken)
public virtual async ValueTask<TAuthorization> FindByIdAsync([NotNull] string identifier, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(identifier))
{
@ -362,11 +384,8 @@ namespace OpenIddict.MongoDb
/// </summary>
/// <param name="subject">The subject associated with the authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the authorizations corresponding to the specified subject.
/// </returns>
public virtual async Task<ImmutableArray<TAuthorization>> FindBySubjectAsync(
/// <returns>The authorizations corresponding to the specified subject.</returns>
public virtual IAsyncEnumerable<TAuthorization> FindBySubjectAsync(
[NotNull] string subject, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(subject))
@ -374,11 +393,19 @@ namespace OpenIddict.MongoDb
throw new ArgumentException("The subject cannot be null or empty.", nameof(subject));
}
var database = await Context.GetDatabaseAsync(cancellationToken);
var collection = database.GetCollection<TAuthorization>(Options.CurrentValue.AuthorizationsCollectionName);
return ExecuteAsync(cancellationToken);
async IAsyncEnumerable<TAuthorization> ExecuteAsync(CancellationToken cancellationToken)
{
var database = await Context.GetDatabaseAsync(cancellationToken);
var collection = database.GetCollection<TAuthorization>(Options.CurrentValue.AuthorizationsCollectionName);
return ImmutableArray.CreateRange(await collection.Find(authorization =>
authorization.Subject == subject).ToListAsync(cancellationToken));
await foreach (var authorization in collection.Find(authorization =>
authorization.Subject == subject).ToAsyncEnumerable(cancellationToken))
{
yield return authorization;
}
}
}
/// <summary>
@ -409,10 +436,10 @@ namespace OpenIddict.MongoDb
/// <param name="state">The optional state.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the first element returned when executing the query.
/// </returns>
public virtual async Task<TResult> GetAsync<TState, TResult>(
public virtual async ValueTask<TResult> GetAsync<TState, TResult>(
[NotNull] Func<IQueryable<TAuthorization>, TState, IQueryable<TResult>> query,
[CanBeNull] TState state, CancellationToken cancellationToken)
{
@ -584,12 +611,9 @@ namespace OpenIddict.MongoDb
/// <param name="count">The number of results to return.</param>
/// <param name="offset">The number of results to skip.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the elements returned when executing the specified query.
/// </returns>
public virtual async Task<ImmutableArray<TAuthorization>> ListAsync(
[CanBeNull] int? count, [CanBeNull] int? offset, CancellationToken cancellationToken)
/// <returns>All the elements returned when executing the specified query.</returns>
public virtual async IAsyncEnumerable<TAuthorization> ListAsync(
[CanBeNull] int? count, [CanBeNull] int? offset, [EnumeratorCancellation] CancellationToken cancellationToken)
{
var database = await Context.GetDatabaseAsync(cancellationToken);
var collection = database.GetCollection<TAuthorization>(Options.CurrentValue.AuthorizationsCollectionName);
@ -606,7 +630,10 @@ namespace OpenIddict.MongoDb
query = query.Take(count.Value);
}
return ImmutableArray.CreateRange(await query.ToListAsync(cancellationToken));
await foreach (var authorization in ((IAsyncCursorSource<TAuthorization>) query).ToAsyncEnumerable(cancellationToken))
{
yield return authorization;
}
}
/// <summary>
@ -617,11 +644,8 @@ namespace OpenIddict.MongoDb
/// <param name="query">The query to execute.</param>
/// <param name="state">The optional state.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the elements returned when executing the specified query.
/// </returns>
public virtual async Task<ImmutableArray<TResult>> ListAsync<TState, TResult>(
/// <returns>All the elements returned when executing the specified query.</returns>
public virtual IAsyncEnumerable<TResult> ListAsync<TState, TResult>(
[NotNull] Func<IQueryable<TAuthorization>, TState, IQueryable<TResult>> query,
[CanBeNull] TState state, CancellationToken cancellationToken)
{
@ -630,21 +654,26 @@ namespace OpenIddict.MongoDb
throw new ArgumentNullException(nameof(query));
}
var database = await Context.GetDatabaseAsync(cancellationToken);
var collection = database.GetCollection<TAuthorization>(Options.CurrentValue.AuthorizationsCollectionName);
return ExecuteAsync(cancellationToken);
return ImmutableArray.CreateRange(
await ((IMongoQueryable<TResult>) query(collection.AsQueryable(), state)).ToListAsync(cancellationToken));
async IAsyncEnumerable<TResult> ExecuteAsync(CancellationToken cancellationToken)
{
var database = await Context.GetDatabaseAsync(cancellationToken);
var collection = database.GetCollection<TAuthorization>(Options.CurrentValue.AuthorizationsCollectionName);
await foreach (var element in query(collection.AsQueryable(), state).ToAsyncEnumerable(cancellationToken))
{
yield return element;
}
}
}
/// <summary>
/// Removes the authorizations that are marked as invalid and the ad-hoc ones that have no valid/nonexpired token attached.
/// </summary>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual async Task PruneAsync(CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual async ValueTask PruneAsync(CancellationToken cancellationToken)
{
var database = await Context.GetDatabaseAsync(cancellationToken);
var collection = database.GetCollection<TAuthorization>(Options.CurrentValue.AuthorizationsCollectionName);
@ -708,10 +737,8 @@ namespace OpenIddict.MongoDb
/// <param name="authorization">The authorization.</param>
/// <param name="identifier">The unique identifier associated with the client application.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetApplicationIdAsync([NotNull] TAuthorization authorization,
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetApplicationIdAsync([NotNull] TAuthorization authorization,
[CanBeNull] string identifier, CancellationToken cancellationToken)
{
if (authorization == null)
@ -729,7 +756,7 @@ namespace OpenIddict.MongoDb
authorization.ApplicationId = ObjectId.Empty;
}
return Task.CompletedTask;
return default;
}
/// <summary>
@ -738,10 +765,8 @@ namespace OpenIddict.MongoDb
/// <param name="authorization">The authorization.</param>
/// <param name="properties">The additional properties associated with the authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetPropertiesAsync([NotNull] TAuthorization authorization, [CanBeNull] JObject properties, CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetPropertiesAsync([NotNull] TAuthorization authorization, [CanBeNull] JObject properties, CancellationToken cancellationToken)
{
if (authorization == null)
{
@ -752,12 +777,12 @@ namespace OpenIddict.MongoDb
{
authorization.Properties = null;
return Task.CompletedTask;
return default;
}
authorization.Properties = BsonDocument.Parse(properties.ToString(Formatting.None));
return Task.CompletedTask;
return default;
}
/// <summary>
@ -766,10 +791,8 @@ namespace OpenIddict.MongoDb
/// <param name="authorization">The authorization.</param>
/// <param name="scopes">The scopes associated with the authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetScopesAsync([NotNull] TAuthorization authorization,
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetScopesAsync([NotNull] TAuthorization authorization,
ImmutableArray<string> scopes, CancellationToken cancellationToken)
{
if (authorization == null)
@ -781,12 +804,12 @@ namespace OpenIddict.MongoDb
{
authorization.Scopes = null;
return Task.CompletedTask;
return default;
}
authorization.Scopes = scopes.ToArray();
return Task.CompletedTask;
return default;
}
/// <summary>
@ -795,10 +818,8 @@ namespace OpenIddict.MongoDb
/// <param name="authorization">The authorization.</param>
/// <param name="status">The status associated with the authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetStatusAsync([NotNull] TAuthorization authorization,
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetStatusAsync([NotNull] TAuthorization authorization,
[CanBeNull] string status, CancellationToken cancellationToken)
{
if (authorization == null)
@ -808,7 +829,7 @@ namespace OpenIddict.MongoDb
authorization.Status = status;
return Task.CompletedTask;
return default;
}
/// <summary>
@ -817,10 +838,8 @@ namespace OpenIddict.MongoDb
/// <param name="authorization">The authorization.</param>
/// <param name="subject">The subject associated with the authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetSubjectAsync([NotNull] TAuthorization authorization,
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetSubjectAsync([NotNull] TAuthorization authorization,
[CanBeNull] string subject, CancellationToken cancellationToken)
{
if (authorization == null)
@ -830,7 +849,7 @@ namespace OpenIddict.MongoDb
authorization.Subject = subject;
return Task.CompletedTask;
return default;
}
/// <summary>
@ -839,10 +858,8 @@ namespace OpenIddict.MongoDb
/// <param name="authorization">The authorization.</param>
/// <param name="type">The type associated with the authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetTypeAsync([NotNull] TAuthorization authorization,
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetTypeAsync([NotNull] TAuthorization authorization,
[CanBeNull] string type, CancellationToken cancellationToken)
{
if (authorization == null)
@ -852,7 +869,7 @@ namespace OpenIddict.MongoDb
authorization.Type = type;
return Task.CompletedTask;
return default;
}
/// <summary>
@ -860,10 +877,8 @@ namespace OpenIddict.MongoDb
/// </summary>
/// <param name="authorization">The authorization to update.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual async Task UpdateAsync([NotNull] TAuthorization authorization, CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual async ValueTask UpdateAsync([NotNull] TAuthorization authorization, CancellationToken cancellationToken)
{
if (authorization == null)
{

163
src/OpenIddict.MongoDb/Stores/OpenIddictScopeStore.cs

@ -5,8 +5,10 @@
*/
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
@ -52,10 +54,10 @@ namespace OpenIddict.MongoDb
/// </summary>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the number of scopes in the database.
/// </returns>
public virtual async Task<long> CountAsync(CancellationToken cancellationToken)
public virtual async ValueTask<long> CountAsync(CancellationToken cancellationToken)
{
var database = await Context.GetDatabaseAsync(cancellationToken);
var collection = database.GetCollection<TScope>(Options.CurrentValue.ScopesCollectionName);
@ -70,10 +72,10 @@ namespace OpenIddict.MongoDb
/// <param name="query">The query to execute.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the number of scopes that match the specified query.
/// </returns>
public virtual async Task<long> CountAsync<TResult>(
public virtual async ValueTask<long> CountAsync<TResult>(
[NotNull] Func<IQueryable<TScope>, IQueryable<TResult>> query, CancellationToken cancellationToken)
{
if (query == null)
@ -92,10 +94,8 @@ namespace OpenIddict.MongoDb
/// </summary>
/// <param name="scope">The scope to create.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual async Task CreateAsync([NotNull] TScope scope, CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual async ValueTask CreateAsync([NotNull] TScope scope, CancellationToken cancellationToken)
{
if (scope == null)
{
@ -113,10 +113,8 @@ namespace OpenIddict.MongoDb
/// </summary>
/// <param name="scope">The scope to delete.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual async Task DeleteAsync([NotNull] TScope scope, CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual async ValueTask DeleteAsync([NotNull] TScope scope, CancellationToken cancellationToken)
{
if (scope == null)
{
@ -143,10 +141,10 @@ namespace OpenIddict.MongoDb
/// <param name="identifier">The unique identifier associated with the scope.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the scope corresponding to the identifier.
/// </returns>
public virtual async Task<TScope> FindByIdAsync([NotNull] string identifier, CancellationToken cancellationToken)
public virtual async ValueTask<TScope> FindByIdAsync([NotNull] string identifier, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(identifier))
{
@ -165,10 +163,10 @@ namespace OpenIddict.MongoDb
/// <param name="name">The name associated with the scope.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the scope corresponding to the specified name.
/// </returns>
public virtual async Task<TScope> FindByNameAsync([NotNull] string name, CancellationToken cancellationToken)
public virtual async ValueTask<TScope> FindByNameAsync([NotNull] string name, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(name))
{
@ -186,11 +184,8 @@ namespace OpenIddict.MongoDb
/// </summary>
/// <param name="names">The names associated with the scopes.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the scopes corresponding to the specified names.
/// </returns>
public virtual async Task<ImmutableArray<TScope>> FindByNamesAsync(
/// <returns>The scopes corresponding to the specified names.</returns>
public virtual IAsyncEnumerable<TScope> FindByNamesAsync(
ImmutableArray<string> names, CancellationToken cancellationToken)
{
if (names.Any(name => string.IsNullOrEmpty(name)))
@ -198,10 +193,18 @@ namespace OpenIddict.MongoDb
throw new ArgumentException("Scope names cannot be null or empty.", nameof(names));
}
var database = await Context.GetDatabaseAsync(cancellationToken);
var collection = database.GetCollection<TScope>(Options.CurrentValue.ScopesCollectionName);
return ExecuteAsync(cancellationToken);
return ImmutableArray.CreateRange(await collection.Find(scope => names.Contains(scope.Name)).ToListAsync(cancellationToken));
async IAsyncEnumerable<TScope> ExecuteAsync(CancellationToken cancellationToken)
{
var database = await Context.GetDatabaseAsync(cancellationToken);
var collection = database.GetCollection<TScope>(Options.CurrentValue.ScopesCollectionName);
await foreach (var scope in collection.Find(scope => names.Contains(scope.Name)).ToAsyncEnumerable(cancellationToken))
{
yield return scope;
}
}
}
/// <summary>
@ -209,11 +212,8 @@ namespace OpenIddict.MongoDb
/// </summary>
/// <param name="resource">The resource associated with the scopes.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the scopes associated with the specified resource.
/// </returns>
public virtual async Task<ImmutableArray<TScope>> FindByResourceAsync(
/// <returns>The scopes associated with the specified resource.</returns>
public virtual IAsyncEnumerable<TScope> FindByResourceAsync(
[NotNull] string resource, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(resource))
@ -221,11 +221,18 @@ namespace OpenIddict.MongoDb
throw new ArgumentException("The resource cannot be null or empty.", nameof(resource));
}
var database = await Context.GetDatabaseAsync(cancellationToken);
var collection = database.GetCollection<TScope>(Options.CurrentValue.ScopesCollectionName);
return ExecuteAsync(cancellationToken);
async IAsyncEnumerable<TScope> ExecuteAsync(CancellationToken cancellationToken)
{
var database = await Context.GetDatabaseAsync(cancellationToken);
var collection = database.GetCollection<TScope>(Options.CurrentValue.ScopesCollectionName);
return ImmutableArray.CreateRange(await collection.Find(scope =>
scope.Resources.Contains(resource)).ToListAsync(cancellationToken));
await foreach (var scope in collection.Find(scope => scope.Resources.Contains(resource)).ToAsyncEnumerable(cancellationToken))
{
yield return scope;
}
}
}
/// <summary>
@ -237,10 +244,10 @@ namespace OpenIddict.MongoDb
/// <param name="state">The optional state.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the first element returned when executing the query.
/// </returns>
public virtual async Task<TResult> GetAsync<TState, TResult>(
public virtual async ValueTask<TResult> GetAsync<TState, TResult>(
[NotNull] Func<IQueryable<TScope>, TState, IQueryable<TResult>> query,
[CanBeNull] TState state, CancellationToken cancellationToken)
{
@ -411,12 +418,9 @@ namespace OpenIddict.MongoDb
/// <param name="count">The number of results to return.</param>
/// <param name="offset">The number of results to skip.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the elements returned when executing the specified query.
/// </returns>
public virtual async Task<ImmutableArray<TScope>> ListAsync(
[CanBeNull] int? count, [CanBeNull] int? offset, CancellationToken cancellationToken)
/// <returns>All the elements returned when executing the specified query.</returns>
public virtual async IAsyncEnumerable<TScope> ListAsync(
[CanBeNull] int? count, [CanBeNull] int? offset, [EnumeratorCancellation] CancellationToken cancellationToken)
{
var database = await Context.GetDatabaseAsync(cancellationToken);
var collection = database.GetCollection<TScope>(Options.CurrentValue.ScopesCollectionName);
@ -433,7 +437,10 @@ namespace OpenIddict.MongoDb
query = query.Take(count.Value);
}
return ImmutableArray.CreateRange(await query.ToListAsync(cancellationToken));
await foreach (var scope in ((IAsyncCursorSource<TScope>) query).ToAsyncEnumerable(cancellationToken))
{
yield return scope;
}
}
/// <summary>
@ -444,11 +451,8 @@ namespace OpenIddict.MongoDb
/// <param name="query">The query to execute.</param>
/// <param name="state">The optional state.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the elements returned when executing the specified query.
/// </returns>
public virtual async Task<ImmutableArray<TResult>> ListAsync<TState, TResult>(
/// <returns>All the elements returned when executing the specified query.</returns>
public virtual IAsyncEnumerable<TResult> ListAsync<TState, TResult>(
[NotNull] Func<IQueryable<TScope>, TState, IQueryable<TResult>> query,
[CanBeNull] TState state, CancellationToken cancellationToken)
{
@ -457,11 +461,18 @@ namespace OpenIddict.MongoDb
throw new ArgumentNullException(nameof(query));
}
var database = await Context.GetDatabaseAsync(cancellationToken);
var collection = database.GetCollection<TScope>(Options.CurrentValue.ScopesCollectionName);
return ExecuteAsync(cancellationToken);
return ImmutableArray.CreateRange(
await ((IMongoQueryable<TResult>) query(collection.AsQueryable(), state)).ToListAsync(cancellationToken));
async IAsyncEnumerable<TResult> ExecuteAsync(CancellationToken cancellationToken)
{
var database = await Context.GetDatabaseAsync(cancellationToken);
var collection = database.GetCollection<TScope>(Options.CurrentValue.ScopesCollectionName);
await foreach (var element in query(collection.AsQueryable(), state).ToAsyncEnumerable(cancellationToken))
{
yield return element;
}
}
}
/// <summary>
@ -470,10 +481,8 @@ namespace OpenIddict.MongoDb
/// <param name="scope">The scope.</param>
/// <param name="description">The description associated with the authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetDescriptionAsync([NotNull] TScope scope, [CanBeNull] string description, CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetDescriptionAsync([NotNull] TScope scope, [CanBeNull] string description, CancellationToken cancellationToken)
{
if (scope == null)
{
@ -482,7 +491,7 @@ namespace OpenIddict.MongoDb
scope.Description = description;
return Task.CompletedTask;
return default;
}
/// <summary>
@ -491,10 +500,8 @@ namespace OpenIddict.MongoDb
/// <param name="scope">The scope.</param>
/// <param name="name">The display name associated with the scope.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetDisplayNameAsync([NotNull] TScope scope, [CanBeNull] string name, CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetDisplayNameAsync([NotNull] TScope scope, [CanBeNull] string name, CancellationToken cancellationToken)
{
if (scope == null)
{
@ -503,7 +510,7 @@ namespace OpenIddict.MongoDb
scope.DisplayName = name;
return Task.CompletedTask;
return default;
}
/// <summary>
@ -512,10 +519,8 @@ namespace OpenIddict.MongoDb
/// <param name="scope">The scope.</param>
/// <param name="name">The name associated with the authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetNameAsync([NotNull] TScope scope, [CanBeNull] string name, CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetNameAsync([NotNull] TScope scope, [CanBeNull] string name, CancellationToken cancellationToken)
{
if (scope == null)
{
@ -524,7 +529,7 @@ namespace OpenIddict.MongoDb
scope.Name = name;
return Task.CompletedTask;
return default;
}
/// <summary>
@ -533,10 +538,8 @@ namespace OpenIddict.MongoDb
/// <param name="scope">The scope.</param>
/// <param name="properties">The additional properties associated with the scope.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetPropertiesAsync([NotNull] TScope scope, [CanBeNull] JObject properties, CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetPropertiesAsync([NotNull] TScope scope, [CanBeNull] JObject properties, CancellationToken cancellationToken)
{
if (scope == null)
{
@ -547,12 +550,12 @@ namespace OpenIddict.MongoDb
{
scope.Properties = null;
return Task.CompletedTask;
return default;
}
scope.Properties = BsonDocument.Parse(properties.ToString(Formatting.None));
return Task.CompletedTask;
return default;
}
/// <summary>
@ -561,10 +564,8 @@ namespace OpenIddict.MongoDb
/// <param name="scope">The scope.</param>
/// <param name="resources">The resources associated with the scope.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetResourcesAsync([NotNull] TScope scope, ImmutableArray<string> resources, CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetResourcesAsync([NotNull] TScope scope, ImmutableArray<string> resources, CancellationToken cancellationToken)
{
if (scope == null)
{
@ -575,12 +576,12 @@ namespace OpenIddict.MongoDb
{
scope.Resources = null;
return Task.CompletedTask;
return default;
}
scope.Resources = resources.ToArray();
return Task.CompletedTask;
return default;
}
/// <summary>
@ -588,10 +589,8 @@ namespace OpenIddict.MongoDb
/// </summary>
/// <param name="scope">The scope to update.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual async Task UpdateAsync([NotNull] TScope scope, CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual async ValueTask UpdateAsync([NotNull] TScope scope, CancellationToken cancellationToken)
{
if (scope == null)
{

311
src/OpenIddict.MongoDb/Stores/OpenIddictTokenStore.cs

@ -5,8 +5,10 @@
*/
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
@ -52,10 +54,10 @@ namespace OpenIddict.MongoDb
/// </summary>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the number of applications in the database.
/// </returns>
public virtual async Task<long> CountAsync(CancellationToken cancellationToken)
public virtual async ValueTask<long> CountAsync(CancellationToken cancellationToken)
{
var database = await Context.GetDatabaseAsync(cancellationToken);
var collection = database.GetCollection<TToken>(Options.CurrentValue.TokensCollectionName);
@ -70,10 +72,10 @@ namespace OpenIddict.MongoDb
/// <param name="query">The query to execute.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the number of tokens that match the specified query.
/// </returns>
public virtual async Task<long> CountAsync<TResult>(
public virtual async ValueTask<long> CountAsync<TResult>(
[NotNull] Func<IQueryable<TToken>, IQueryable<TResult>> query, CancellationToken cancellationToken)
{
if (query == null)
@ -92,10 +94,8 @@ namespace OpenIddict.MongoDb
/// </summary>
/// <param name="token">The token to create.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual async Task CreateAsync([NotNull] TToken token, CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual async ValueTask CreateAsync([NotNull] TToken token, CancellationToken cancellationToken)
{
if (token == null)
{
@ -113,10 +113,8 @@ namespace OpenIddict.MongoDb
/// </summary>
/// <param name="token">The token to delete.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual async Task DeleteAsync([NotNull] TToken token, CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual async ValueTask DeleteAsync([NotNull] TToken token, CancellationToken cancellationToken)
{
if (token == null)
{
@ -144,11 +142,8 @@ namespace OpenIddict.MongoDb
/// <param name="subject">The subject associated with the token.</param>
/// <param name="client">The client associated with the token.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the tokens corresponding to the subject/client.
/// </returns>
public virtual async Task<ImmutableArray<TToken>> FindAsync([NotNull] string subject,
/// <returns>The tokens corresponding to the subject/client.</returns>
public virtual IAsyncEnumerable<TToken> FindAsync([NotNull] string subject,
[NotNull] string client, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(subject))
@ -161,12 +156,20 @@ namespace OpenIddict.MongoDb
throw new ArgumentException("The client cannot be null or empty.", nameof(client));
}
var database = await Context.GetDatabaseAsync(cancellationToken);
var collection = database.GetCollection<TToken>(Options.CurrentValue.TokensCollectionName);
return ExecuteAsync(cancellationToken);
return ImmutableArray.CreateRange(await collection.Find(token =>
token.ApplicationId == ObjectId.Parse(client) &&
token.Subject == subject).ToListAsync(cancellationToken));
async IAsyncEnumerable<TToken> ExecuteAsync(CancellationToken cancellationToken)
{
var database = await Context.GetDatabaseAsync(cancellationToken);
var collection = database.GetCollection<TToken>(Options.CurrentValue.TokensCollectionName);
await foreach (var token in collection.Find(token =>
token.ApplicationId == ObjectId.Parse(client) &&
token.Subject == subject).ToAsyncEnumerable(cancellationToken))
{
yield return token;
}
}
}
/// <summary>
@ -176,11 +179,8 @@ namespace OpenIddict.MongoDb
/// <param name="client">The client associated with the token.</param>
/// <param name="status">The token status.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the tokens corresponding to the criteria.
/// </returns>
public virtual async Task<ImmutableArray<TToken>> FindAsync(
/// <returns>The tokens corresponding to the criteria.</returns>
public virtual IAsyncEnumerable<TToken> FindAsync(
[NotNull] string subject, [NotNull] string client,
[NotNull] string status, CancellationToken cancellationToken)
{
@ -199,13 +199,21 @@ namespace OpenIddict.MongoDb
throw new ArgumentException("The status cannot be null or empty.", nameof(status));
}
var database = await Context.GetDatabaseAsync(cancellationToken);
var collection = database.GetCollection<TToken>(Options.CurrentValue.TokensCollectionName);
return ExecuteAsync(cancellationToken);
async IAsyncEnumerable<TToken> ExecuteAsync(CancellationToken cancellationToken)
{
var database = await Context.GetDatabaseAsync(cancellationToken);
var collection = database.GetCollection<TToken>(Options.CurrentValue.TokensCollectionName);
return ImmutableArray.CreateRange(await collection.Find(token =>
token.ApplicationId == ObjectId.Parse(client) &&
token.Subject == subject &&
token.Status == status).ToListAsync(cancellationToken));
await foreach (var token in collection.Find(token =>
token.ApplicationId == ObjectId.Parse(client) &&
token.Subject == subject &&
token.Status == status).ToAsyncEnumerable(cancellationToken))
{
yield return token;
}
}
}
/// <summary>
@ -216,11 +224,8 @@ namespace OpenIddict.MongoDb
/// <param name="status">The token status.</param>
/// <param name="type">The token type.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the tokens corresponding to the criteria.
/// </returns>
public virtual async Task<ImmutableArray<TToken>> FindAsync(
/// <returns>The tokens corresponding to the criteria.</returns>
public virtual IAsyncEnumerable<TToken> FindAsync(
[NotNull] string subject, [NotNull] string client,
[NotNull] string status, [NotNull] string type, CancellationToken cancellationToken)
{
@ -244,14 +249,22 @@ namespace OpenIddict.MongoDb
throw new ArgumentException("The type cannot be null or empty.", nameof(type));
}
var database = await Context.GetDatabaseAsync(cancellationToken);
var collection = database.GetCollection<TToken>(Options.CurrentValue.TokensCollectionName);
return ExecuteAsync(cancellationToken);
async IAsyncEnumerable<TToken> ExecuteAsync(CancellationToken cancellationToken)
{
var database = await Context.GetDatabaseAsync(cancellationToken);
var collection = database.GetCollection<TToken>(Options.CurrentValue.TokensCollectionName);
return ImmutableArray.CreateRange(await collection.Find(token =>
token.ApplicationId == ObjectId.Parse(client) &&
token.Subject == subject &&
token.Status == status &&
token.Type == type).ToListAsync(cancellationToken));
await foreach (var token in collection.Find(token =>
token.ApplicationId == ObjectId.Parse(client) &&
token.Subject == subject &&
token.Status == status &&
token.Type == type).ToAsyncEnumerable(cancellationToken))
{
yield return token;
}
}
}
/// <summary>
@ -259,11 +272,8 @@ namespace OpenIddict.MongoDb
/// </summary>
/// <param name="identifier">The application identifier associated with the tokens.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the tokens corresponding to the specified application.
/// </returns>
public virtual async Task<ImmutableArray<TToken>> FindByApplicationIdAsync(
/// <returns>The tokens corresponding to the specified application.</returns>
public virtual IAsyncEnumerable<TToken> FindByApplicationIdAsync(
[NotNull] string identifier, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(identifier))
@ -271,11 +281,19 @@ namespace OpenIddict.MongoDb
throw new ArgumentException("The identifier cannot be null or empty.", nameof(identifier));
}
var database = await Context.GetDatabaseAsync(cancellationToken);
var collection = database.GetCollection<TToken>(Options.CurrentValue.TokensCollectionName);
return ExecuteAsync(cancellationToken);
async IAsyncEnumerable<TToken> ExecuteAsync(CancellationToken cancellationToken)
{
var database = await Context.GetDatabaseAsync(cancellationToken);
var collection = database.GetCollection<TToken>(Options.CurrentValue.TokensCollectionName);
return ImmutableArray.CreateRange(await collection.Find(token =>
token.ApplicationId == ObjectId.Parse(identifier)).ToListAsync(cancellationToken));
await foreach (var token in collection.Find(token =>
token.ApplicationId == ObjectId.Parse(identifier)).ToAsyncEnumerable(cancellationToken))
{
yield return token;
}
}
}
/// <summary>
@ -283,11 +301,8 @@ namespace OpenIddict.MongoDb
/// </summary>
/// <param name="identifier">The authorization identifier associated with the tokens.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the tokens corresponding to the specified authorization.
/// </returns>
public virtual async Task<ImmutableArray<TToken>> FindByAuthorizationIdAsync(
/// <returns>The tokens corresponding to the specified authorization.</returns>
public virtual IAsyncEnumerable<TToken> FindByAuthorizationIdAsync(
[NotNull] string identifier, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(identifier))
@ -295,10 +310,19 @@ namespace OpenIddict.MongoDb
throw new ArgumentException("The identifier cannot be null or empty.", nameof(identifier));
}
var database = await Context.GetDatabaseAsync(cancellationToken);
var collection = database.GetCollection<TToken>(Options.CurrentValue.TokensCollectionName);
return ExecuteAsync(cancellationToken);
return ImmutableArray.CreateRange(await collection.Find(token => token.AuthorizationId == ObjectId.Parse(identifier)).ToListAsync(cancellationToken));
async IAsyncEnumerable<TToken> ExecuteAsync(CancellationToken cancellationToken)
{
var database = await Context.GetDatabaseAsync(cancellationToken);
var collection = database.GetCollection<TToken>(Options.CurrentValue.TokensCollectionName);
await foreach (var token in collection.Find(token =>
token.AuthorizationId == ObjectId.Parse(identifier)).ToAsyncEnumerable(cancellationToken))
{
yield return token;
}
}
}
/// <summary>
@ -307,10 +331,10 @@ namespace OpenIddict.MongoDb
/// <param name="identifier">The unique identifier associated with the token.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the token corresponding to the unique identifier.
/// </returns>
public virtual async Task<TToken> FindByIdAsync([NotNull] string identifier, CancellationToken cancellationToken)
public virtual async ValueTask<TToken> FindByIdAsync([NotNull] string identifier, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(identifier))
{
@ -330,10 +354,10 @@ namespace OpenIddict.MongoDb
/// <param name="identifier">The reference identifier associated with the tokens.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the tokens corresponding to the specified reference identifier.
/// </returns>
public virtual async Task<TToken> FindByReferenceIdAsync([NotNull] string identifier, CancellationToken cancellationToken)
public virtual async ValueTask<TToken> FindByReferenceIdAsync([NotNull] string identifier, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(identifier))
{
@ -351,21 +375,26 @@ namespace OpenIddict.MongoDb
/// </summary>
/// <param name="subject">The subject associated with the tokens.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the tokens corresponding to the specified subject.
/// </returns>
public virtual async Task<ImmutableArray<TToken>> FindBySubjectAsync([NotNull] string subject, CancellationToken cancellationToken)
/// <returns>The tokens corresponding to the specified subject.</returns>
public virtual IAsyncEnumerable<TToken> FindBySubjectAsync([NotNull] string subject, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(subject))
{
throw new ArgumentException("The subject cannot be null or empty.", nameof(subject));
}
var database = await Context.GetDatabaseAsync(cancellationToken);
var collection = database.GetCollection<TToken>(Options.CurrentValue.TokensCollectionName);
return ExecuteAsync(cancellationToken);
return ImmutableArray.CreateRange(await collection.Find(token => token.Subject == subject).ToListAsync(cancellationToken));
async IAsyncEnumerable<TToken> ExecuteAsync(CancellationToken cancellationToken)
{
var database = await Context.GetDatabaseAsync(cancellationToken);
var collection = database.GetCollection<TToken>(Options.CurrentValue.TokensCollectionName);
await foreach (var token in collection.Find(token => token.Subject == subject).ToAsyncEnumerable(cancellationToken))
{
yield return token;
}
}
}
/// <summary>
@ -396,10 +425,10 @@ namespace OpenIddict.MongoDb
/// <param name="state">The optional state.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the first element returned when executing the query.
/// </returns>
public virtual async Task<TResult> GetAsync<TState, TResult>(
public virtual async ValueTask<TResult> GetAsync<TState, TResult>(
[NotNull] Func<IQueryable<TToken>, TState, IQueryable<TResult>> query,
[CanBeNull] TState state, CancellationToken cancellationToken)
{
@ -643,12 +672,9 @@ namespace OpenIddict.MongoDb
/// <param name="count">The number of results to return.</param>
/// <param name="offset">The number of results to skip.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the elements returned when executing the specified query.
/// </returns>
public virtual async Task<ImmutableArray<TToken>> ListAsync(
[CanBeNull] int? count, [CanBeNull] int? offset, CancellationToken cancellationToken)
/// <returns>All the elements returned when executing the specified query.</returns>
public virtual async IAsyncEnumerable<TToken> ListAsync(
[CanBeNull] int? count, [CanBeNull] int? offset, [EnumeratorCancellation] CancellationToken cancellationToken)
{
var database = await Context.GetDatabaseAsync(cancellationToken);
var collection = database.GetCollection<TToken>(Options.CurrentValue.TokensCollectionName);
@ -665,7 +691,10 @@ namespace OpenIddict.MongoDb
query = query.Take(count.Value);
}
return ImmutableArray.CreateRange(await query.ToListAsync(cancellationToken));
await foreach (var token in ((IAsyncCursorSource<TToken>) query).ToAsyncEnumerable(cancellationToken))
{
yield return token;
}
}
/// <summary>
@ -676,11 +705,8 @@ namespace OpenIddict.MongoDb
/// <param name="query">The query to execute.</param>
/// <param name="state">The optional state.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the elements returned when executing the specified query.
/// </returns>
public virtual async Task<ImmutableArray<TResult>> ListAsync<TState, TResult>(
/// <returns>All the elements returned when executing the specified query.</returns>
public virtual IAsyncEnumerable<TResult> ListAsync<TState, TResult>(
[NotNull] Func<IQueryable<TToken>, TState, IQueryable<TResult>> query,
[CanBeNull] TState state, CancellationToken cancellationToken)
{
@ -689,21 +715,26 @@ namespace OpenIddict.MongoDb
throw new ArgumentNullException(nameof(query));
}
var database = await Context.GetDatabaseAsync(cancellationToken);
var collection = database.GetCollection<TToken>(Options.CurrentValue.TokensCollectionName);
return ExecuteAsync(cancellationToken);
async IAsyncEnumerable<TResult> ExecuteAsync(CancellationToken cancellationToken)
{
var database = await Context.GetDatabaseAsync(cancellationToken);
var collection = database.GetCollection<TToken>(Options.CurrentValue.TokensCollectionName);
return ImmutableArray.CreateRange(
await ((IMongoQueryable<TResult>) query(collection.AsQueryable(), state)).ToListAsync(cancellationToken));
await foreach (var element in query(collection.AsQueryable(), state).ToAsyncEnumerable(cancellationToken))
{
yield return element;
}
}
}
/// <summary>
/// Removes the tokens that are marked as expired or invalid.
/// </summary>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual async Task PruneAsync(CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual async ValueTask PruneAsync(CancellationToken cancellationToken)
{
var database = await Context.GetDatabaseAsync(cancellationToken);
var collection = database.GetCollection<TToken>(Options.CurrentValue.TokensCollectionName);
@ -718,10 +749,8 @@ namespace OpenIddict.MongoDb
/// <param name="token">The token.</param>
/// <param name="identifier">The unique identifier associated with the client application.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetApplicationIdAsync([NotNull] TToken token,
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetApplicationIdAsync([NotNull] TToken token,
[CanBeNull] string identifier, CancellationToken cancellationToken)
{
if (token == null)
@ -739,7 +768,7 @@ namespace OpenIddict.MongoDb
token.ApplicationId = ObjectId.Empty;
}
return Task.CompletedTask;
return default;
}
/// <summary>
@ -748,10 +777,8 @@ namespace OpenIddict.MongoDb
/// <param name="token">The token.</param>
/// <param name="identifier">The unique identifier associated with the authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetAuthorizationIdAsync([NotNull] TToken token,
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetAuthorizationIdAsync([NotNull] TToken token,
[CanBeNull] string identifier, CancellationToken cancellationToken)
{
if (token == null)
@ -769,7 +796,7 @@ namespace OpenIddict.MongoDb
token.AuthorizationId = ObjectId.Empty;
}
return Task.CompletedTask;
return default;
}
/// <summary>
@ -778,10 +805,8 @@ namespace OpenIddict.MongoDb
/// <param name="token">The token.</param>
/// <param name="date">The creation date.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetCreationDateAsync([NotNull] TToken token,
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetCreationDateAsync([NotNull] TToken token,
[CanBeNull] DateTimeOffset? date, CancellationToken cancellationToken)
{
if (token == null)
@ -791,7 +816,7 @@ namespace OpenIddict.MongoDb
token.CreationDate = date?.UtcDateTime;
return Task.CompletedTask;
return default;
}
/// <summary>
@ -800,10 +825,8 @@ namespace OpenIddict.MongoDb
/// <param name="token">The token.</param>
/// <param name="date">The expiration date.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetExpirationDateAsync([NotNull] TToken token,
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetExpirationDateAsync([NotNull] TToken token,
[CanBeNull] DateTimeOffset? date, CancellationToken cancellationToken)
{
if (token == null)
@ -813,7 +836,7 @@ namespace OpenIddict.MongoDb
token.ExpirationDate = date?.UtcDateTime;
return Task.CompletedTask;
return default;
}
/// <summary>
@ -822,10 +845,8 @@ namespace OpenIddict.MongoDb
/// <param name="token">The token.</param>
/// <param name="payload">The payload associated with the token.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetPayloadAsync([NotNull] TToken token, [CanBeNull] string payload, CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetPayloadAsync([NotNull] TToken token, [CanBeNull] string payload, CancellationToken cancellationToken)
{
if (token == null)
{
@ -834,7 +855,7 @@ namespace OpenIddict.MongoDb
token.Payload = payload;
return Task.CompletedTask;
return default;
}
/// <summary>
@ -843,10 +864,8 @@ namespace OpenIddict.MongoDb
/// <param name="token">The token.</param>
/// <param name="properties">The additional properties associated with the token.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetPropertiesAsync([NotNull] TToken token, [CanBeNull] JObject properties, CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetPropertiesAsync([NotNull] TToken token, [CanBeNull] JObject properties, CancellationToken cancellationToken)
{
if (token == null)
{
@ -857,12 +876,12 @@ namespace OpenIddict.MongoDb
{
token.Properties = null;
return Task.CompletedTask;
return default;
}
token.Properties = BsonDocument.Parse(properties.ToString(Formatting.None));
return Task.CompletedTask;
return default;
}
/// <summary>
@ -873,10 +892,8 @@ namespace OpenIddict.MongoDb
/// <param name="token">The token.</param>
/// <param name="identifier">The reference identifier associated with the token.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetReferenceIdAsync([NotNull] TToken token, [CanBeNull] string identifier, CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetReferenceIdAsync([NotNull] TToken token, [CanBeNull] string identifier, CancellationToken cancellationToken)
{
if (token == null)
{
@ -885,7 +902,7 @@ namespace OpenIddict.MongoDb
token.ReferenceId = identifier;
return Task.CompletedTask;
return default;
}
/// <summary>
@ -894,10 +911,8 @@ namespace OpenIddict.MongoDb
/// <param name="token">The token.</param>
/// <param name="status">The status associated with the authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetStatusAsync([NotNull] TToken token, [CanBeNull] string status, CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetStatusAsync([NotNull] TToken token, [CanBeNull] string status, CancellationToken cancellationToken)
{
if (token == null)
{
@ -906,7 +921,7 @@ namespace OpenIddict.MongoDb
token.Status = status;
return Task.CompletedTask;
return default;
}
/// <summary>
@ -915,10 +930,8 @@ namespace OpenIddict.MongoDb
/// <param name="token">The token.</param>
/// <param name="subject">The subject associated with the token.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetSubjectAsync([NotNull] TToken token, [CanBeNull] string subject, CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetSubjectAsync([NotNull] TToken token, [CanBeNull] string subject, CancellationToken cancellationToken)
{
if (token == null)
{
@ -927,7 +940,7 @@ namespace OpenIddict.MongoDb
token.Subject = subject;
return Task.CompletedTask;
return default;
}
/// <summary>
@ -936,10 +949,8 @@ namespace OpenIddict.MongoDb
/// <param name="token">The token.</param>
/// <param name="type">The token type associated with the token.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetTypeAsync([NotNull] TToken token, [CanBeNull] string type, CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetTypeAsync([NotNull] TToken token, [CanBeNull] string type, CancellationToken cancellationToken)
{
if (token == null)
{
@ -948,7 +959,7 @@ namespace OpenIddict.MongoDb
token.Type = type;
return Task.CompletedTask;
return default;
}
/// <summary>
@ -956,10 +967,8 @@ namespace OpenIddict.MongoDb
/// </summary>
/// <param name="token">The token to update.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual async Task UpdateAsync([NotNull] TToken token, CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual async ValueTask UpdateAsync([NotNull] TToken token, CancellationToken cancellationToken)
{
if (token == null)
{

31
src/OpenIddict.NHibernate/OpenIddictNHibernateHelpers.cs

@ -5,7 +5,11 @@
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using JetBrains.Annotations;
using NHibernate.Linq;
using NHibernate.Mapping.ByCode;
using OpenIddict.NHibernate;
using OpenIddict.NHibernate.Models;
@ -13,7 +17,7 @@ using OpenIddict.NHibernate.Models;
namespace NHibernate.Cfg
{
/// <summary>
/// Exposes extensions allowing to register the OpenIddict NHibernate mappings.
/// Exposes extensions simplifying the integration between OpenIddict and NHibernate.
/// </summary>
public static class OpenIddictNHibernateHelpers
{
@ -70,5 +74,30 @@ namespace NHibernate.Cfg
return configuration;
}
/// <summary>
/// Executes the query and returns the results as a non-streamed async enumeration.
/// </summary>
/// <typeparam name="T">The type of the returned entities.</typeparam>
/// <param name="source">The query source.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>The non-streamed async enumeration containing the results.</returns>
internal static IAsyncEnumerable<T> AsAsyncEnumerable<T>([NotNull] this IQueryable<T> source, CancellationToken cancellationToken)
{
if (source == null)
{
throw new ArgumentNullException(nameof(source));
}
return ExecuteAsync(cancellationToken);
async IAsyncEnumerable<T> ExecuteAsync(CancellationToken cancellationToken)
{
foreach (var element in await source.ToListAsync(cancellationToken))
{
yield return element;
}
}
}
}
}

259
src/OpenIddict.NHibernate/Stores/OpenIddictApplicationStore.cs

@ -5,9 +5,11 @@
*/
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
@ -17,6 +19,7 @@ using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using NHibernate;
using NHibernate.Cfg;
using NHibernate.Linq;
using OpenIddict.Abstractions;
using OpenIddict.NHibernate.Models;
@ -100,10 +103,10 @@ namespace OpenIddict.NHibernate
/// </summary>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the number of applications in the database.
/// </returns>
public virtual async Task<long> CountAsync(CancellationToken cancellationToken)
public virtual async ValueTask<long> CountAsync(CancellationToken cancellationToken)
{
var session = await Context.GetSessionAsync(cancellationToken);
return await session.Query<TApplication>().LongCountAsync(cancellationToken);
@ -116,10 +119,10 @@ namespace OpenIddict.NHibernate
/// <param name="query">The query to execute.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the number of applications that match the specified query.
/// </returns>
public virtual async Task<long> CountAsync<TResult>([NotNull] Func<IQueryable<TApplication>, IQueryable<TResult>> query, CancellationToken cancellationToken)
public virtual async ValueTask<long> CountAsync<TResult>([NotNull] Func<IQueryable<TApplication>, IQueryable<TResult>> query, CancellationToken cancellationToken)
{
if (query == null)
{
@ -135,10 +138,8 @@ namespace OpenIddict.NHibernate
/// </summary>
/// <param name="application">The application to create.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual async Task CreateAsync([NotNull] TApplication application, CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual async ValueTask CreateAsync([NotNull] TApplication application, CancellationToken cancellationToken)
{
if (application == null)
{
@ -155,10 +156,8 @@ namespace OpenIddict.NHibernate
/// </summary>
/// <param name="application">The application to delete.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual async Task DeleteAsync([NotNull] TApplication application, CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual async ValueTask DeleteAsync([NotNull] TApplication application, CancellationToken cancellationToken)
{
if (application == null)
{
@ -171,13 +170,13 @@ namespace OpenIddict.NHibernate
{
// Delete all the tokens associated with the application.
await (from authorization in session.Query<TAuthorization>()
where authorization.Application.Id.Equals(application.Id)
select authorization).DeleteAsync(cancellationToken);
where authorization.Application.Id.Equals(application.Id)
select authorization).DeleteAsync(cancellationToken);
// Delete all the tokens associated with the application.
await (from token in session.Query<TToken>()
where token.Application.Id.Equals(application.Id)
select token).DeleteAsync(cancellationToken);
where token.Application.Id.Equals(application.Id)
select token).DeleteAsync(cancellationToken);
await session.DeleteAsync(application, cancellationToken);
await session.FlushAsync(cancellationToken);
@ -198,10 +197,10 @@ namespace OpenIddict.NHibernate
/// <param name="identifier">The client identifier associated with the application.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the client application corresponding to the identifier.
/// </returns>
public virtual async Task<TApplication> FindByClientIdAsync([NotNull] string identifier, CancellationToken cancellationToken)
public virtual async ValueTask<TApplication> FindByClientIdAsync([NotNull] string identifier, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(identifier))
{
@ -221,10 +220,10 @@ namespace OpenIddict.NHibernate
/// <param name="identifier">The unique identifier associated with the application.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the client application corresponding to the identifier.
/// </returns>
public virtual async Task<TApplication> FindByIdAsync([NotNull] string identifier, CancellationToken cancellationToken)
public virtual async ValueTask<TApplication> FindByIdAsync([NotNull] string identifier, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(identifier))
{
@ -240,48 +239,34 @@ namespace OpenIddict.NHibernate
/// </summary>
/// <param name="address">The post_logout_redirect_uri associated with the applications.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation, whose result
/// returns the client applications corresponding to the specified post_logout_redirect_uri.
/// </returns>
public virtual async Task<ImmutableArray<TApplication>> FindByPostLogoutRedirectUriAsync([NotNull] string address, CancellationToken cancellationToken)
/// <returns>The client applications corresponding to the specified post_logout_redirect_uri.</returns>
public virtual IAsyncEnumerable<TApplication> FindByPostLogoutRedirectUriAsync([NotNull] string address, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(address))
{
throw new ArgumentException("The address cannot be null or empty.", nameof(address));
}
var session = await Context.GetSessionAsync(cancellationToken);
// To optimize the efficiency of the query a bit, only applications whose stringified
// PostLogoutRedirectUris contains the specified URL are returned. Once the applications
// are retrieved, a second pass is made to ensure only valid elements are returned.
// Implementers that use this method in a hot path may want to override this method
// to use SQL Server 2016 functions like JSON_VALUE to make the query more efficient.
var applications = await (from application in session.Query<TApplication>()
where application.PostLogoutRedirectUris.Contains(address)
select application).ToListAsync(cancellationToken);
var builder = ImmutableArray.CreateBuilder<TApplication>();
return ExecuteAsync(cancellationToken);
foreach (var application in applications)
async IAsyncEnumerable<TApplication> ExecuteAsync(CancellationToken cancellationToken)
{
foreach (var uri in await GetPostLogoutRedirectUrisAsync(application, cancellationToken))
var session = await Context.GetSessionAsync(cancellationToken);
// To optimize the efficiency of the query a bit, only applications whose stringified
// PostLogoutRedirectUris contains the specified URL are returned. Once the applications
// are retrieved, a second pass is made to ensure only valid elements are returned.
// Implementers that use this method in a hot path may want to override this method
// to use SQL Server 2016 functions like JSON_VALUE to make the query more efficient.
await foreach (var application in session.Query<TApplication>()
.Where(application => application.PostLogoutRedirectUris.Contains(address))
.AsAsyncEnumerable(cancellationToken)
.WhereAwait(async application => (await GetPostLogoutRedirectUrisAsync(application, cancellationToken))
.Contains(address, StringComparer.Ordinal)))
{
// Note: the post_logout_redirect_uri must be compared
// using case-sensitive "Simple String Comparison".
if (string.Equals(uri, address, StringComparison.Ordinal))
{
builder.Add(application);
break;
}
yield return application;
}
}
return builder.Count == builder.Capacity ?
builder.MoveToImmutable() :
builder.ToImmutable();
}
/// <summary>
@ -289,48 +274,34 @@ namespace OpenIddict.NHibernate
/// </summary>
/// <param name="address">The redirect_uri associated with the applications.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation, whose result
/// returns the client applications corresponding to the specified redirect_uri.
/// </returns>
public virtual async Task<ImmutableArray<TApplication>> FindByRedirectUriAsync([NotNull] string address, CancellationToken cancellationToken)
/// <returns>The client applications corresponding to the specified redirect_uri.</returns>
public virtual IAsyncEnumerable<TApplication> FindByRedirectUriAsync([NotNull] string address, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(address))
{
throw new ArgumentException("The address cannot be null or empty.", nameof(address));
}
var session = await Context.GetSessionAsync(cancellationToken);
// To optimize the efficiency of the query a bit, only applications whose stringified
// RedirectUris property contains the specified URL are returned. Once the applications
// are retrieved, a second pass is made to ensure only valid elements are returned.
// Implementers that use this method in a hot path may want to override this method
// to use SQL Server 2016 functions like JSON_VALUE to make the query more efficient.
var applications = await (from application in session.Query<TApplication>()
where application.RedirectUris.Contains(address)
select application).ToListAsync(cancellationToken);
var builder = ImmutableArray.CreateBuilder<TApplication>();
return ExecuteAsync(cancellationToken);
foreach (var application in applications)
async IAsyncEnumerable<TApplication> ExecuteAsync(CancellationToken cancellationToken)
{
foreach (var uri in await GetRedirectUrisAsync(application, cancellationToken))
var session = await Context.GetSessionAsync(cancellationToken);
// To optimize the efficiency of the query a bit, only applications whose stringified
// RedirectUris contains the specified URL are returned. Once the applications
// are retrieved, a second pass is made to ensure only valid elements are returned.
// Implementers that use this method in a hot path may want to override this method
// to use SQL Server 2016 functions like JSON_VALUE to make the query more efficient.
await foreach (var application in session.Query<TApplication>()
.Where(application => application.RedirectUris.Contains(address))
.AsAsyncEnumerable(cancellationToken)
.WhereAwait(async application => (await GetRedirectUrisAsync(application, cancellationToken))
.Contains(address, StringComparer.Ordinal)))
{
// Note: the redirect_uri must be compared using case-sensitive "Simple String Comparison".
// See http://openid.net/specs/openid-connect-core-1_0.html#AuthRequest for more information.
if (string.Equals(uri, address, StringComparison.Ordinal))
{
builder.Add(application);
break;
}
yield return application;
}
}
return builder.Count == builder.Capacity ?
builder.MoveToImmutable() :
builder.ToImmutable();
}
/// <summary>
@ -342,10 +313,10 @@ namespace OpenIddict.NHibernate
/// <param name="state">The optional state.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the first element returned when executing the query.
/// </returns>
public virtual async Task<TResult> GetAsync<TState, TResult>(
public virtual async ValueTask<TResult> GetAsync<TState, TResult>(
[NotNull] Func<IQueryable<TApplication>, TState, IQueryable<TResult>> query,
[CanBeNull] TState state, CancellationToken cancellationToken)
{
@ -641,12 +612,9 @@ namespace OpenIddict.NHibernate
/// <param name="count">The number of results to return.</param>
/// <param name="offset">The number of results to skip.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the elements returned when executing the specified query.
/// </returns>
public virtual async Task<ImmutableArray<TApplication>> ListAsync(
[CanBeNull] int? count, [CanBeNull] int? offset, CancellationToken cancellationToken)
/// <returns>All the elements returned when executing the specified query.</returns>
public virtual async IAsyncEnumerable<TApplication> ListAsync(
[CanBeNull] int? count, [CanBeNull] int? offset, [EnumeratorCancellation] CancellationToken cancellationToken)
{
var session = await Context.GetSessionAsync(cancellationToken);
var query = session.Query<TApplication>()
@ -663,7 +631,10 @@ namespace OpenIddict.NHibernate
query = query.Take(count.Value);
}
return ImmutableArray.CreateRange(await query.ToListAsync(cancellationToken));
await foreach (var application in query.AsAsyncEnumerable(cancellationToken))
{
yield return application;
}
}
/// <summary>
@ -674,11 +645,8 @@ namespace OpenIddict.NHibernate
/// <param name="query">The query to execute.</param>
/// <param name="state">The optional state.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the elements returned when executing the specified query.
/// </returns>
public virtual async Task<ImmutableArray<TResult>> ListAsync<TState, TResult>(
/// <returns>All the elements returned when executing the specified query.</returns>
public virtual IAsyncEnumerable<TResult> ListAsync<TState, TResult>(
[NotNull] Func<IQueryable<TApplication>, TState, IQueryable<TResult>> query,
[CanBeNull] TState state, CancellationToken cancellationToken)
{
@ -687,8 +655,17 @@ namespace OpenIddict.NHibernate
throw new ArgumentNullException(nameof(query));
}
var session = await Context.GetSessionAsync(cancellationToken);
return ImmutableArray.CreateRange(await query(session.Query<TApplication>(), state).ToListAsync(cancellationToken));
return ExecuteAsync(cancellationToken);
async IAsyncEnumerable<TResult> ExecuteAsync(CancellationToken cancellationToken)
{
var session = await Context.GetSessionAsync(cancellationToken);
await foreach (var element in query(session.Query<TApplication>(), state).AsAsyncEnumerable(cancellationToken))
{
yield return element;
}
}
}
/// <summary>
@ -697,10 +674,8 @@ namespace OpenIddict.NHibernate
/// <param name="application">The application.</param>
/// <param name="identifier">The client identifier associated with the application.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetClientIdAsync([NotNull] TApplication application,
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetClientIdAsync([NotNull] TApplication application,
[CanBeNull] string identifier, CancellationToken cancellationToken)
{
if (application == null)
@ -710,7 +685,7 @@ namespace OpenIddict.NHibernate
application.ClientId = identifier;
return Task.CompletedTask;
return default;
}
/// <summary>
@ -721,10 +696,8 @@ namespace OpenIddict.NHibernate
/// <param name="application">The application.</param>
/// <param name="secret">The client secret associated with the application.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetClientSecretAsync([NotNull] TApplication application,
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetClientSecretAsync([NotNull] TApplication application,
[CanBeNull] string secret, CancellationToken cancellationToken)
{
if (application == null)
@ -734,7 +707,7 @@ namespace OpenIddict.NHibernate
application.ClientSecret = secret;
return Task.CompletedTask;
return default;
}
/// <summary>
@ -743,10 +716,8 @@ namespace OpenIddict.NHibernate
/// <param name="application">The application.</param>
/// <param name="type">The client type associated with the application.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetClientTypeAsync([NotNull] TApplication application,
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetClientTypeAsync([NotNull] TApplication application,
[CanBeNull] string type, CancellationToken cancellationToken)
{
if (application == null)
@ -756,7 +727,7 @@ namespace OpenIddict.NHibernate
application.Type = type;
return Task.CompletedTask;
return default;
}
/// <summary>
@ -765,10 +736,8 @@ namespace OpenIddict.NHibernate
/// <param name="application">The application.</param>
/// <param name="type">The consent type associated with the application.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetConsentTypeAsync([NotNull] TApplication application,
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetConsentTypeAsync([NotNull] TApplication application,
[CanBeNull] string type, CancellationToken cancellationToken)
{
if (application == null)
@ -778,7 +747,7 @@ namespace OpenIddict.NHibernate
application.ConsentType = type;
return Task.CompletedTask;
return default;
}
/// <summary>
@ -787,10 +756,8 @@ namespace OpenIddict.NHibernate
/// <param name="application">The application.</param>
/// <param name="name">The display name associated with the application.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetDisplayNameAsync([NotNull] TApplication application,
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetDisplayNameAsync([NotNull] TApplication application,
[CanBeNull] string name, CancellationToken cancellationToken)
{
if (application == null)
@ -800,7 +767,7 @@ namespace OpenIddict.NHibernate
application.DisplayName = name;
return Task.CompletedTask;
return default;
}
/// <summary>
@ -809,10 +776,8 @@ namespace OpenIddict.NHibernate
/// <param name="application">The application.</param>
/// <param name="permissions">The permissions associated with the application </param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetPermissionsAsync([NotNull] TApplication application, ImmutableArray<string> permissions, CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetPermissionsAsync([NotNull] TApplication application, ImmutableArray<string> permissions, CancellationToken cancellationToken)
{
if (application == null)
{
@ -823,12 +788,12 @@ namespace OpenIddict.NHibernate
{
application.Permissions = null;
return Task.CompletedTask;
return default;
}
application.Permissions = new JArray(permissions.ToArray()).ToString(Formatting.None);
return Task.CompletedTask;
return default;
}
/// <summary>
@ -837,10 +802,8 @@ namespace OpenIddict.NHibernate
/// <param name="application">The application.</param>
/// <param name="addresses">The logout callback addresses associated with the application </param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetPostLogoutRedirectUrisAsync([NotNull] TApplication application,
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetPostLogoutRedirectUrisAsync([NotNull] TApplication application,
ImmutableArray<string> addresses, CancellationToken cancellationToken)
{
if (application == null)
@ -852,12 +815,12 @@ namespace OpenIddict.NHibernate
{
application.PostLogoutRedirectUris = null;
return Task.CompletedTask;
return default;
}
application.PostLogoutRedirectUris = new JArray(addresses.ToArray()).ToString(Formatting.None);
return Task.CompletedTask;
return default;
}
/// <summary>
@ -866,10 +829,8 @@ namespace OpenIddict.NHibernate
/// <param name="application">The application.</param>
/// <param name="properties">The additional properties associated with the application.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetPropertiesAsync([NotNull] TApplication application, [CanBeNull] JObject properties, CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetPropertiesAsync([NotNull] TApplication application, [CanBeNull] JObject properties, CancellationToken cancellationToken)
{
if (application == null)
{
@ -880,12 +841,12 @@ namespace OpenIddict.NHibernate
{
application.Properties = null;
return Task.CompletedTask;
return default;
}
application.Properties = properties.ToString(Formatting.None);
return Task.CompletedTask;
return default;
}
/// <summary>
@ -894,10 +855,8 @@ namespace OpenIddict.NHibernate
/// <param name="application">The application.</param>
/// <param name="addresses">The callback addresses associated with the application </param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetRedirectUrisAsync([NotNull] TApplication application,
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetRedirectUrisAsync([NotNull] TApplication application,
ImmutableArray<string> addresses, CancellationToken cancellationToken)
{
if (application == null)
@ -909,12 +868,12 @@ namespace OpenIddict.NHibernate
{
application.RedirectUris = null;
return Task.CompletedTask;
return default;
}
application.RedirectUris = new JArray(addresses.ToArray()).ToString(Formatting.None);
return Task.CompletedTask;
return default;
}
/// <summary>
@ -922,10 +881,8 @@ namespace OpenIddict.NHibernate
/// </summary>
/// <param name="application">The application to update.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual async Task UpdateAsync([NotNull] TApplication application, CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual async ValueTask UpdateAsync([NotNull] TApplication application, CancellationToken cancellationToken)
{
if (application == null)
{

329
src/OpenIddict.NHibernate/Stores/OpenIddictAuthorizationStore.cs

@ -5,9 +5,11 @@
*/
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
@ -17,6 +19,7 @@ using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using NHibernate;
using NHibernate.Cfg;
using NHibernate.Linq;
using OpenIddict.Abstractions;
using OpenIddict.NHibernate.Models;
@ -100,10 +103,10 @@ namespace OpenIddict.NHibernate
/// </summary>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the number of authorizations in the database.
/// </returns>
public virtual async Task<long> CountAsync(CancellationToken cancellationToken)
public virtual async ValueTask<long> CountAsync(CancellationToken cancellationToken)
{
var session = await Context.GetSessionAsync(cancellationToken);
return await session.Query<TAuthorization>().LongCountAsync(cancellationToken);
@ -116,10 +119,10 @@ namespace OpenIddict.NHibernate
/// <param name="query">The query to execute.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the number of authorizations that match the specified query.
/// </returns>
public virtual async Task<long> CountAsync<TResult>([NotNull] Func<IQueryable<TAuthorization>, IQueryable<TResult>> query, CancellationToken cancellationToken)
public virtual async ValueTask<long> CountAsync<TResult>([NotNull] Func<IQueryable<TAuthorization>, IQueryable<TResult>> query, CancellationToken cancellationToken)
{
if (query == null)
{
@ -135,10 +138,8 @@ namespace OpenIddict.NHibernate
/// </summary>
/// <param name="authorization">The authorization to create.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual async Task CreateAsync([NotNull] TAuthorization authorization, CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual async ValueTask CreateAsync([NotNull] TAuthorization authorization, CancellationToken cancellationToken)
{
if (authorization == null)
{
@ -155,10 +156,8 @@ namespace OpenIddict.NHibernate
/// </summary>
/// <param name="authorization">The authorization to delete.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual async Task DeleteAsync([NotNull] TAuthorization authorization, CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual async ValueTask DeleteAsync([NotNull] TAuthorization authorization, CancellationToken cancellationToken)
{
if (authorization == null)
{
@ -194,11 +193,8 @@ namespace OpenIddict.NHibernate
/// <param name="subject">The subject associated with the authorization.</param>
/// <param name="client">The client associated with the authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the authorizations corresponding to the subject/client.
/// </returns>
public virtual async Task<ImmutableArray<TAuthorization>> FindAsync(
/// <returns>The authorizations corresponding to the subject/client.</returns>
public virtual IAsyncEnumerable<TAuthorization> FindAsync(
[NotNull] string subject, [NotNull] string client, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(subject))
@ -211,16 +207,23 @@ namespace OpenIddict.NHibernate
throw new ArgumentException("The client cannot be null or empty.", nameof(client));
}
var session = await Context.GetSessionAsync(cancellationToken);
return ExecuteAsync(cancellationToken);
var key = ConvertIdentifierFromString(client);
async IAsyncEnumerable<TAuthorization> ExecuteAsync(CancellationToken cancellationToken)
{
var session = await Context.GetSessionAsync(cancellationToken);
var key = ConvertIdentifierFromString(client);
return ImmutableArray.CreateRange(
await (from authorization in session.Query<TAuthorization>().Fetch(authorization => authorization.Application)
where authorization.Application != null &&
authorization.Application.Id.Equals(key) &&
authorization.Subject == subject
select authorization).ToListAsync(cancellationToken));
await foreach (var authorization in
(from authorization in session.Query<TAuthorization>().Fetch(authorization => authorization.Application)
where authorization.Application != null &&
authorization.Application.Id.Equals(key) &&
authorization.Subject == subject
select authorization).AsAsyncEnumerable(cancellationToken))
{
yield return authorization;
}
}
}
/// <summary>
@ -230,11 +233,8 @@ namespace OpenIddict.NHibernate
/// <param name="client">The client associated with the authorization.</param>
/// <param name="status">The authorization status.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the authorizations corresponding to the criteria.
/// </returns>
public virtual async Task<ImmutableArray<TAuthorization>> FindAsync(
/// <returns>The authorizations corresponding to the criteria.</returns>
public virtual IAsyncEnumerable<TAuthorization> FindAsync(
[NotNull] string subject, [NotNull] string client,
[NotNull] string status, CancellationToken cancellationToken)
{
@ -253,17 +253,24 @@ namespace OpenIddict.NHibernate
throw new ArgumentException("The status cannot be null or empty.", nameof(status));
}
var session = await Context.GetSessionAsync(cancellationToken);
return ExecuteAsync(cancellationToken);
var key = ConvertIdentifierFromString(client);
async IAsyncEnumerable<TAuthorization> ExecuteAsync(CancellationToken cancellationToken)
{
var session = await Context.GetSessionAsync(cancellationToken);
var key = ConvertIdentifierFromString(client);
return ImmutableArray.CreateRange(
await (from authorization in session.Query<TAuthorization>().Fetch(authorization => authorization.Application)
where authorization.Application != null &&
authorization.Application.Id.Equals(key) &&
authorization.Subject == subject &&
authorization.Status == status
select authorization).ToListAsync(cancellationToken));
await foreach (var authorization in
(from authorization in session.Query<TAuthorization>().Fetch(authorization => authorization.Application)
where authorization.Application != null &&
authorization.Application.Id.Equals(key) &&
authorization.Subject == subject &&
authorization.Status == status
select authorization).AsAsyncEnumerable(cancellationToken))
{
yield return authorization;
}
}
}
/// <summary>
@ -274,11 +281,8 @@ namespace OpenIddict.NHibernate
/// <param name="status">The authorization status.</param>
/// <param name="type">The authorization type.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the authorizations corresponding to the criteria.
/// </returns>
public virtual async Task<ImmutableArray<TAuthorization>> FindAsync(
/// <returns>The authorizations corresponding to the criteria.</returns>
public virtual IAsyncEnumerable<TAuthorization> FindAsync(
[NotNull] string subject, [NotNull] string client,
[NotNull] string status, [NotNull] string type, CancellationToken cancellationToken)
{
@ -302,18 +306,25 @@ namespace OpenIddict.NHibernate
throw new ArgumentException("The type cannot be null or empty.", nameof(type));
}
var session = await Context.GetSessionAsync(cancellationToken);
return ExecuteAsync(cancellationToken);
var key = ConvertIdentifierFromString(client);
async IAsyncEnumerable<TAuthorization> ExecuteAsync(CancellationToken cancellationToken)
{
var session = await Context.GetSessionAsync(cancellationToken);
var key = ConvertIdentifierFromString(client);
return ImmutableArray.CreateRange(
await (from authorization in session.Query<TAuthorization>().Fetch(authorization => authorization.Application)
where authorization.Application != null &&
authorization.Application.Id.Equals(key) &&
authorization.Subject == subject &&
authorization.Status == status &&
authorization.Type == type
select authorization).ToListAsync(cancellationToken));
await foreach (var authorization in
(from authorization in session.Query<TAuthorization>().Fetch(authorization => authorization.Application)
where authorization.Application != null &&
authorization.Application.Id.Equals(key) &&
authorization.Subject == subject &&
authorization.Status == status &&
authorization.Type == type
select authorization).AsAsyncEnumerable(cancellationToken))
{
yield return authorization;
}
}
}
/// <summary>
@ -325,51 +336,22 @@ namespace OpenIddict.NHibernate
/// <param name="type">The authorization type.</param>
/// <param name="scopes">The minimal scopes associated with the authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the authorizations corresponding to the criteria.
/// </returns>
public virtual async Task<ImmutableArray<TAuthorization>> FindAsync(
/// <returns>The authorizations corresponding to the criteria.</returns>
public virtual IAsyncEnumerable<TAuthorization> FindAsync(
[NotNull] string subject, [NotNull] string client,
[NotNull] string status, [NotNull] string type,
ImmutableArray<string> scopes, CancellationToken cancellationToken)
{
var authorizations = await FindAsync(subject, client, status, type, cancellationToken);
if (authorizations.IsEmpty)
{
return ImmutableArray.Create<TAuthorization>();
}
var builder = ImmutableArray.CreateBuilder<TAuthorization>(authorizations.Length);
foreach (var authorization in authorizations)
{
async Task<bool> HasScopesAsync()
=> (await GetScopesAsync(authorization, cancellationToken))
.ToImmutableHashSet(StringComparer.Ordinal)
.IsSupersetOf(scopes);
if (await HasScopesAsync())
{
builder.Add(authorization);
}
}
return builder.Count == builder.Capacity ?
builder.MoveToImmutable() :
builder.ToImmutable();
}
=> FindAsync(subject, client, status, type, cancellationToken)
.WhereAwait(async authorization => new HashSet<string>(
await GetScopesAsync(authorization, cancellationToken), StringComparer.Ordinal).IsSupersetOf(scopes));
/// <summary>
/// Retrieves the list of authorizations corresponding to the specified application identifier.
/// </summary>
/// <param name="identifier">The application identifier associated with the authorizations.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the authorizations corresponding to the specified application.
/// </returns>
public virtual async Task<ImmutableArray<TAuthorization>> FindByApplicationIdAsync(
/// <returns>The authorizations corresponding to the specified application.</returns>
public virtual IAsyncEnumerable<TAuthorization> FindByApplicationIdAsync(
[NotNull] string identifier, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(identifier))
@ -377,15 +359,22 @@ namespace OpenIddict.NHibernate
throw new ArgumentException("The identifier cannot be null or empty.", nameof(identifier));
}
var session = await Context.GetSessionAsync(cancellationToken);
return ExecuteAsync(cancellationToken);
var key = ConvertIdentifierFromString(identifier);
async IAsyncEnumerable<TAuthorization> ExecuteAsync(CancellationToken cancellationToken)
{
var session = await Context.GetSessionAsync(cancellationToken);
var key = ConvertIdentifierFromString(identifier);
return ImmutableArray.CreateRange(
await (from authorization in session.Query<TAuthorization>().Fetch(authorization => authorization.Application)
where authorization.Application != null &&
authorization.Application.Id.Equals(key)
select authorization).ToListAsync(cancellationToken));
await foreach (var authorization in
(from authorization in session.Query<TAuthorization>().Fetch(authorization => authorization.Application)
where authorization.Application != null &&
authorization.Application.Id.Equals(key)
select authorization).AsAsyncEnumerable(cancellationToken))
{
yield return authorization;
}
}
}
/// <summary>
@ -394,10 +383,10 @@ namespace OpenIddict.NHibernate
/// <param name="identifier">The unique identifier associated with the authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the authorization corresponding to the identifier.
/// </returns>
public virtual async Task<TAuthorization> FindByIdAsync([NotNull] string identifier, CancellationToken cancellationToken)
public virtual async ValueTask<TAuthorization> FindByIdAsync([NotNull] string identifier, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(identifier))
{
@ -413,11 +402,8 @@ namespace OpenIddict.NHibernate
/// </summary>
/// <param name="subject">The subject associated with the authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the authorizations corresponding to the specified subject.
/// </returns>
public virtual async Task<ImmutableArray<TAuthorization>> FindBySubjectAsync(
/// <returns>The authorizations corresponding to the specified subject.</returns>
public virtual IAsyncEnumerable<TAuthorization> FindBySubjectAsync(
[NotNull] string subject, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(subject))
@ -425,12 +411,20 @@ namespace OpenIddict.NHibernate
throw new ArgumentException("The subject cannot be null or empty.", nameof(subject));
}
var session = await Context.GetSessionAsync(cancellationToken);
return ExecuteAsync(cancellationToken);
return ImmutableArray.CreateRange(
await (from authorization in session.Query<TAuthorization>().Fetch(authorization => authorization.Application)
where authorization.Subject == subject
select authorization).ToListAsync(cancellationToken));
async IAsyncEnumerable<TAuthorization> ExecuteAsync(CancellationToken cancellationToken)
{
var session = await Context.GetSessionAsync(cancellationToken);
await foreach (var authorization in
(from authorization in session.Query<TAuthorization>().Fetch(authorization => authorization.Application)
where authorization.Subject == subject
select authorization).AsAsyncEnumerable(cancellationToken))
{
yield return authorization;
}
}
}
/// <summary>
@ -466,10 +460,10 @@ namespace OpenIddict.NHibernate
/// <param name="state">The optional state.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the first element returned when executing the query.
/// </returns>
public virtual async Task<TResult> GetAsync<TState, TResult>(
public virtual async ValueTask<TResult> GetAsync<TState, TResult>(
[NotNull] Func<IQueryable<TAuthorization>, TState, IQueryable<TResult>> query,
[CanBeNull] TState state, CancellationToken cancellationToken)
{
@ -548,7 +542,20 @@ namespace OpenIddict.NHibernate
return new ValueTask<ImmutableArray<string>>(ImmutableArray.Create<string>());
}
return new ValueTask<ImmutableArray<string>>(JArray.Parse(authorization.Scopes).Select(element => (string) element).ToImmutableArray());
// Note: parsing the stringified scopes is an expensive operation.
// To mitigate that, the resulting array is stored in the memory cache.
var key = string.Concat("2ba4ab0f-e2ec-4d48-b3bd-28e2bb660c75", "\x1e", authorization.Scopes);
var scopes = Cache.GetOrCreate(key, entry =>
{
entry.SetPriority(CacheItemPriority.High)
.SetSlidingExpiration(TimeSpan.FromMinutes(1));
return JArray.Parse(authorization.Scopes)
.Select(element => (string) element)
.ToImmutableArray();
});
return new ValueTask<ImmutableArray<string>>(scopes);
}
/// <summary>
@ -640,12 +647,9 @@ namespace OpenIddict.NHibernate
/// <param name="count">The number of results to return.</param>
/// <param name="offset">The number of results to skip.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the elements returned when executing the specified query.
/// </returns>
public virtual async Task<ImmutableArray<TAuthorization>> ListAsync(
[CanBeNull] int? count, [CanBeNull] int? offset, CancellationToken cancellationToken)
/// <returns>All the elements returned when executing the specified query.</returns>
public virtual async IAsyncEnumerable<TAuthorization> ListAsync(
[CanBeNull] int? count, [CanBeNull] int? offset, [EnumeratorCancellation] CancellationToken cancellationToken)
{
var session = await Context.GetSessionAsync(cancellationToken);
var query = session.Query<TAuthorization>()
@ -663,7 +667,10 @@ namespace OpenIddict.NHibernate
query = query.Take(count.Value);
}
return ImmutableArray.CreateRange(await query.ToListAsync(cancellationToken));
await foreach (var authorization in query.AsAsyncEnumerable(cancellationToken))
{
yield return authorization;
}
}
/// <summary>
@ -674,11 +681,8 @@ namespace OpenIddict.NHibernate
/// <param name="query">The query to execute.</param>
/// <param name="state">The optional state.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the elements returned when executing the specified query.
/// </returns>
public virtual async Task<ImmutableArray<TResult>> ListAsync<TState, TResult>(
/// <returns>All the elements returned when executing the specified query.</returns>
public virtual IAsyncEnumerable<TResult> ListAsync<TState, TResult>(
[NotNull] Func<IQueryable<TAuthorization>, TState, IQueryable<TResult>> query,
[CanBeNull] TState state, CancellationToken cancellationToken)
{
@ -687,20 +691,27 @@ namespace OpenIddict.NHibernate
throw new ArgumentNullException(nameof(query));
}
var session = await Context.GetSessionAsync(cancellationToken);
return ExecuteAsync(cancellationToken);
async IAsyncEnumerable<TResult> ExecuteAsync(CancellationToken cancellationToken)
{
var session = await Context.GetSessionAsync(cancellationToken);
return ImmutableArray.CreateRange(await query(
session.Query<TAuthorization>().Fetch(authorization => authorization.Application), state).ToListAsync(cancellationToken));
await foreach (var element in query(
session.Query<TAuthorization>()
.Fetch(authorization => authorization.Application), state).AsAsyncEnumerable(cancellationToken))
{
yield return element;
}
}
}
/// <summary>
/// Removes the authorizations that are marked as invalid and the ad-hoc ones that have no valid/nonexpired token attached.
/// </summary>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual async Task PruneAsync(CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual async ValueTask PruneAsync(CancellationToken cancellationToken)
{
var session = await Context.GetSessionAsync(cancellationToken);
@ -723,10 +734,8 @@ namespace OpenIddict.NHibernate
/// <param name="authorization">The authorization.</param>
/// <param name="identifier">The unique identifier associated with the client application.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual async Task SetApplicationIdAsync([NotNull] TAuthorization authorization,
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual async ValueTask SetApplicationIdAsync([NotNull] TAuthorization authorization,
[CanBeNull] string identifier, CancellationToken cancellationToken)
{
if (authorization == null)
@ -753,10 +762,8 @@ namespace OpenIddict.NHibernate
/// <param name="authorization">The authorization.</param>
/// <param name="properties">The additional properties associated with the authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetPropertiesAsync([NotNull] TAuthorization authorization, [CanBeNull] JObject properties, CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetPropertiesAsync([NotNull] TAuthorization authorization, [CanBeNull] JObject properties, CancellationToken cancellationToken)
{
if (authorization == null)
{
@ -767,12 +774,12 @@ namespace OpenIddict.NHibernate
{
authorization.Properties = null;
return Task.CompletedTask;
return default;
}
authorization.Properties = properties.ToString(Formatting.None);
return Task.CompletedTask;
return default;
}
/// <summary>
@ -781,10 +788,8 @@ namespace OpenIddict.NHibernate
/// <param name="authorization">The authorization.</param>
/// <param name="scopes">The scopes associated with the authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetScopesAsync([NotNull] TAuthorization authorization,
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetScopesAsync([NotNull] TAuthorization authorization,
ImmutableArray<string> scopes, CancellationToken cancellationToken)
{
if (authorization == null)
@ -796,12 +801,12 @@ namespace OpenIddict.NHibernate
{
authorization.Scopes = null;
return Task.CompletedTask;
return default;
}
authorization.Scopes = new JArray(scopes.ToArray()).ToString(Formatting.None);
return Task.CompletedTask;
return default;
}
/// <summary>
@ -810,10 +815,8 @@ namespace OpenIddict.NHibernate
/// <param name="authorization">The authorization.</param>
/// <param name="status">The status associated with the authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetStatusAsync([NotNull] TAuthorization authorization,
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetStatusAsync([NotNull] TAuthorization authorization,
[CanBeNull] string status, CancellationToken cancellationToken)
{
if (authorization == null)
@ -823,7 +826,7 @@ namespace OpenIddict.NHibernate
authorization.Status = status;
return Task.CompletedTask;
return default;
}
/// <summary>
@ -832,10 +835,8 @@ namespace OpenIddict.NHibernate
/// <param name="authorization">The authorization.</param>
/// <param name="subject">The subject associated with the authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetSubjectAsync([NotNull] TAuthorization authorization,
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetSubjectAsync([NotNull] TAuthorization authorization,
[CanBeNull] string subject, CancellationToken cancellationToken)
{
if (authorization == null)
@ -845,7 +846,7 @@ namespace OpenIddict.NHibernate
authorization.Subject = subject;
return Task.CompletedTask;
return default;
}
/// <summary>
@ -854,10 +855,8 @@ namespace OpenIddict.NHibernate
/// <param name="authorization">The authorization.</param>
/// <param name="type">The type associated with the authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetTypeAsync([NotNull] TAuthorization authorization,
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetTypeAsync([NotNull] TAuthorization authorization,
[CanBeNull] string type, CancellationToken cancellationToken)
{
if (authorization == null)
@ -867,7 +866,7 @@ namespace OpenIddict.NHibernate
authorization.Type = type;
return Task.CompletedTask;
return default;
}
/// <summary>
@ -875,10 +874,8 @@ namespace OpenIddict.NHibernate
/// </summary>
/// <param name="authorization">The authorization to update.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual async Task UpdateAsync([NotNull] TAuthorization authorization, CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual async ValueTask UpdateAsync([NotNull] TAuthorization authorization, CancellationToken cancellationToken)
{
if (authorization == null)
{

184
src/OpenIddict.NHibernate/Stores/OpenIddictScopeStore.cs

@ -5,9 +5,11 @@
*/
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
@ -17,6 +19,7 @@ using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using NHibernate;
using NHibernate.Cfg;
using NHibernate.Linq;
using OpenIddict.Abstractions;
using OpenIddict.NHibernate.Models;
@ -92,10 +95,10 @@ namespace OpenIddict.NHibernate
/// </summary>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the number of scopes in the database.
/// </returns>
public virtual async Task<long> CountAsync(CancellationToken cancellationToken)
public virtual async ValueTask<long> CountAsync(CancellationToken cancellationToken)
{
var session = await Context.GetSessionAsync(cancellationToken);
return await session.Query<TScope>().LongCountAsync(cancellationToken);
@ -108,10 +111,10 @@ namespace OpenIddict.NHibernate
/// <param name="query">The query to execute.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the number of scopes that match the specified query.
/// </returns>
public virtual async Task<long> CountAsync<TResult>([NotNull] Func<IQueryable<TScope>, IQueryable<TResult>> query, CancellationToken cancellationToken)
public virtual async ValueTask<long> CountAsync<TResult>([NotNull] Func<IQueryable<TScope>, IQueryable<TResult>> query, CancellationToken cancellationToken)
{
if (query == null)
{
@ -127,10 +130,8 @@ namespace OpenIddict.NHibernate
/// </summary>
/// <param name="scope">The scope to create.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual async Task CreateAsync([NotNull] TScope scope, CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual async ValueTask CreateAsync([NotNull] TScope scope, CancellationToken cancellationToken)
{
if (scope == null)
{
@ -147,10 +148,8 @@ namespace OpenIddict.NHibernate
/// </summary>
/// <param name="scope">The scope to delete.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual async Task DeleteAsync([NotNull] TScope scope, CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual async ValueTask DeleteAsync([NotNull] TScope scope, CancellationToken cancellationToken)
{
if (scope == null)
{
@ -180,10 +179,10 @@ namespace OpenIddict.NHibernate
/// <param name="identifier">The unique identifier associated with the scope.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the scope corresponding to the identifier.
/// </returns>
public virtual async Task<TScope> FindByIdAsync([NotNull] string identifier, CancellationToken cancellationToken)
public virtual async ValueTask<TScope> FindByIdAsync([NotNull] string identifier, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(identifier))
{
@ -200,10 +199,10 @@ namespace OpenIddict.NHibernate
/// <param name="name">The name associated with the scope.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the scope corresponding to the specified name.
/// </returns>
public virtual async Task<TScope> FindByNameAsync([NotNull] string name, CancellationToken cancellationToken)
public virtual async ValueTask<TScope> FindByNameAsync([NotNull] string name, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(name))
{
@ -222,24 +221,27 @@ namespace OpenIddict.NHibernate
/// </summary>
/// <param name="names">The names associated with the scopes.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the scopes corresponding to the specified names.
/// </returns>
public virtual async Task<ImmutableArray<TScope>> FindByNamesAsync(
ImmutableArray<string> names, CancellationToken cancellationToken)
/// <returns>The scopes corresponding to the specified names.</returns>
public virtual IAsyncEnumerable<TScope> FindByNamesAsync(ImmutableArray<string> names, CancellationToken cancellationToken)
{
if (names.Any(name => string.IsNullOrEmpty(name)))
{
throw new ArgumentException("Scope names cannot be null or empty.", nameof(names));
}
var session = await Context.GetSessionAsync(cancellationToken);
return ExecuteAsync(cancellationToken);
async IAsyncEnumerable<TScope> ExecuteAsync(CancellationToken cancellationToken)
{
var session = await Context.GetSessionAsync(cancellationToken);
return ImmutableArray.CreateRange(
await (from scope in session.Query<TScope>()
where names.Contains(scope.Name)
select scope).ToListAsync(cancellationToken));
await foreach (var scope in (from scope in session.Query<TScope>()
where names.Contains(scope.Name)
select scope).AsAsyncEnumerable(cancellationToken))
{
yield return scope;
}
}
}
/// <summary>
@ -247,41 +249,33 @@ namespace OpenIddict.NHibernate
/// </summary>
/// <param name="resource">The resource associated with the scopes.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the scopes associated with the specified resource.
/// </returns>
public virtual async Task<ImmutableArray<TScope>> FindByResourceAsync(
[NotNull] string resource, CancellationToken cancellationToken)
/// <returns>The scopes associated with the specified resource.</returns>
public virtual IAsyncEnumerable<TScope> FindByResourceAsync([NotNull] string resource, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(resource))
{
throw new ArgumentException("The resource cannot be null or empty.", nameof(resource));
}
var session = await Context.GetSessionAsync(cancellationToken);
// To optimize the efficiency of the query a bit, only scopes whose stringified
// Resources column contains the specified resource are returned. Once the scopes
// are retrieved, a second pass is made to ensure only valid elements are returned.
// Implementers that use this method in a hot path may want to override this method
// to use SQL Server 2016 functions like JSON_VALUE to make the query more efficient.
var scopes = await (from scope in session.Query<TScope>()
where scope.Resources.Contains(resource)
select scope).ToListAsync(cancellationToken);
var builder = ImmutableArray.CreateBuilder<TScope>();
return ExecuteAsync(cancellationToken);
foreach (var scope in scopes)
async IAsyncEnumerable<TScope> ExecuteAsync(CancellationToken cancellationToken)
{
var resources = await GetResourcesAsync(scope, cancellationToken);
if (resources.Contains(resource, StringComparer.OrdinalIgnoreCase))
var session = await Context.GetSessionAsync(cancellationToken);
// To optimize the efficiency of the query a bit, only scopes whose stringified
// Resources column contains the specified resource are returned. Once the scopes
// are retrieved, a second pass is made to ensure only valid elements are returned.
// Implementers that use this method in a hot path may want to override this method
// to use SQL Server 2016 functions like JSON_VALUE to make the query more efficient.
await foreach (var scope in session.Query<TScope>()
.Where(scope => scope.Resources.Contains(resource))
.AsAsyncEnumerable(cancellationToken)
.WhereAwait(async scope => (await GetResourcesAsync(scope, cancellationToken)).Contains(resource, StringComparer.Ordinal)))
{
builder.Add(scope);
yield return scope;
}
}
return builder.ToImmutable();
}
/// <summary>
@ -293,10 +287,10 @@ namespace OpenIddict.NHibernate
/// <param name="state">The optional state.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the first element returned when executing the query.
/// </returns>
public virtual async Task<TResult> GetAsync<TState, TResult>(
public virtual async ValueTask<TResult> GetAsync<TState, TResult>(
[NotNull] Func<IQueryable<TScope>, TState, IQueryable<TResult>> query,
[CanBeNull] TState state, CancellationToken cancellationToken)
{
@ -478,12 +472,9 @@ namespace OpenIddict.NHibernate
/// <param name="count">The number of results to return.</param>
/// <param name="offset">The number of results to skip.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the elements returned when executing the specified query.
/// </returns>
public virtual async Task<ImmutableArray<TScope>> ListAsync(
[CanBeNull] int? count, [CanBeNull] int? offset, CancellationToken cancellationToken)
/// <returns>All the elements returned when executing the specified query.</returns>
public virtual async IAsyncEnumerable<TScope> ListAsync(
[CanBeNull] int? count, [CanBeNull] int? offset, [EnumeratorCancellation] CancellationToken cancellationToken)
{
var session = await Context.GetSessionAsync(cancellationToken);
var query = session.Query<TScope>()
@ -500,7 +491,10 @@ namespace OpenIddict.NHibernate
query = query.Take(count.Value);
}
return ImmutableArray.CreateRange(await query.ToListAsync(cancellationToken));
await foreach (var scope in query.AsAsyncEnumerable(cancellationToken))
{
yield return scope;
}
}
/// <summary>
@ -511,11 +505,8 @@ namespace OpenIddict.NHibernate
/// <param name="query">The query to execute.</param>
/// <param name="state">The optional state.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the elements returned when executing the specified query.
/// </returns>
public virtual async Task<ImmutableArray<TResult>> ListAsync<TState, TResult>(
/// <returns>All the elements returned when executing the specified query.</returns>
public virtual IAsyncEnumerable<TResult> ListAsync<TState, TResult>(
[NotNull] Func<IQueryable<TScope>, TState, IQueryable<TResult>> query,
[CanBeNull] TState state, CancellationToken cancellationToken)
{
@ -524,8 +515,17 @@ namespace OpenIddict.NHibernate
throw new ArgumentNullException(nameof(query));
}
var session = await Context.GetSessionAsync(cancellationToken);
return ImmutableArray.CreateRange(await query(session.Query<TScope>(), state).ToListAsync(cancellationToken));
return ExecuteAsync(cancellationToken);
async IAsyncEnumerable<TResult> ExecuteAsync(CancellationToken cancellationToken)
{
var session = await Context.GetSessionAsync(cancellationToken);
await foreach (var element in query(session.Query<TScope>(), state).AsAsyncEnumerable(cancellationToken))
{
yield return element;
}
}
}
/// <summary>
@ -534,10 +534,8 @@ namespace OpenIddict.NHibernate
/// <param name="scope">The scope.</param>
/// <param name="description">The description associated with the authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetDescriptionAsync([NotNull] TScope scope, [CanBeNull] string description, CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetDescriptionAsync([NotNull] TScope scope, [CanBeNull] string description, CancellationToken cancellationToken)
{
if (scope == null)
{
@ -546,7 +544,7 @@ namespace OpenIddict.NHibernate
scope.Description = description;
return Task.CompletedTask;
return default;
}
/// <summary>
@ -555,10 +553,8 @@ namespace OpenIddict.NHibernate
/// <param name="scope">The scope.</param>
/// <param name="name">The display name associated with the scope.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetDisplayNameAsync([NotNull] TScope scope, [CanBeNull] string name, CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetDisplayNameAsync([NotNull] TScope scope, [CanBeNull] string name, CancellationToken cancellationToken)
{
if (scope == null)
{
@ -567,7 +563,7 @@ namespace OpenIddict.NHibernate
scope.DisplayName = name;
return Task.CompletedTask;
return default;
}
/// <summary>
@ -576,10 +572,8 @@ namespace OpenIddict.NHibernate
/// <param name="scope">The scope.</param>
/// <param name="name">The name associated with the authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetNameAsync([NotNull] TScope scope, [CanBeNull] string name, CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetNameAsync([NotNull] TScope scope, [CanBeNull] string name, CancellationToken cancellationToken)
{
if (scope == null)
{
@ -588,7 +582,7 @@ namespace OpenIddict.NHibernate
scope.Name = name;
return Task.CompletedTask;
return default;
}
/// <summary>
@ -597,10 +591,8 @@ namespace OpenIddict.NHibernate
/// <param name="scope">The scope.</param>
/// <param name="properties">The additional properties associated with the scope.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetPropertiesAsync([NotNull] TScope scope, [CanBeNull] JObject properties, CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetPropertiesAsync([NotNull] TScope scope, [CanBeNull] JObject properties, CancellationToken cancellationToken)
{
if (scope == null)
{
@ -611,12 +603,12 @@ namespace OpenIddict.NHibernate
{
scope.Properties = null;
return Task.CompletedTask;
return default;
}
scope.Properties = properties.ToString(Formatting.None);
return Task.CompletedTask;
return default;
}
/// <summary>
@ -625,10 +617,8 @@ namespace OpenIddict.NHibernate
/// <param name="scope">The scope.</param>
/// <param name="resources">The resources associated with the scope.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetResourcesAsync([NotNull] TScope scope, ImmutableArray<string> resources, CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetResourcesAsync([NotNull] TScope scope, ImmutableArray<string> resources, CancellationToken cancellationToken)
{
if (scope == null)
{
@ -639,12 +629,12 @@ namespace OpenIddict.NHibernate
{
scope.Resources = null;
return Task.CompletedTask;
return default;
}
scope.Resources = new JArray(resources.ToArray()).ToString(Formatting.None);
return Task.CompletedTask;
return default;
}
/// <summary>
@ -652,10 +642,8 @@ namespace OpenIddict.NHibernate
/// </summary>
/// <param name="scope">The scope to update.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual async Task UpdateAsync([NotNull] TScope scope, CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual async ValueTask UpdateAsync([NotNull] TScope scope, CancellationToken cancellationToken)
{
if (scope == null)
{

368
src/OpenIddict.NHibernate/Stores/OpenIddictTokenStore.cs

@ -5,9 +5,11 @@
*/
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
@ -17,6 +19,7 @@ using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using NHibernate;
using NHibernate.Cfg;
using NHibernate.Linq;
using OpenIddict.Abstractions;
using OpenIddict.NHibernate.Models;
@ -100,10 +103,10 @@ namespace OpenIddict.NHibernate
/// </summary>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the number of applications in the database.
/// </returns>
public virtual async Task<long> CountAsync(CancellationToken cancellationToken)
public virtual async ValueTask<long> CountAsync(CancellationToken cancellationToken)
{
var session = await Context.GetSessionAsync(cancellationToken);
return await session.Query<TToken>().LongCountAsync(cancellationToken);
@ -116,10 +119,10 @@ namespace OpenIddict.NHibernate
/// <param name="query">The query to execute.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the number of tokens that match the specified query.
/// </returns>
public virtual async Task<long> CountAsync<TResult>([NotNull] Func<IQueryable<TToken>, IQueryable<TResult>> query, CancellationToken cancellationToken)
public virtual async ValueTask<long> CountAsync<TResult>([NotNull] Func<IQueryable<TToken>, IQueryable<TResult>> query, CancellationToken cancellationToken)
{
if (query == null)
{
@ -135,10 +138,8 @@ namespace OpenIddict.NHibernate
/// </summary>
/// <param name="token">The token to create.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual async Task CreateAsync([NotNull] TToken token, CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual async ValueTask CreateAsync([NotNull] TToken token, CancellationToken cancellationToken)
{
if (token == null)
{
@ -155,10 +156,8 @@ namespace OpenIddict.NHibernate
/// </summary>
/// <param name="token">The token to delete.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual async Task DeleteAsync([NotNull] TToken token, CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual async ValueTask DeleteAsync([NotNull] TToken token, CancellationToken cancellationToken)
{
if (token == null)
{
@ -189,11 +188,8 @@ namespace OpenIddict.NHibernate
/// <param name="subject">The subject associated with the token.</param>
/// <param name="client">The client associated with the token.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the tokens corresponding to the subject/client.
/// </returns>
public virtual async Task<ImmutableArray<TToken>> FindAsync([NotNull] string subject,
/// <returns>The tokens corresponding to the subject/client.</returns>
public virtual IAsyncEnumerable<TToken> FindAsync([NotNull] string subject,
[NotNull] string client, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(subject))
@ -206,18 +202,24 @@ namespace OpenIddict.NHibernate
throw new ArgumentException("The client cannot be null or empty.", nameof(client));
}
var session = await Context.GetSessionAsync(cancellationToken);
var key = ConvertIdentifierFromString(client);
return ExecuteAsync(cancellationToken);
return ImmutableArray.CreateRange(
await (from token in session.Query<TToken>()
.Fetch(token => token.Application)
.Fetch(token => token.Authorization)
where token.Application != null &&
token.Application.Id.Equals(key) &&
token.Subject == subject
select token).ToListAsync(cancellationToken));
async IAsyncEnumerable<TToken> ExecuteAsync(CancellationToken cancellationToken)
{
var session = await Context.GetSessionAsync(cancellationToken);
var key = ConvertIdentifierFromString(client);
await foreach (var token in (from token in session.Query<TToken>()
.Fetch(token => token.Application)
.Fetch(token => token.Authorization)
where token.Application != null &&
token.Application.Id.Equals(key) &&
token.Subject == subject
select token).AsAsyncEnumerable(cancellationToken))
{
yield return token;
}
}
}
/// <summary>
@ -227,11 +229,8 @@ namespace OpenIddict.NHibernate
/// <param name="client">The client associated with the token.</param>
/// <param name="status">The token status.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the tokens corresponding to the criteria.
/// </returns>
public virtual async Task<ImmutableArray<TToken>> FindAsync(
/// <returns>The tokens corresponding to the criteria.</returns>
public virtual IAsyncEnumerable<TToken> FindAsync(
[NotNull] string subject, [NotNull] string client,
[NotNull] string status, CancellationToken cancellationToken)
{
@ -250,19 +249,25 @@ namespace OpenIddict.NHibernate
throw new ArgumentException("The status cannot be null or empty.", nameof(status));
}
var session = await Context.GetSessionAsync(cancellationToken);
return ExecuteAsync(cancellationToken);
var key = ConvertIdentifierFromString(client);
return ImmutableArray.CreateRange(
await (from token in session.Query<TToken>()
.Fetch(token => token.Application)
.Fetch(token => token.Authorization)
where token.Application != null &&
token.Application.Id.Equals(key) &&
token.Subject == subject &&
token.Status == status
select token).ToListAsync(cancellationToken));
async IAsyncEnumerable<TToken> ExecuteAsync(CancellationToken cancellationToken)
{
var session = await Context.GetSessionAsync(cancellationToken);
var key = ConvertIdentifierFromString(client);
await foreach (var token in (from token in session.Query<TToken>()
.Fetch(token => token.Application)
.Fetch(token => token.Authorization)
where token.Application != null &&
token.Application.Id.Equals(key) &&
token.Subject == subject &&
token.Status == status
select token).AsAsyncEnumerable(cancellationToken))
{
yield return token;
}
}
}
/// <summary>
@ -273,11 +278,8 @@ namespace OpenIddict.NHibernate
/// <param name="status">The token status.</param>
/// <param name="type">The token type.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the tokens corresponding to the criteria.
/// </returns>
public virtual async Task<ImmutableArray<TToken>> FindAsync(
/// <returns>The tokens corresponding to the criteria.</returns>
public virtual IAsyncEnumerable<TToken> FindAsync(
[NotNull] string subject, [NotNull] string client,
[NotNull] string status, [NotNull] string type, CancellationToken cancellationToken)
{
@ -301,20 +303,26 @@ namespace OpenIddict.NHibernate
throw new ArgumentException("The type cannot be null or empty.", nameof(type));
}
var session = await Context.GetSessionAsync(cancellationToken);
return ExecuteAsync(cancellationToken);
var key = ConvertIdentifierFromString(client);
return ImmutableArray.CreateRange(
await (from token in session.Query<TToken>()
.Fetch(token => token.Application)
.Fetch(token => token.Authorization)
where token.Application != null &&
token.Application.Id.Equals(key) &&
token.Subject == subject &&
token.Status == status &&
token.Type == type
select token).ToListAsync(cancellationToken));
async IAsyncEnumerable<TToken> ExecuteAsync(CancellationToken cancellationToken)
{
var session = await Context.GetSessionAsync(cancellationToken);
var key = ConvertIdentifierFromString(client);
await foreach (var token in (from token in session.Query<TToken>()
.Fetch(token => token.Application)
.Fetch(token => token.Authorization)
where token.Application != null &&
token.Application.Id.Equals(key) &&
token.Subject == subject &&
token.Status == status &&
token.Type == type
select token).AsAsyncEnumerable(cancellationToken))
{
yield return token;
}
}
}
/// <summary>
@ -322,28 +330,31 @@ namespace OpenIddict.NHibernate
/// </summary>
/// <param name="identifier">The application identifier associated with the tokens.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the tokens corresponding to the specified application.
/// </returns>
public virtual async Task<ImmutableArray<TToken>> FindByApplicationIdAsync([NotNull] string identifier, CancellationToken cancellationToken)
/// <returns>The tokens corresponding to the specified application.</returns>
public virtual IAsyncEnumerable<TToken> FindByApplicationIdAsync([NotNull] string identifier, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(identifier))
{
throw new ArgumentException("The identifier cannot be null or empty.", nameof(identifier));
}
var session = await Context.GetSessionAsync(cancellationToken);
return ExecuteAsync(cancellationToken);
var key = ConvertIdentifierFromString(identifier);
return ImmutableArray.CreateRange(
await (from token in session.Query<TToken>()
.Fetch(token => token.Application)
.Fetch(token => token.Authorization)
where token.Application != null &&
token.Application.Id.Equals(key)
select token).ToListAsync(cancellationToken));
async IAsyncEnumerable<TToken> ExecuteAsync(CancellationToken cancellationToken)
{
var session = await Context.GetSessionAsync(cancellationToken);
var key = ConvertIdentifierFromString(identifier);
await foreach (var token in (from token in session.Query<TToken>()
.Fetch(token => token.Application)
.Fetch(token => token.Authorization)
where token.Application != null &&
token.Application.Id.Equals(key)
select token).AsAsyncEnumerable(cancellationToken))
{
yield return token;
}
}
}
/// <summary>
@ -351,28 +362,31 @@ namespace OpenIddict.NHibernate
/// </summary>
/// <param name="identifier">The authorization identifier associated with the tokens.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the tokens corresponding to the specified authorization.
/// </returns>
public virtual async Task<ImmutableArray<TToken>> FindByAuthorizationIdAsync([NotNull] string identifier, CancellationToken cancellationToken)
/// <returns>The tokens corresponding to the specified authorization.</returns>
public virtual IAsyncEnumerable<TToken> FindByAuthorizationIdAsync([NotNull] string identifier, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(identifier))
{
throw new ArgumentException("The identifier cannot be null or empty.", nameof(identifier));
}
var session = await Context.GetSessionAsync(cancellationToken);
var key = ConvertIdentifierFromString(identifier);
return ExecuteAsync(cancellationToken);
return ImmutableArray.CreateRange(
await (from token in session.Query<TToken>()
.Fetch(token => token.Application)
.Fetch(token => token.Authorization)
where token.Authorization != null &&
token.Authorization.Id.Equals(key)
select token).ToListAsync(cancellationToken));
async IAsyncEnumerable<TToken> ExecuteAsync(CancellationToken cancellationToken)
{
var session = await Context.GetSessionAsync(cancellationToken);
var key = ConvertIdentifierFromString(identifier);
await foreach (var token in (from token in session.Query<TToken>()
.Fetch(token => token.Application)
.Fetch(token => token.Authorization)
where token.Authorization != null &&
token.Authorization.Id.Equals(key)
select token).AsAsyncEnumerable(cancellationToken))
{
yield return token;
}
}
}
/// <summary>
@ -381,10 +395,10 @@ namespace OpenIddict.NHibernate
/// <param name="identifier">The unique identifier associated with the token.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the token corresponding to the unique identifier.
/// </returns>
public virtual async Task<TToken> FindByIdAsync([NotNull] string identifier, CancellationToken cancellationToken)
public virtual async ValueTask<TToken> FindByIdAsync([NotNull] string identifier, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(identifier))
{
@ -402,10 +416,10 @@ namespace OpenIddict.NHibernate
/// <param name="identifier">The reference identifier associated with the tokens.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the tokens corresponding to the specified reference identifier.
/// </returns>
public virtual async Task<TToken> FindByReferenceIdAsync([NotNull] string identifier, CancellationToken cancellationToken)
public virtual async ValueTask<TToken> FindByReferenceIdAsync([NotNull] string identifier, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(identifier))
{
@ -426,25 +440,29 @@ namespace OpenIddict.NHibernate
/// </summary>
/// <param name="subject">The subject associated with the tokens.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the tokens corresponding to the specified subject.
/// </returns>
public virtual async Task<ImmutableArray<TToken>> FindBySubjectAsync([NotNull] string subject, CancellationToken cancellationToken)
/// <returns>The tokens corresponding to the specified subject.</returns>
public virtual IAsyncEnumerable<TToken> FindBySubjectAsync([NotNull] string subject, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(subject))
{
throw new ArgumentException("The subject cannot be null or empty.", nameof(subject));
}
var session = await Context.GetSessionAsync(cancellationToken);
return ExecuteAsync(cancellationToken);
return ImmutableArray.CreateRange(
await (from token in session.Query<TToken>()
.Fetch(token => token.Application)
.Fetch(token => token.Authorization)
where token.Subject == subject
select token).ToListAsync(cancellationToken));
async IAsyncEnumerable<TToken> ExecuteAsync(CancellationToken cancellationToken)
{
var session = await Context.GetSessionAsync(cancellationToken);
await foreach (var token in (from token in session.Query<TToken>()
.Fetch(token => token.Application)
.Fetch(token => token.Authorization)
where token.Subject == subject
select token).AsAsyncEnumerable(cancellationToken))
{
yield return token;
}
}
}
/// <summary>
@ -480,10 +498,10 @@ namespace OpenIddict.NHibernate
/// <param name="state">The optional state.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the first element returned when executing the query.
/// </returns>
public virtual async Task<TResult> GetAsync<TState, TResult>(
public virtual async ValueTask<TResult> GetAsync<TState, TResult>(
[NotNull] Func<IQueryable<TToken>, TState, IQueryable<TResult>> query,
[CanBeNull] TState state, CancellationToken cancellationToken)
{
@ -733,12 +751,9 @@ namespace OpenIddict.NHibernate
/// <param name="count">The number of results to return.</param>
/// <param name="offset">The number of results to skip.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the elements returned when executing the specified query.
/// </returns>
public virtual async Task<ImmutableArray<TToken>> ListAsync(
[CanBeNull] int? count, [CanBeNull] int? offset, CancellationToken cancellationToken)
/// <returns>All the elements returned when executing the specified query.</returns>
public virtual async IAsyncEnumerable<TToken> ListAsync(
[CanBeNull] int? count, [CanBeNull] int? offset, [EnumeratorCancellation] CancellationToken cancellationToken)
{
var session = await Context.GetSessionAsync(cancellationToken);
var query = session.Query<TToken>()
@ -757,7 +772,10 @@ namespace OpenIddict.NHibernate
query = query.Take(count.Value);
}
return ImmutableArray.CreateRange(await query.ToListAsync(cancellationToken));
await foreach (var token in query.AsAsyncEnumerable(cancellationToken))
{
yield return token;
}
}
/// <summary>
@ -768,11 +786,8 @@ namespace OpenIddict.NHibernate
/// <param name="query">The query to execute.</param>
/// <param name="state">The optional state.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the elements returned when executing the specified query.
/// </returns>
public virtual async Task<ImmutableArray<TResult>> ListAsync<TState, TResult>(
/// <returns>All the elements returned when executing the specified query.</returns>
public virtual IAsyncEnumerable<TResult> ListAsync<TState, TResult>(
[NotNull] Func<IQueryable<TToken>, TState, IQueryable<TResult>> query,
[CanBeNull] TState state, CancellationToken cancellationToken)
{
@ -781,21 +796,28 @@ namespace OpenIddict.NHibernate
throw new ArgumentNullException(nameof(query));
}
var session = await Context.GetSessionAsync(cancellationToken);
return ExecuteAsync(cancellationToken);
return ImmutableArray.CreateRange(await query(
session.Query<TToken>().Fetch(token => token.Application)
.Fetch(token => token.Authorization), state).ToListAsync(cancellationToken));
async IAsyncEnumerable<TResult> ExecuteAsync(CancellationToken cancellationToken)
{
var session = await Context.GetSessionAsync(cancellationToken);
await foreach (var element in query(
session.Query<TToken>()
.Fetch(token => token.Application)
.Fetch(token => token.Authorization), state).AsAsyncEnumerable(cancellationToken))
{
yield return element;
}
}
}
/// <summary>
/// Removes the tokens that are marked as expired or invalid.
/// </summary>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual async Task PruneAsync(CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual async ValueTask PruneAsync(CancellationToken cancellationToken)
{
var session = await Context.GetSessionAsync(cancellationToken);
@ -813,10 +835,8 @@ namespace OpenIddict.NHibernate
/// <param name="token">The token.</param>
/// <param name="identifier">The unique identifier associated with the client application.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual async Task SetApplicationIdAsync([NotNull] TToken token,
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual async ValueTask SetApplicationIdAsync([NotNull] TToken token,
[CanBeNull] string identifier, CancellationToken cancellationToken)
{
if (token == null)
@ -843,10 +863,8 @@ namespace OpenIddict.NHibernate
/// <param name="token">The token.</param>
/// <param name="identifier">The unique identifier associated with the authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual async Task SetAuthorizationIdAsync([NotNull] TToken token,
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual async ValueTask SetAuthorizationIdAsync([NotNull] TToken token,
[CanBeNull] string identifier, CancellationToken cancellationToken)
{
if (token == null)
@ -873,10 +891,8 @@ namespace OpenIddict.NHibernate
/// <param name="token">The token.</param>
/// <param name="date">The creation date.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetCreationDateAsync([NotNull] TToken token,
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetCreationDateAsync([NotNull] TToken token,
[CanBeNull] DateTimeOffset? date, CancellationToken cancellationToken)
{
if (token == null)
@ -886,7 +902,7 @@ namespace OpenIddict.NHibernate
token.CreationDate = date;
return Task.CompletedTask;
return default;
}
/// <summary>
@ -895,10 +911,8 @@ namespace OpenIddict.NHibernate
/// <param name="token">The token.</param>
/// <param name="date">The expiration date.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetExpirationDateAsync([NotNull] TToken token,
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetExpirationDateAsync([NotNull] TToken token,
[CanBeNull] DateTimeOffset? date, CancellationToken cancellationToken)
{
if (token == null)
@ -908,7 +922,7 @@ namespace OpenIddict.NHibernate
token.ExpirationDate = date;
return Task.CompletedTask;
return default;
}
/// <summary>
@ -917,10 +931,8 @@ namespace OpenIddict.NHibernate
/// <param name="token">The token.</param>
/// <param name="payload">The payload associated with the token.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetPayloadAsync([NotNull] TToken token, [CanBeNull] string payload, CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetPayloadAsync([NotNull] TToken token, [CanBeNull] string payload, CancellationToken cancellationToken)
{
if (token == null)
{
@ -929,7 +941,7 @@ namespace OpenIddict.NHibernate
token.Payload = payload;
return Task.CompletedTask;
return default;
}
/// <summary>
@ -938,10 +950,8 @@ namespace OpenIddict.NHibernate
/// <param name="token">The token.</param>
/// <param name="properties">The additional properties associated with the token.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetPropertiesAsync([NotNull] TToken token, [CanBeNull] JObject properties, CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetPropertiesAsync([NotNull] TToken token, [CanBeNull] JObject properties, CancellationToken cancellationToken)
{
if (token == null)
{
@ -952,12 +962,12 @@ namespace OpenIddict.NHibernate
{
token.Properties = null;
return Task.CompletedTask;
return default;
}
token.Properties = properties.ToString(Formatting.None);
return Task.CompletedTask;
return default;
}
/// <summary>
@ -968,10 +978,8 @@ namespace OpenIddict.NHibernate
/// <param name="token">The token.</param>
/// <param name="identifier">The reference identifier associated with the token.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetReferenceIdAsync([NotNull] TToken token, [CanBeNull] string identifier, CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetReferenceIdAsync([NotNull] TToken token, [CanBeNull] string identifier, CancellationToken cancellationToken)
{
if (token == null)
{
@ -980,7 +988,7 @@ namespace OpenIddict.NHibernate
token.ReferenceId = identifier;
return Task.CompletedTask;
return default;
}
/// <summary>
@ -989,10 +997,8 @@ namespace OpenIddict.NHibernate
/// <param name="token">The token.</param>
/// <param name="status">The status associated with the authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetStatusAsync([NotNull] TToken token, [CanBeNull] string status, CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetStatusAsync([NotNull] TToken token, [CanBeNull] string status, CancellationToken cancellationToken)
{
if (token == null)
{
@ -1001,7 +1007,7 @@ namespace OpenIddict.NHibernate
token.Status = status;
return Task.CompletedTask;
return default;
}
/// <summary>
@ -1010,10 +1016,8 @@ namespace OpenIddict.NHibernate
/// <param name="token">The token.</param>
/// <param name="subject">The subject associated with the token.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetSubjectAsync([NotNull] TToken token, [CanBeNull] string subject, CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetSubjectAsync([NotNull] TToken token, [CanBeNull] string subject, CancellationToken cancellationToken)
{
if (token == null)
{
@ -1022,7 +1026,7 @@ namespace OpenIddict.NHibernate
token.Subject = subject;
return Task.CompletedTask;
return default;
}
/// <summary>
@ -1031,10 +1035,8 @@ namespace OpenIddict.NHibernate
/// <param name="token">The token.</param>
/// <param name="type">The token type associated with the token.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetTypeAsync([NotNull] TToken token, [CanBeNull] string type, CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetTypeAsync([NotNull] TToken token, [CanBeNull] string type, CancellationToken cancellationToken)
{
if (token == null)
{
@ -1043,7 +1045,7 @@ namespace OpenIddict.NHibernate
token.Type = type;
return Task.CompletedTask;
return default;
}
/// <summary>
@ -1051,10 +1053,8 @@ namespace OpenIddict.NHibernate
/// </summary>
/// <param name="token">The token to update.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual async Task UpdateAsync([NotNull] TToken token, CancellationToken cancellationToken)
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual async ValueTask UpdateAsync([NotNull] TToken token, CancellationToken cancellationToken)
{
if (token == null)
{

2
src/OpenIddict.Server/OpenIddictServerHandlers.Authentication.cs

@ -1017,7 +1017,7 @@ namespace OpenIddict.Server
var scopes = context.Request.GetScopes().Except(context.Options.Scopes);
if (scopes.Count != 0)
{
foreach (var scope in await _scopeManager.FindByNamesAsync(scopes.ToImmutableArray()))
await foreach (var scope in _scopeManager.FindByNamesAsync(scopes.ToImmutableArray()))
{
scopes = scopes.Remove(await _scopeManager.GetNameAsync(scope));
}

2
src/OpenIddict.Server/OpenIddictServerHandlers.Exchange.cs

@ -713,7 +713,7 @@ namespace OpenIddict.Server
var scopes = context.Request.GetScopes().Except(context.Options.Scopes);
if (scopes.Count != 0)
{
foreach (var scope in await _scopeManager.FindByNamesAsync(scopes.ToImmutableArray()))
await foreach (var scope in _scopeManager.FindByNamesAsync(scopes.ToImmutableArray()))
{
scopes = scopes.Remove(await _scopeManager.GetNameAsync(scope));
}

51
src/OpenIddict.Server/OpenIddictServerHandlers.Session.cs

@ -446,30 +446,6 @@ namespace OpenIddict.Server
throw new ArgumentNullException(nameof(context));
}
async Task<bool> ValidatePostLogoutRedirectUriAsync(string address)
{
var applications = await _applicationManager.FindByPostLogoutRedirectUriAsync(address);
if (applications.IsDefaultOrEmpty)
{
return false;
}
if (context.Options.IgnoreEndpointPermissions)
{
return true;
}
foreach (var application in applications)
{
if (await _applicationManager.HasPermissionAsync(application, Permissions.Endpoints.Logout))
{
return true;
}
}
return false;
}
if (!await ValidatePostLogoutRedirectUriAsync(context.PostLogoutRedirectUri))
{
context.Logger.LogError("The logout request was rejected because the specified post_logout_redirect_uri " +
@ -481,6 +457,33 @@ namespace OpenIddict.Server
return;
}
async Task<bool> ValidatePostLogoutRedirectUriAsync(string address)
{
// To be considered valid, a post_logout_redirect_uri must correspond to an existing client application
// that was granted the ept:logout permission, unless endpoint permissions checking was explicitly disabled.
await using var enumerator = _applicationManager.FindByPostLogoutRedirectUriAsync(address).GetAsyncEnumerator();
if (await enumerator.MoveNextAsync())
{
if (context.Options.IgnoreEndpointPermissions)
{
return true;
}
do
{
if (await _applicationManager.HasPermissionAsync(enumerator.Current, Permissions.Endpoints.Logout))
{
return true;
}
}
while (await enumerator.MoveNextAsync());
}
return false;
}
}
}

Loading…
Cancel
Save