Browse Source

Add nullable annotations to OpenIddict.EntityFramework

pull/1038/head
Kévin Chalet 6 years ago
parent
commit
a4a57f30c2
  1. 2
      src/OpenIddict.EntityFramework/Configurations/OpenIddictEntityFrameworkApplicationConfiguration.cs
  2. 2
      src/OpenIddict.EntityFramework/Configurations/OpenIddictEntityFrameworkAuthorizationConfiguration.cs
  3. 2
      src/OpenIddict.EntityFramework/Configurations/OpenIddictEntityFrameworkScopeConfiguration.cs
  4. 2
      src/OpenIddict.EntityFramework/Configurations/OpenIddictEntityFrameworkTokenConfiguration.cs
  5. 1
      src/OpenIddict.EntityFramework/OpenIddict.EntityFramework.csproj
  6. 11
      src/OpenIddict.EntityFramework/OpenIddictEntityFrameworkBuilder.cs
  7. 6
      src/OpenIddict.EntityFramework/OpenIddictEntityFrameworkExtensions.cs
  8. 7
      src/OpenIddict.EntityFramework/OpenIddictEntityFrameworkHelpers.cs
  9. 2
      src/OpenIddict.EntityFramework/OpenIddictEntityFrameworkOptions.cs
  10. 7
      src/OpenIddict.EntityFramework/Resolvers/OpenIddictEntityFrameworkApplicationStoreResolver.cs
  11. 7
      src/OpenIddict.EntityFramework/Resolvers/OpenIddictEntityFrameworkAuthorizationStoreResolver.cs
  12. 7
      src/OpenIddict.EntityFramework/Resolvers/OpenIddictEntityFrameworkScopeStoreResolver.cs
  13. 7
      src/OpenIddict.EntityFramework/Resolvers/OpenIddictEntityFrameworkTokenStoreResolver.cs
  14. 453
      src/OpenIddict.EntityFramework/Stores/OpenIddictEntityFrameworkApplicationStore.cs
  15. 403
      src/OpenIddict.EntityFramework/Stores/OpenIddictEntityFrameworkAuthorizationStore.cs
  16. 345
      src/OpenIddict.EntityFramework/Stores/OpenIddictEntityFrameworkScopeStore.cs
  17. 489
      src/OpenIddict.EntityFramework/Stores/OpenIddictEntityFrameworkTokenStore.cs

2
src/OpenIddict.EntityFramework/Configurations/OpenIddictEntityFrameworkApplicationConfiguration.cs

@ -33,7 +33,7 @@ namespace OpenIddict.EntityFramework
// Entity Framework would throw an exception due to the TKey generic parameter
// being non-nullable when using value types like short, int, long or Guid.
HasKey(application => application.Id);
HasKey(application => application.Id!);
Property(application => application.ClientId)
.HasMaxLength(100)

2
src/OpenIddict.EntityFramework/Configurations/OpenIddictEntityFrameworkAuthorizationConfiguration.cs

@ -31,7 +31,7 @@ namespace OpenIddict.EntityFramework
// Entity Framework would throw an exception due to the TKey generic parameter
// being non-nullable when using value types like short, int, long or Guid.
HasKey(authorization => authorization.Id);
HasKey(authorization => authorization.Id!);
Property(authorization => authorization.ConcurrencyToken)
.HasMaxLength(50)

2
src/OpenIddict.EntityFramework/Configurations/OpenIddictEntityFrameworkScopeConfiguration.cs

@ -29,7 +29,7 @@ namespace OpenIddict.EntityFramework
// Entity Framework would throw an exception due to the TKey generic parameter
// being non-nullable when using value types like short, int, long or Guid.
HasKey(scope => scope.Id);
HasKey(scope => scope.Id!);
Property(scope => scope.ConcurrencyToken)
.HasMaxLength(50)

2
src/OpenIddict.EntityFramework/Configurations/OpenIddictEntityFrameworkTokenConfiguration.cs

@ -33,7 +33,7 @@ namespace OpenIddict.EntityFramework
// Entity Framework would throw an exception due to the TKey generic parameter
// being non-nullable when using value types like short, int, long or Guid.
HasKey(token => token.Id);
HasKey(token => token.Id!);
Property(token => token.ConcurrencyToken)
.HasMaxLength(50)

1
src/OpenIddict.EntityFramework/OpenIddict.EntityFramework.csproj

@ -2,6 +2,7 @@
<PropertyGroup>
<TargetFrameworks>net461;netstandard2.1</TargetFrameworks>
<Nullable>enable</Nullable>
</PropertyGroup>
<PropertyGroup>

11
src/OpenIddict.EntityFramework/OpenIddictEntityFrameworkBuilder.cs

@ -7,7 +7,6 @@
using System;
using System.ComponentModel;
using System.Data.Entity;
using JetBrains.Annotations;
using Microsoft.Extensions.DependencyInjection.Extensions;
using OpenIddict.Core;
using OpenIddict.EntityFramework;
@ -25,7 +24,7 @@ namespace Microsoft.Extensions.DependencyInjection
/// Initializes a new instance of <see cref="OpenIddictEntityFrameworkBuilder"/>.
/// </summary>
/// <param name="services">The services collection.</param>
public OpenIddictEntityFrameworkBuilder([NotNull] IServiceCollection services)
public OpenIddictEntityFrameworkBuilder(IServiceCollection services)
=> Services = services ?? throw new ArgumentNullException(nameof(services));
/// <summary>
@ -40,7 +39,7 @@ namespace Microsoft.Extensions.DependencyInjection
/// <param name="configuration">The delegate used to configure the OpenIddict options.</param>
/// <remarks>This extension can be safely called multiple times.</remarks>
/// <returns>The <see cref="OpenIddictEntityFrameworkBuilder"/>.</returns>
public OpenIddictEntityFrameworkBuilder Configure([NotNull] Action<OpenIddictEntityFrameworkOptions> configuration)
public OpenIddictEntityFrameworkBuilder Configure(Action<OpenIddictEntityFrameworkOptions> configuration)
{
if (configuration == null)
{
@ -98,7 +97,7 @@ namespace Microsoft.Extensions.DependencyInjection
/// </summary>
/// <param name="type">The type of the <see cref="DbContext"/> used by OpenIddict.</param>
/// <returns>The <see cref="OpenIddictEntityFrameworkBuilder"/>.</returns>
public OpenIddictEntityFrameworkBuilder UseDbContext([NotNull] Type type)
public OpenIddictEntityFrameworkBuilder UseDbContext(Type type)
{
if (type == null)
{
@ -121,7 +120,7 @@ namespace Microsoft.Extensions.DependencyInjection
/// <param name="obj">The object to compare with the current object.</param>
/// <returns><c>true</c> if the specified object is equal to the current object; otherwise, false.</returns>
[EditorBrowsable(EditorBrowsableState.Never)]
public override bool Equals([CanBeNull] object obj) => base.Equals(obj);
public override bool Equals(object? obj) => base.Equals(obj);
/// <summary>
/// Serves as the default hash function.
@ -135,6 +134,6 @@ namespace Microsoft.Extensions.DependencyInjection
/// </summary>
/// <returns>A string that represents the current object.</returns>
[EditorBrowsable(EditorBrowsableState.Never)]
public override string ToString() => base.ToString();
public override string? ToString() => base.ToString();
}
}

6
src/OpenIddict.EntityFramework/OpenIddictEntityFrameworkExtensions.cs

@ -5,7 +5,6 @@
*/
using System;
using JetBrains.Annotations;
using Microsoft.Extensions.DependencyInjection.Extensions;
using OpenIddict.EntityFramework;
using OpenIddict.EntityFramework.Models;
@ -24,7 +23,7 @@ namespace Microsoft.Extensions.DependencyInjection
/// <param name="builder">The services builder used by OpenIddict to register new services.</param>
/// <remarks>This extension can be safely called multiple times.</remarks>
/// <returns>The <see cref="OpenIddictEntityFrameworkBuilder"/>.</returns>
public static OpenIddictEntityFrameworkBuilder UseEntityFramework([NotNull] this OpenIddictCoreBuilder builder)
public static OpenIddictEntityFrameworkBuilder UseEntityFramework(this OpenIddictCoreBuilder builder)
{
if (builder == null)
{
@ -68,8 +67,7 @@ namespace Microsoft.Extensions.DependencyInjection
/// <remarks>This extension can be safely called multiple times.</remarks>
/// <returns>The <see cref="OpenIddictCoreBuilder"/>.</returns>
public static OpenIddictCoreBuilder UseEntityFramework(
[NotNull] this OpenIddictCoreBuilder builder,
[NotNull] Action<OpenIddictEntityFrameworkBuilder> configuration)
this OpenIddictCoreBuilder builder, Action<OpenIddictEntityFrameworkBuilder> configuration)
{
if (builder == null)
{

7
src/OpenIddict.EntityFramework/OpenIddictEntityFrameworkHelpers.cs

@ -8,7 +8,6 @@ using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Threading;
using JetBrains.Annotations;
using Microsoft.Extensions.DependencyInjection;
using OpenIddict.EntityFramework;
using OpenIddict.EntityFramework.Models;
@ -26,7 +25,7 @@ namespace System.Data.Entity
/// </summary>
/// <param name="builder">The builder used to configure the Entity Framework context.</param>
/// <returns>The Entity Framework context builder.</returns>
public static DbModelBuilder UseOpenIddict([NotNull] this DbModelBuilder builder)
public static DbModelBuilder UseOpenIddict(this DbModelBuilder builder)
=> builder.UseOpenIddict<OpenIddictEntityFrameworkApplication,
OpenIddictEntityFrameworkAuthorization,
OpenIddictEntityFrameworkScope,
@ -42,7 +41,7 @@ namespace System.Data.Entity
/// </remarks>
/// <param name="builder">The builder used to configure the Entity Framework context.</param>
/// <returns>The Entity Framework context builder.</returns>
public static DbModelBuilder UseOpenIddict<TApplication, TAuthorization, TScope, TToken, TKey>([NotNull] this DbModelBuilder builder)
public static DbModelBuilder UseOpenIddict<TApplication, TAuthorization, TScope, TToken, TKey>(this DbModelBuilder builder)
where TApplication : OpenIddictEntityFrameworkApplication<TKey, TAuthorization, TToken>
where TAuthorization : OpenIddictEntityFrameworkAuthorization<TKey, TApplication, TToken>
where TScope : OpenIddictEntityFrameworkScope<TKey>
@ -70,7 +69,7 @@ namespace System.Data.Entity
/// <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)
internal static IAsyncEnumerable<T> AsAsyncEnumerable<T>(this IQueryable<T> source, CancellationToken cancellationToken)
{
if (source == null)
{

2
src/OpenIddict.EntityFramework/OpenIddictEntityFrameworkOptions.cs

@ -20,6 +20,6 @@ namespace OpenIddict.EntityFramework
/// OpenIddict Entity Framework 6.x stores. If this property is not populated,
/// an exception is thrown at runtime when trying to use the stores.
/// </summary>
public Type DbContextType { get; set; }
public Type? DbContextType { get; set; }
}
}

7
src/OpenIddict.EntityFramework/Resolvers/OpenIddictEntityFrameworkApplicationStoreResolver.cs

@ -6,7 +6,6 @@
using System;
using System.Collections.Concurrent;
using JetBrains.Annotations;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using OpenIddict.Abstractions;
@ -26,9 +25,9 @@ namespace OpenIddict.EntityFramework
private readonly IServiceProvider _provider;
public OpenIddictEntityFrameworkApplicationStoreResolver(
[NotNull] TypeResolutionCache cache,
[NotNull] IOptionsMonitor<OpenIddictEntityFrameworkOptions> options,
[NotNull] IServiceProvider provider)
TypeResolutionCache cache,
IOptionsMonitor<OpenIddictEntityFrameworkOptions> options,
IServiceProvider provider)
{
_cache = cache;
_options = options;

7
src/OpenIddict.EntityFramework/Resolvers/OpenIddictEntityFrameworkAuthorizationStoreResolver.cs

@ -6,7 +6,6 @@
using System;
using System.Collections.Concurrent;
using JetBrains.Annotations;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using OpenIddict.Abstractions;
@ -26,9 +25,9 @@ namespace OpenIddict.EntityFramework
private readonly IServiceProvider _provider;
public OpenIddictEntityFrameworkAuthorizationStoreResolver(
[NotNull] TypeResolutionCache cache,
[NotNull] IOptionsMonitor<OpenIddictEntityFrameworkOptions> options,
[NotNull] IServiceProvider provider)
TypeResolutionCache cache,
IOptionsMonitor<OpenIddictEntityFrameworkOptions> options,
IServiceProvider provider)
{
_cache = cache;
_options = options;

7
src/OpenIddict.EntityFramework/Resolvers/OpenIddictEntityFrameworkScopeStoreResolver.cs

@ -6,7 +6,6 @@
using System;
using System.Collections.Concurrent;
using JetBrains.Annotations;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using OpenIddict.Abstractions;
@ -26,9 +25,9 @@ namespace OpenIddict.EntityFramework
private readonly IServiceProvider _provider;
public OpenIddictEntityFrameworkScopeStoreResolver(
[NotNull] TypeResolutionCache cache,
[NotNull] IOptionsMonitor<OpenIddictEntityFrameworkOptions> options,
[NotNull] IServiceProvider provider)
TypeResolutionCache cache,
IOptionsMonitor<OpenIddictEntityFrameworkOptions> options,
IServiceProvider provider)
{
_cache = cache;
_options = options;

7
src/OpenIddict.EntityFramework/Resolvers/OpenIddictEntityFrameworkTokenStoreResolver.cs

@ -6,7 +6,6 @@
using System;
using System.Collections.Concurrent;
using JetBrains.Annotations;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using OpenIddict.Abstractions;
@ -26,9 +25,9 @@ namespace OpenIddict.EntityFramework
private readonly IServiceProvider _provider;
public OpenIddictEntityFrameworkTokenStoreResolver(
[NotNull] TypeResolutionCache cache,
[NotNull] IOptionsMonitor<OpenIddictEntityFrameworkOptions> options,
[NotNull] IServiceProvider provider)
TypeResolutionCache cache,
IOptionsMonitor<OpenIddictEntityFrameworkOptions> options,
IServiceProvider provider)
{
_cache = cache;
_options = options;

453
src/OpenIddict.EntityFramework/Stores/OpenIddictEntityFrameworkApplicationStore.cs

@ -11,6 +11,7 @@ using System.ComponentModel;
using System.Data;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.IO;
using System.Linq;
@ -20,7 +21,6 @@ using System.Text.Encodings.Web;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using JetBrains.Annotations;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Options;
using OpenIddict.Abstractions;
@ -40,9 +40,9 @@ namespace OpenIddict.EntityFramework
where TContext : DbContext
{
public OpenIddictEntityFrameworkApplicationStore(
[NotNull] IMemoryCache cache,
[NotNull] TContext context,
[NotNull] IOptionsMonitor<OpenIddictEntityFrameworkOptions> options)
IMemoryCache cache,
TContext context,
IOptionsMonitor<OpenIddictEntityFrameworkOptions> options)
: base(cache, context, options)
{
}
@ -64,9 +64,9 @@ namespace OpenIddict.EntityFramework
where TKey : IEquatable<TKey>
{
public OpenIddictEntityFrameworkApplicationStore(
[NotNull] IMemoryCache cache,
[NotNull] TContext context,
[NotNull] IOptionsMonitor<OpenIddictEntityFrameworkOptions> options)
IMemoryCache cache,
TContext context,
IOptionsMonitor<OpenIddictEntityFrameworkOptions> options)
{
Cache = cache;
Context = context;
@ -103,28 +103,12 @@ namespace OpenIddict.EntityFramework
/// </summary>
private DbSet<TToken> Tokens => Context.Set<TToken>();
/// <summary>
/// Determines the number of applications that exist in the database.
/// </summary>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the number of applications in the database.
/// </returns>
/// <inheritdoc/>
public virtual async ValueTask<long> CountAsync(CancellationToken cancellationToken)
=> await Applications.LongCountAsync(cancellationToken);
/// <summary>
/// Determines the number of applications that match the specified query.
/// </summary>
/// <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="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 ValueTask<long> CountAsync<TResult>([NotNull] Func<IQueryable<TApplication>, IQueryable<TResult>> query, CancellationToken cancellationToken)
/// <inheritdoc/>
public virtual async ValueTask<long> CountAsync<TResult>(Func<IQueryable<TApplication>, IQueryable<TResult>> query, CancellationToken cancellationToken)
{
if (query == null)
{
@ -134,13 +118,8 @@ namespace OpenIddict.EntityFramework
return await query(Applications).LongCountAsync(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="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual async ValueTask CreateAsync([NotNull] TApplication application, CancellationToken cancellationToken)
/// <inheritdoc/>
public virtual async ValueTask CreateAsync(TApplication application, CancellationToken cancellationToken)
{
if (application == null)
{
@ -152,20 +131,15 @@ namespace OpenIddict.EntityFramework
await Context.SaveChangesAsync(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="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual async ValueTask DeleteAsync([NotNull] TApplication application, CancellationToken cancellationToken)
/// <inheritdoc/>
public virtual async ValueTask DeleteAsync(TApplication application, CancellationToken cancellationToken)
{
if (application == null)
{
throw new ArgumentNullException(nameof(application));
}
DbContextTransaction CreateTransaction()
DbContextTransaction? CreateTransaction()
{
try
{
@ -180,13 +154,13 @@ namespace OpenIddict.EntityFramework
Task<List<TAuthorization>> ListAuthorizationsAsync()
=> (from authorization in Authorizations.Include(authorization => authorization.Tokens)
where authorization.Application.Id.Equals(application.Id)
where authorization.Application!.Id!.Equals(application.Id)
select authorization).ToListAsync(cancellationToken);
Task<List<TToken>> ListTokensAsync()
=> (from token in Tokens
where token.Authorization == null
where token.Application.Id.Equals(application.Id)
where token.Application!.Id!.Equals(application.Id)
select token).ToListAsync(cancellationToken);
// To prevent an SQL exception from being thrown if a new associated entity is
@ -241,16 +215,8 @@ namespace OpenIddict.EntityFramework
}
}
/// <summary>
/// Retrieves an application using its unique identifier.
/// </summary>
/// <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="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the client application corresponding to the identifier.
/// </returns>
public virtual async ValueTask<TApplication> FindByIdAsync([NotNull] string identifier, CancellationToken cancellationToken)
/// <inheritdoc/>
public virtual async ValueTask<TApplication?> FindByIdAsync(string identifier, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(identifier))
{
@ -260,20 +226,12 @@ namespace OpenIddict.EntityFramework
var key = ConvertIdentifierFromString(identifier);
return await (from application in Applications
where application.Id.Equals(key)
where application.Id!.Equals(key)
select application).FirstOrDefaultAsync(cancellationToken);
}
/// <summary>
/// Retrieves an application using its client identifier.
/// </summary>
/// <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="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the client application corresponding to the identifier.
/// </returns>
public virtual async ValueTask<TApplication> FindByClientIdAsync([NotNull] string identifier, CancellationToken cancellationToken)
/// <inheritdoc/>
public virtual async ValueTask<TApplication?> FindByClientIdAsync(string identifier, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(identifier))
{
@ -285,14 +243,9 @@ namespace OpenIddict.EntityFramework
select application).FirstOrDefaultAsync(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>The client applications corresponding to the specified post_logout_redirect_uri.</returns>
/// <inheritdoc/>
public virtual IAsyncEnumerable<TApplication> FindByPostLogoutRedirectUriAsync(
[NotNull] string address, CancellationToken cancellationToken)
string address, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(address))
{
@ -310,7 +263,7 @@ namespace OpenIddict.EntityFramework
async IAsyncEnumerable<TApplication> ExecuteAsync([EnumeratorCancellation] CancellationToken cancellationToken)
{
var applications = (from application in Applications
where application.PostLogoutRedirectUris.Contains(address)
where application.PostLogoutRedirectUris!.Contains(address)
select application).AsAsyncEnumerable(cancellationToken);
await foreach (var application in applications)
@ -324,14 +277,9 @@ namespace OpenIddict.EntityFramework
}
}
/// <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>The client applications corresponding to the specified redirect_uri.</returns>
/// <inheritdoc/>
public virtual IAsyncEnumerable<TApplication> FindByRedirectUriAsync(
[NotNull] string address, CancellationToken cancellationToken)
string address, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(address))
{
@ -349,7 +297,7 @@ namespace OpenIddict.EntityFramework
async IAsyncEnumerable<TApplication> ExecuteAsync([EnumeratorCancellation] CancellationToken cancellationToken)
{
var applications = (from application in Applications
where application.RedirectUris.Contains(address)
where application.RedirectUris!.Contains(address)
select application).AsAsyncEnumerable(cancellationToken);
await foreach (var application in applications)
@ -363,21 +311,10 @@ namespace OpenIddict.EntityFramework
}
}
/// <summary>
/// Executes the specified query and returns the first element.
/// </summary>
/// <typeparam name="TState">The state type.</typeparam>
/// <typeparam name="TResult">The result type.</typeparam>
/// <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="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the first element returned when executing the query.
/// </returns>
/// <inheritdoc/>
public virtual async ValueTask<TResult> GetAsync<TState, TResult>(
[NotNull] Func<IQueryable<TApplication>, TState, IQueryable<TResult>> query,
[CanBeNull] TState state, CancellationToken cancellationToken)
Func<IQueryable<TApplication>, TState, IQueryable<TResult>> query,
TState state, CancellationToken cancellationToken)
{
if (query == null)
{
@ -387,113 +324,63 @@ namespace OpenIddict.EntityFramework
return await query(Applications, state).FirstOrDefaultAsync(cancellationToken);
}
/// <summary>
/// Retrieves the client identifier associated with an application.
/// </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="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
/// whose result returns the client identifier associated with the application.
/// </returns>
public virtual ValueTask<string> GetClientIdAsync([NotNull] TApplication application, CancellationToken cancellationToken)
/// <inheritdoc/>
public virtual ValueTask<string?> GetClientIdAsync(TApplication application, CancellationToken cancellationToken)
{
if (application == null)
{
throw new ArgumentNullException(nameof(application));
}
return new ValueTask<string>(application.ClientId);
return new ValueTask<string?>(application.ClientId);
}
/// <summary>
/// Retrieves the client secret associated with an application.
/// Note: depending on the manager used to create the application,
/// the client secret may be hashed for security reasons.
/// </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="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
/// whose result returns the client secret associated with the application.
/// </returns>
public virtual ValueTask<string> GetClientSecretAsync([NotNull] TApplication application, CancellationToken cancellationToken)
/// <inheritdoc/>
public virtual ValueTask<string?> GetClientSecretAsync(TApplication application, CancellationToken cancellationToken)
{
if (application == null)
{
throw new ArgumentNullException(nameof(application));
}
return new ValueTask<string>(application.ClientSecret);
return new ValueTask<string?>(application.ClientSecret);
}
/// <summary>
/// Retrieves the client type associated with an application.
/// </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="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
/// whose result returns the client type of the application (by default, "public").
/// </returns>
public virtual ValueTask<string> GetClientTypeAsync([NotNull] TApplication application, CancellationToken cancellationToken)
/// <inheritdoc/>
public virtual ValueTask<string?> GetClientTypeAsync(TApplication application, CancellationToken cancellationToken)
{
if (application == null)
{
throw new ArgumentNullException(nameof(application));
}
return new ValueTask<string>(application.Type);
return new ValueTask<string?>(application.Type);
}
/// <summary>
/// Retrieves the consent type associated with an application.
/// </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="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
/// whose result returns the consent type of the application (by default, "explicit").
/// </returns>
public virtual ValueTask<string> GetConsentTypeAsync([NotNull] TApplication application, CancellationToken cancellationToken)
/// <inheritdoc/>
public virtual ValueTask<string?> GetConsentTypeAsync(TApplication application, CancellationToken cancellationToken)
{
if (application == null)
{
throw new ArgumentNullException(nameof(application));
}
return new ValueTask<string>(application.ConsentType);
return new ValueTask<string?>(application.ConsentType);
}
/// <summary>
/// Retrieves the display name associated with an application.
/// </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="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
/// whose result returns the display name associated with the application.
/// </returns>
public virtual ValueTask<string> GetDisplayNameAsync([NotNull] TApplication application, CancellationToken cancellationToken)
/// <inheritdoc/>
public virtual ValueTask<string?> GetDisplayNameAsync(TApplication application, CancellationToken cancellationToken)
{
if (application == null)
{
throw new ArgumentNullException(nameof(application));
}
return new ValueTask<string>(application.DisplayName);
return new ValueTask<string?>(application.DisplayName);
}
/// <summary>
/// Retrieves the localized display names associated with an application.
/// </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="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the localized display names associated with the application.
/// </returns>
public virtual ValueTask<ImmutableDictionary<CultureInfo, string>> GetDisplayNamesAsync([NotNull] TApplication application, CancellationToken cancellationToken)
/// <inheritdoc/>
public virtual ValueTask<ImmutableDictionary<CultureInfo, string>> GetDisplayNamesAsync(TApplication application, CancellationToken cancellationToken)
{
if (application == null)
{
@ -520,35 +407,19 @@ namespace OpenIddict.EntityFramework
return new ValueTask<ImmutableDictionary<CultureInfo, string>>(names);
}
/// <summary>
/// Retrieves the unique identifier associated with an application.
/// </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="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
/// whose result returns the unique identifier associated with the application.
/// </returns>
public virtual ValueTask<string> GetIdAsync([NotNull] TApplication application, CancellationToken cancellationToken)
/// <inheritdoc/>
public virtual ValueTask<string?> GetIdAsync(TApplication application, CancellationToken cancellationToken)
{
if (application == null)
{
throw new ArgumentNullException(nameof(application));
}
return new ValueTask<string>(ConvertIdentifierToString(application.Id));
return new ValueTask<string?>(ConvertIdentifierToString(application.Id));
}
/// <summary>
/// Retrieves the permissions associated with an application.
/// </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="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the permissions associated with the application.
/// </returns>
public virtual ValueTask<ImmutableArray<string>> GetPermissionsAsync([NotNull] TApplication application, CancellationToken cancellationToken)
/// <inheritdoc/>
public virtual ValueTask<ImmutableArray<string>> GetPermissionsAsync(TApplication application, CancellationToken cancellationToken)
{
if (application == null)
{
@ -574,16 +445,8 @@ namespace OpenIddict.EntityFramework
return new ValueTask<ImmutableArray<string>>(permissions);
}
/// <summary>
/// Retrieves the logout callback addresses associated with an application.
/// </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="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the post_logout_redirect_uri associated with the application.
/// </returns>
public virtual ValueTask<ImmutableArray<string>> GetPostLogoutRedirectUrisAsync([NotNull] TApplication application, CancellationToken cancellationToken)
/// <inheritdoc/>
public virtual ValueTask<ImmutableArray<string>> GetPostLogoutRedirectUrisAsync(TApplication application, CancellationToken cancellationToken)
{
if (application == null)
{
@ -609,16 +472,8 @@ namespace OpenIddict.EntityFramework
return new ValueTask<ImmutableArray<string>>(addresses);
}
/// <summary>
/// Retrieves the additional properties associated with an application.
/// </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="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the additional properties associated with the application.
/// </returns>
public virtual ValueTask<ImmutableDictionary<string, JsonElement>> GetPropertiesAsync([NotNull] TApplication application, CancellationToken cancellationToken)
/// <inheritdoc/>
public virtual ValueTask<ImmutableDictionary<string, JsonElement>> GetPropertiesAsync(TApplication application, CancellationToken cancellationToken)
{
if (application == null)
{
@ -644,16 +499,8 @@ namespace OpenIddict.EntityFramework
return new ValueTask<ImmutableDictionary<string, JsonElement>>(properties);
}
/// <summary>
/// Retrieves the callback addresses associated with an application.
/// </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="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the redirect_uri associated with the application.
/// </returns>
public virtual ValueTask<ImmutableArray<string>> GetRedirectUrisAsync([NotNull] TApplication application, CancellationToken cancellationToken)
/// <inheritdoc/>
public virtual ValueTask<ImmutableArray<string>> GetRedirectUrisAsync(TApplication application, CancellationToken cancellationToken)
{
if (application == null)
{
@ -679,16 +526,8 @@ namespace OpenIddict.EntityFramework
return new ValueTask<ImmutableArray<string>>(addresses);
}
/// <summary>
/// Retrieves the requirements associated with an application.
/// </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="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the requirements associated with the application.
/// </returns>
public virtual ValueTask<ImmutableArray<string>> GetRequirementsAsync([NotNull] TApplication application, CancellationToken cancellationToken)
/// <inheritdoc/>
public virtual ValueTask<ImmutableArray<string>> GetRequirementsAsync(TApplication application, CancellationToken cancellationToken)
{
if (application == null)
{
@ -714,14 +553,7 @@ namespace OpenIddict.EntityFramework
return new ValueTask<ImmutableArray<string>>(requirements);
}
/// <summary>
/// Instantiates a new application.
/// </summary>
/// <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 instantiated application, that can be persisted in the database.
/// </returns>
/// <inheritdoc/>
public virtual ValueTask<TApplication> InstantiateAsync(CancellationToken cancellationToken)
{
try
@ -736,17 +568,11 @@ namespace OpenIddict.EntityFramework
}
}
/// <summary>
/// Executes the specified query and returns all the corresponding elements.
/// </summary>
/// <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>All the elements returned when executing the specified query.</returns>
/// <inheritdoc/>
public virtual IAsyncEnumerable<TApplication> ListAsync(
[CanBeNull] int? count, [CanBeNull] int? offset, CancellationToken cancellationToken)
int? count, int? offset, CancellationToken cancellationToken)
{
var query = Applications.OrderBy(application => application.Id).AsQueryable();
var query = Applications.OrderBy(application => application.Id!).AsQueryable();
if (offset.HasValue)
{
@ -761,18 +587,10 @@ namespace OpenIddict.EntityFramework
return query.AsAsyncEnumerable(cancellationToken);
}
/// <summary>
/// Executes the specified query and returns all the corresponding elements.
/// </summary>
/// <typeparam name="TState">The state type.</typeparam>
/// <typeparam name="TResult">The result type.</typeparam>
/// <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>All the elements returned when executing the specified query.</returns>
/// <inheritdoc/>
public virtual IAsyncEnumerable<TResult> ListAsync<TState, TResult>(
[NotNull] Func<IQueryable<TApplication>, TState, IQueryable<TResult>> query,
[CanBeNull] TState state, CancellationToken cancellationToken)
Func<IQueryable<TApplication>, TState, IQueryable<TResult>> query,
TState state, CancellationToken cancellationToken)
{
if (query == null)
{
@ -782,15 +600,8 @@ namespace OpenIddict.EntityFramework
return query(Applications, state).AsAsyncEnumerable(cancellationToken);
}
/// <summary>
/// Sets the client identifier associated with an application.
/// </summary>
/// <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="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetClientIdAsync([NotNull] TApplication application,
[CanBeNull] string identifier, CancellationToken cancellationToken)
/// <inheritdoc/>
public virtual ValueTask SetClientIdAsync(TApplication application, string? identifier, CancellationToken cancellationToken)
{
if (application == null)
{
@ -802,17 +613,8 @@ namespace OpenIddict.EntityFramework
return default;
}
/// <summary>
/// Sets the client secret associated with an application.
/// Note: depending on the manager used to create the application,
/// the client secret may be hashed for security reasons.
/// </summary>
/// <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="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetClientSecretAsync([NotNull] TApplication application,
[CanBeNull] string secret, CancellationToken cancellationToken)
/// <inheritdoc/>
public virtual ValueTask SetClientSecretAsync(TApplication application, string? secret, CancellationToken cancellationToken)
{
if (application == null)
{
@ -824,15 +626,8 @@ namespace OpenIddict.EntityFramework
return default;
}
/// <summary>
/// Sets the client type associated with an application.
/// </summary>
/// <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="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetClientTypeAsync([NotNull] TApplication application,
[CanBeNull] string type, CancellationToken cancellationToken)
/// <inheritdoc/>
public virtual ValueTask SetClientTypeAsync(TApplication application, string? type, CancellationToken cancellationToken)
{
if (application == null)
{
@ -844,15 +639,8 @@ namespace OpenIddict.EntityFramework
return default;
}
/// <summary>
/// Sets the consent type associated with an application.
/// </summary>
/// <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="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetConsentTypeAsync([NotNull] TApplication application,
[CanBeNull] string type, CancellationToken cancellationToken)
/// <inheritdoc/>
public virtual ValueTask SetConsentTypeAsync(TApplication application, string? type, CancellationToken cancellationToken)
{
if (application == null)
{
@ -864,15 +652,8 @@ namespace OpenIddict.EntityFramework
return default;
}
/// <summary>
/// Sets the display name associated with an application.
/// </summary>
/// <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="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetDisplayNameAsync([NotNull] TApplication application,
[CanBeNull] string name, CancellationToken cancellationToken)
/// <inheritdoc/>
public virtual ValueTask SetDisplayNameAsync(TApplication application, string? name, CancellationToken cancellationToken)
{
if (application == null)
{
@ -884,15 +665,9 @@ namespace OpenIddict.EntityFramework
return default;
}
/// <summary>
/// Sets the localized display names associated with an application.
/// </summary>
/// <param name="application">The application.</param>
/// <param name="names">The localized display names 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="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetDisplayNamesAsync([NotNull] TApplication application,
[CanBeNull] ImmutableDictionary<CultureInfo, string> names, CancellationToken cancellationToken)
/// <inheritdoc/>
public virtual ValueTask SetDisplayNamesAsync(TApplication application,
ImmutableDictionary<CultureInfo, string> names, CancellationToken cancellationToken)
{
if (application == null)
{
@ -929,14 +704,8 @@ namespace OpenIddict.EntityFramework
return default;
}
/// <summary>
/// Sets the permissions associated with an application.
/// </summary>
/// <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="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetPermissionsAsync([NotNull] TApplication application, ImmutableArray<string> permissions, CancellationToken cancellationToken)
/// <inheritdoc/>
public virtual ValueTask SetPermissionsAsync(TApplication application, ImmutableArray<string> permissions, CancellationToken cancellationToken)
{
if (application == null)
{
@ -959,14 +728,8 @@ namespace OpenIddict.EntityFramework
return default;
}
/// <summary>
/// Sets the logout callback addresses associated with an application.
/// </summary>
/// <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="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetPostLogoutRedirectUrisAsync([NotNull] TApplication application,
/// <inheritdoc/>
public virtual ValueTask SetPostLogoutRedirectUrisAsync(TApplication application,
ImmutableArray<string> addresses, CancellationToken cancellationToken)
{
if (application == null)
@ -990,15 +753,9 @@ namespace OpenIddict.EntityFramework
return default;
}
/// <summary>
/// Sets the additional properties associated with an application.
/// </summary>
/// <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="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetPropertiesAsync([NotNull] TApplication application,
[CanBeNull] ImmutableDictionary<string, JsonElement> properties, CancellationToken cancellationToken)
/// <inheritdoc/>
public virtual ValueTask SetPropertiesAsync(TApplication application,
ImmutableDictionary<string, JsonElement> properties, CancellationToken cancellationToken)
{
if (application == null)
{
@ -1021,14 +778,8 @@ namespace OpenIddict.EntityFramework
return default;
}
/// <summary>
/// Sets the callback addresses associated with an application.
/// </summary>
/// <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="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetRedirectUrisAsync([NotNull] TApplication application,
/// <inheritdoc/>
public virtual ValueTask SetRedirectUrisAsync(TApplication application,
ImmutableArray<string> addresses, CancellationToken cancellationToken)
{
if (application == null)
@ -1052,14 +803,8 @@ namespace OpenIddict.EntityFramework
return default;
}
/// <summary>
/// Sets the requirements associated with an application.
/// </summary>
/// <param name="application">The application.</param>
/// <param name="requirements">The requirements 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="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetRequirementsAsync([NotNull] TApplication application, ImmutableArray<string> requirements, CancellationToken cancellationToken)
/// <inheritdoc/>
public virtual ValueTask SetRequirementsAsync(TApplication application, ImmutableArray<string> requirements, CancellationToken cancellationToken)
{
if (application == null)
{
@ -1082,13 +827,8 @@ namespace OpenIddict.EntityFramework
return default;
}
/// <summary>
/// Updates an existing application.
/// </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="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual async ValueTask UpdateAsync([NotNull] TApplication application, CancellationToken cancellationToken)
/// <inheritdoc/>
public virtual async ValueTask UpdateAsync(TApplication application, CancellationToken cancellationToken)
{
if (application == null)
{
@ -1122,7 +862,8 @@ namespace OpenIddict.EntityFramework
/// </summary>
/// <param name="identifier">The identifier to convert.</param>
/// <returns>An instance of <typeparamref name="TKey"/> representing the provided identifier.</returns>
public virtual TKey ConvertIdentifierFromString([CanBeNull] string identifier)
[return: MaybeNull]
public virtual TKey ConvertIdentifierFromString(string? identifier)
{
if (string.IsNullOrEmpty(identifier))
{
@ -1137,7 +878,7 @@ namespace OpenIddict.EntityFramework
/// </summary>
/// <param name="identifier">The identifier to convert.</param>
/// <returns>A <see cref="string"/> representation of the provided identifier.</returns>
public virtual string ConvertIdentifierToString([CanBeNull] TKey identifier)
public virtual string? ConvertIdentifierToString([AllowNull] TKey identifier)
{
if (Equals(identifier, default(TKey)))
{

403
src/OpenIddict.EntityFramework/Stores/OpenIddictEntityFrameworkAuthorizationStore.cs

@ -11,13 +11,13 @@ using System.ComponentModel;
using System.Data;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text.Encodings.Web;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using JetBrains.Annotations;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Options;
using OpenIddict.Abstractions;
@ -37,9 +37,9 @@ namespace OpenIddict.EntityFramework
where TContext : DbContext
{
public OpenIddictEntityFrameworkAuthorizationStore(
[NotNull] IMemoryCache cache,
[NotNull] TContext context,
[NotNull] IOptionsMonitor<OpenIddictEntityFrameworkOptions> options)
IMemoryCache cache,
TContext context,
IOptionsMonitor<OpenIddictEntityFrameworkOptions> options)
: base(cache, context, options)
{
}
@ -61,9 +61,9 @@ namespace OpenIddict.EntityFramework
where TKey : IEquatable<TKey>
{
public OpenIddictEntityFrameworkAuthorizationStore(
[NotNull] IMemoryCache cache,
[NotNull] TContext context,
[NotNull] IOptionsMonitor<OpenIddictEntityFrameworkOptions> options)
IMemoryCache cache,
TContext context,
IOptionsMonitor<OpenIddictEntityFrameworkOptions> options)
{
Cache = cache;
Context = context;
@ -100,28 +100,12 @@ namespace OpenIddict.EntityFramework
/// </summary>
private DbSet<TToken> Tokens => Context.Set<TToken>();
/// <summary>
/// Determines the number of authorizations that exist in the database.
/// </summary>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the number of authorizations in the database.
/// </returns>
/// <inheritdoc/>
public virtual async ValueTask<long> CountAsync(CancellationToken cancellationToken)
=> await Authorizations.LongCountAsync(cancellationToken);
/// <summary>
/// Determines the number of authorizations that match the specified query.
/// </summary>
/// <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="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 ValueTask<long> CountAsync<TResult>([NotNull] Func<IQueryable<TAuthorization>, IQueryable<TResult>> query, CancellationToken cancellationToken)
/// <inheritdoc/>
public virtual async ValueTask<long> CountAsync<TResult>(Func<IQueryable<TAuthorization>, IQueryable<TResult>> query, CancellationToken cancellationToken)
{
if (query == null)
{
@ -131,13 +115,8 @@ namespace OpenIddict.EntityFramework
return await query(Authorizations).LongCountAsync(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="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual async ValueTask CreateAsync([NotNull] TAuthorization authorization, CancellationToken cancellationToken)
/// <inheritdoc/>
public virtual async ValueTask CreateAsync(TAuthorization authorization, CancellationToken cancellationToken)
{
if (authorization == null)
{
@ -149,20 +128,15 @@ namespace OpenIddict.EntityFramework
await Context.SaveChangesAsync(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="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual async ValueTask DeleteAsync([NotNull] TAuthorization authorization, CancellationToken cancellationToken)
/// <inheritdoc/>
public virtual async ValueTask DeleteAsync(TAuthorization authorization, CancellationToken cancellationToken)
{
if (authorization == null)
{
throw new ArgumentNullException(nameof(authorization));
}
DbContextTransaction CreateTransaction()
DbContextTransaction? CreateTransaction()
{
try
{
@ -177,7 +151,7 @@ namespace OpenIddict.EntityFramework
Task<List<TToken>> ListTokensAsync()
=> (from token in Tokens
where token.Authorization.Id.Equals(authorization.Id)
where token.Authorization!.Id!.Equals(authorization.Id)
select token).ToListAsync(cancellationToken);
// To prevent an SQL exception from being thrown if a new associated entity is
@ -214,16 +188,9 @@ namespace OpenIddict.EntityFramework
}
}
/// <summary>
/// Retrieves the authorizations corresponding to the specified
/// subject and associated with the application identifier.
/// </summary>
/// <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>The authorizations corresponding to the subject/client.</returns>
/// <inheritdoc/>
public virtual IAsyncEnumerable<TAuthorization> FindAsync(
[NotNull] string subject, [NotNull] string client, CancellationToken cancellationToken)
string subject, string client, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(subject))
{
@ -239,22 +206,15 @@ namespace OpenIddict.EntityFramework
return (from authorization in Authorizations.Include(authorization => authorization.Application)
where authorization.Application != null &&
authorization.Application.Id.Equals(key) &&
authorization.Application.Id!.Equals(key) &&
authorization.Subject == subject
select authorization).AsAsyncEnumerable(cancellationToken);
}
/// <summary>
/// Retrieves the authorizations matching the specified parameters.
/// </summary>
/// <param name="subject">The subject associated with the authorization.</param>
/// <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>The authorizations corresponding to the criteria.</returns>
/// <inheritdoc/>
public virtual IAsyncEnumerable<TAuthorization> FindAsync(
[NotNull] string subject, [NotNull] string client,
[NotNull] string status, CancellationToken cancellationToken)
string subject, string client,
string status, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(subject))
{
@ -275,24 +235,16 @@ namespace OpenIddict.EntityFramework
return (from authorization in Authorizations.Include(authorization => authorization.Application)
where authorization.Application != null &&
authorization.Application.Id.Equals(key) &&
authorization.Application.Id!.Equals(key) &&
authorization.Subject == subject &&
authorization.Status == status
select authorization).AsAsyncEnumerable(cancellationToken);
}
/// <summary>
/// Retrieves the authorizations matching the specified parameters.
/// </summary>
/// <param name="subject">The subject associated with the authorization.</param>
/// <param name="client">The client associated with the authorization.</param>
/// <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>The authorizations corresponding to the criteria.</returns>
/// <inheritdoc/>
public virtual IAsyncEnumerable<TAuthorization> FindAsync(
[NotNull] string subject, [NotNull] string client,
[NotNull] string status, [NotNull] string type, CancellationToken cancellationToken)
string subject, string client,
string status, string type, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(subject))
{
@ -318,26 +270,17 @@ namespace OpenIddict.EntityFramework
return (from authorization in Authorizations.Include(authorization => authorization.Application)
where authorization.Application != null &&
authorization.Application.Id.Equals(key) &&
authorization.Application.Id!.Equals(key) &&
authorization.Subject == subject &&
authorization.Status == status &&
authorization.Type == type
select authorization).AsAsyncEnumerable(cancellationToken);
}
/// <summary>
/// Retrieves the authorizations matching the specified parameters.
/// </summary>
/// <param name="subject">The subject associated with the authorization.</param>
/// <param name="client">The client associated with the authorization.</param>
/// <param name="status">The authorization status.</param>
/// <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>The authorizations corresponding to the criteria.</returns>
/// <inheritdoc/>
public virtual IAsyncEnumerable<TAuthorization> FindAsync(
[NotNull] string subject, [NotNull] string client,
[NotNull] string status, [NotNull] string type,
string subject, string client,
string status, string type,
ImmutableArray<string> scopes, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(subject))
@ -368,7 +311,7 @@ namespace OpenIddict.EntityFramework
var authorizations = (from authorization in Authorizations.Include(authorization => authorization.Application)
where authorization.Application != null &&
authorization.Application.Id.Equals(key) &&
authorization.Application.Id!.Equals(key) &&
authorization.Subject == subject &&
authorization.Status == status &&
authorization.Type == type
@ -384,14 +327,9 @@ namespace OpenIddict.EntityFramework
}
}
/// <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>The authorizations corresponding to the specified application.</returns>
/// <inheritdoc/>
public virtual IAsyncEnumerable<TAuthorization> FindByApplicationIdAsync(
[NotNull] string identifier, CancellationToken cancellationToken)
string identifier, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(identifier))
{
@ -401,20 +339,12 @@ namespace OpenIddict.EntityFramework
var key = ConvertIdentifierFromString(identifier);
return (from authorization in Authorizations.Include(authorization => authorization.Application)
where authorization.Application.Id.Equals(key)
where authorization.Application!.Id!.Equals(key)
select authorization).AsAsyncEnumerable(cancellationToken);
}
/// <summary>
/// Retrieves an authorization using its unique identifier.
/// </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="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the authorization corresponding to the identifier.
/// </returns>
public virtual async ValueTask<TAuthorization> FindByIdAsync([NotNull] string identifier, CancellationToken cancellationToken)
/// <inheritdoc/>
public virtual async ValueTask<TAuthorization?> FindByIdAsync(string identifier, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(identifier))
{
@ -424,18 +354,13 @@ namespace OpenIddict.EntityFramework
var key = ConvertIdentifierFromString(identifier);
return await (from authorization in Authorizations.Include(authorization => authorization.Application)
where authorization.Id.Equals(key)
where authorization.Id!.Equals(key)
select authorization).FirstOrDefaultAsync(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>The authorizations corresponding to the specified subject.</returns>
/// <inheritdoc/>
public virtual IAsyncEnumerable<TAuthorization> FindBySubjectAsync(
[NotNull] string subject, CancellationToken cancellationToken)
string subject, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(subject))
{
@ -447,16 +372,8 @@ namespace OpenIddict.EntityFramework
select authorization).AsAsyncEnumerable(cancellationToken);
}
/// <summary>
/// Retrieves the optional application identifier associated with an authorization.
/// </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="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
/// whose result returns the application identifier associated with the authorization.
/// </returns>
public virtual async ValueTask<string> GetApplicationIdAsync([NotNull] TAuthorization authorization, CancellationToken cancellationToken)
/// <inheritdoc/>
public virtual async ValueTask<string?> GetApplicationIdAsync(TAuthorization authorization, CancellationToken cancellationToken)
{
if (authorization == null)
{
@ -483,21 +400,10 @@ namespace OpenIddict.EntityFramework
return ConvertIdentifierToString(authorization.Application.Id);
}
/// <summary>
/// Executes the specified query and returns the first element.
/// </summary>
/// <typeparam name="TState">The state type.</typeparam>
/// <typeparam name="TResult">The result type.</typeparam>
/// <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="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the first element returned when executing the query.
/// </returns>
/// <inheritdoc/>
public virtual async ValueTask<TResult> GetAsync<TState, TResult>(
[NotNull] Func<IQueryable<TAuthorization>, TState, IQueryable<TResult>> query,
[CanBeNull] TState state, CancellationToken cancellationToken)
Func<IQueryable<TAuthorization>, TState, IQueryable<TResult>> query,
TState state, CancellationToken cancellationToken)
{
if (query == null)
{
@ -508,35 +414,19 @@ namespace OpenIddict.EntityFramework
Authorizations.Include(authorization => authorization.Application), state).FirstOrDefaultAsync(cancellationToken);
}
/// <summary>
/// Retrieves the unique identifier associated with an authorization.
/// </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="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
/// whose result returns the unique identifier associated with the authorization.
/// </returns>
public virtual ValueTask<string> GetIdAsync([NotNull] TAuthorization authorization, CancellationToken cancellationToken)
/// <inheritdoc/>
public virtual ValueTask<string?> GetIdAsync(TAuthorization authorization, CancellationToken cancellationToken)
{
if (authorization == null)
{
throw new ArgumentNullException(nameof(authorization));
}
return new ValueTask<string>(ConvertIdentifierToString(authorization.Id));
return new ValueTask<string?>(ConvertIdentifierToString(authorization.Id));
}
/// <summary>
/// Retrieves the additional properties associated with an authorization.
/// </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="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the additional properties associated with the authorization.
/// </returns>
public virtual ValueTask<ImmutableDictionary<string, JsonElement>> GetPropertiesAsync([NotNull] TAuthorization authorization, CancellationToken cancellationToken)
/// <inheritdoc/>
public virtual ValueTask<ImmutableDictionary<string, JsonElement>> GetPropertiesAsync(TAuthorization authorization, CancellationToken cancellationToken)
{
if (authorization == null)
{
@ -562,16 +452,8 @@ namespace OpenIddict.EntityFramework
return new ValueTask<ImmutableDictionary<string, JsonElement>>(properties);
}
/// <summary>
/// Retrieves the scopes associated with an authorization.
/// </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="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
/// whose result returns the scopes associated with the specified authorization.
/// </returns>
public virtual ValueTask<ImmutableArray<string>> GetScopesAsync([NotNull] TAuthorization authorization, CancellationToken cancellationToken)
/// <inheritdoc/>
public virtual ValueTask<ImmutableArray<string>> GetScopesAsync(TAuthorization authorization, CancellationToken cancellationToken)
{
if (authorization == null)
{
@ -597,71 +479,40 @@ namespace OpenIddict.EntityFramework
return new ValueTask<ImmutableArray<string>>(scopes);
}
/// <summary>
/// Retrieves the status associated with an authorization.
/// </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="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
/// whose result returns the status associated with the specified authorization.
/// </returns>
public virtual ValueTask<string> GetStatusAsync([NotNull] TAuthorization authorization, CancellationToken cancellationToken)
/// <inheritdoc/>
public virtual ValueTask<string?> GetStatusAsync(TAuthorization authorization, CancellationToken cancellationToken)
{
if (authorization == null)
{
throw new ArgumentNullException(nameof(authorization));
}
return new ValueTask<string>(authorization.Status);
return new ValueTask<string?>(authorization.Status);
}
/// <summary>
/// Retrieves the subject associated with an authorization.
/// </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="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
/// whose result returns the subject associated with the specified authorization.
/// </returns>
public virtual ValueTask<string> GetSubjectAsync([NotNull] TAuthorization authorization, CancellationToken cancellationToken)
/// <inheritdoc/>
public virtual ValueTask<string?> GetSubjectAsync(TAuthorization authorization, CancellationToken cancellationToken)
{
if (authorization == null)
{
throw new ArgumentNullException(nameof(authorization));
}
return new ValueTask<string>(authorization.Subject);
return new ValueTask<string?>(authorization.Subject);
}
/// <summary>
/// Retrieves the type associated with an authorization.
/// </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="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
/// whose result returns the type associated with the specified authorization.
/// </returns>
public virtual ValueTask<string> GetTypeAsync([NotNull] TAuthorization authorization, CancellationToken cancellationToken)
/// <inheritdoc/>
public virtual ValueTask<string?> GetTypeAsync(TAuthorization authorization, CancellationToken cancellationToken)
{
if (authorization == null)
{
throw new ArgumentNullException(nameof(authorization));
}
return new ValueTask<string>(authorization.Type);
return new ValueTask<string?>(authorization.Type);
}
/// <summary>
/// Instantiates a new authorization.
/// </summary>
/// <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 instantiated authorization, that can be persisted in the database.
/// </returns>
/// <inheritdoc/>
public virtual ValueTask<TAuthorization> InstantiateAsync(CancellationToken cancellationToken)
{
try
@ -676,18 +527,11 @@ namespace OpenIddict.EntityFramework
}
}
/// <summary>
/// Executes the specified query and returns all the corresponding elements.
/// </summary>
/// <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>All the elements returned when executing the specified query.</returns>
public virtual IAsyncEnumerable<TAuthorization> ListAsync(
[CanBeNull] int? count, [CanBeNull] int? offset, CancellationToken cancellationToken)
/// <inheritdoc/>
public virtual IAsyncEnumerable<TAuthorization> ListAsync(int? count, int? offset, CancellationToken cancellationToken)
{
var query = Authorizations.Include(authorization => authorization.Application)
.OrderBy(authorization => authorization.Id)
.OrderBy(authorization => authorization.Id!)
.AsQueryable();
if (offset.HasValue)
@ -703,18 +547,10 @@ namespace OpenIddict.EntityFramework
return query.AsAsyncEnumerable(cancellationToken);
}
/// <summary>
/// Executes the specified query and returns all the corresponding elements.
/// </summary>
/// <typeparam name="TState">The state type.</typeparam>
/// <typeparam name="TResult">The result type.</typeparam>
/// <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>All the elements returned when executing the specified query.</returns>
/// <inheritdoc/>
public virtual IAsyncEnumerable<TResult> ListAsync<TState, TResult>(
[NotNull] Func<IQueryable<TAuthorization>, TState, IQueryable<TResult>> query,
[CanBeNull] TState state, CancellationToken cancellationToken)
Func<IQueryable<TAuthorization>, TState, IQueryable<TResult>> query,
TState state, CancellationToken cancellationToken)
{
if (query == null)
{
@ -724,20 +560,16 @@ namespace OpenIddict.EntityFramework
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="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
/// <inheritdoc/>
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.
// To work around this limitation, entities are manually listed and deleted using a batch logic.
List<Exception> exceptions = null;
List<Exception>? exceptions = null;
DbContextTransaction CreateTransaction()
DbContextTransaction? CreateTransaction()
{
// Note: relational providers like Sqlite are known to lack proper support
// for repeatable read transactions. To ensure this method can be safely used
@ -807,17 +639,9 @@ namespace OpenIddict.EntityFramework
}
}
/// <summary>
/// Sets the application identifier associated with an authorization.
/// </summary>
/// <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="ValueTask"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual async ValueTask SetApplicationIdAsync([NotNull] TAuthorization authorization,
[CanBeNull] string identifier, CancellationToken cancellationToken)
/// <inheritdoc/>
public virtual async ValueTask SetApplicationIdAsync(TAuthorization authorization,
string? identifier, CancellationToken cancellationToken)
{
if (authorization == null)
{
@ -853,17 +677,9 @@ namespace OpenIddict.EntityFramework
}
}
/// <summary>
/// Sets the additional properties associated with an authorization.
/// </summary>
/// <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="ValueTask"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual ValueTask SetPropertiesAsync([NotNull] TAuthorization authorization,
[CanBeNull] ImmutableDictionary<string, JsonElement> properties, CancellationToken cancellationToken)
/// <inheritdoc/>
public virtual ValueTask SetPropertiesAsync(TAuthorization authorization,
ImmutableDictionary<string, JsonElement> properties, CancellationToken cancellationToken)
{
if (authorization == null)
{
@ -886,16 +702,8 @@ namespace OpenIddict.EntityFramework
return default;
}
/// <summary>
/// Sets the scopes associated with an authorization.
/// </summary>
/// <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="ValueTask"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual ValueTask SetScopesAsync([NotNull] TAuthorization authorization,
/// <inheritdoc/>
public virtual ValueTask SetScopesAsync(TAuthorization authorization,
ImmutableArray<string> scopes, CancellationToken cancellationToken)
{
if (authorization == null)
@ -919,17 +727,8 @@ namespace OpenIddict.EntityFramework
return default;
}
/// <summary>
/// Sets the status associated with an authorization.
/// </summary>
/// <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="ValueTask"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual ValueTask SetStatusAsync([NotNull] TAuthorization authorization,
[CanBeNull] string status, CancellationToken cancellationToken)
/// <inheritdoc/>
public virtual ValueTask SetStatusAsync(TAuthorization authorization, string? status, CancellationToken cancellationToken)
{
if (authorization == null)
{
@ -941,17 +740,8 @@ namespace OpenIddict.EntityFramework
return default;
}
/// <summary>
/// Sets the subject associated with an authorization.
/// </summary>
/// <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="ValueTask"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual ValueTask SetSubjectAsync([NotNull] TAuthorization authorization,
[CanBeNull] string subject, CancellationToken cancellationToken)
/// <inheritdoc/>
public virtual ValueTask SetSubjectAsync(TAuthorization authorization, string? subject, CancellationToken cancellationToken)
{
if (authorization == null)
{
@ -963,17 +753,8 @@ namespace OpenIddict.EntityFramework
return default;
}
/// <summary>
/// Sets the type associated with an authorization.
/// </summary>
/// <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="ValueTask"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual ValueTask SetTypeAsync([NotNull] TAuthorization authorization,
[CanBeNull] string type, CancellationToken cancellationToken)
/// <inheritdoc/>
public virtual ValueTask SetTypeAsync(TAuthorization authorization, string? type, CancellationToken cancellationToken)
{
if (authorization == null)
{
@ -985,15 +766,8 @@ namespace OpenIddict.EntityFramework
return default;
}
/// <summary>
/// Updates an existing authorization.
/// </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="ValueTask"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual async ValueTask UpdateAsync([NotNull] TAuthorization authorization, CancellationToken cancellationToken)
/// <inheritdoc/>
public virtual async ValueTask UpdateAsync(TAuthorization authorization, CancellationToken cancellationToken)
{
if (authorization == null)
{
@ -1027,7 +801,8 @@ namespace OpenIddict.EntityFramework
/// </summary>
/// <param name="identifier">The identifier to convert.</param>
/// <returns>An instance of <typeparamref name="TKey"/> representing the provided identifier.</returns>
public virtual TKey ConvertIdentifierFromString([CanBeNull] string identifier)
[return: MaybeNull]
public virtual TKey ConvertIdentifierFromString(string? identifier)
{
if (string.IsNullOrEmpty(identifier))
{
@ -1042,7 +817,7 @@ namespace OpenIddict.EntityFramework
/// </summary>
/// <param name="identifier">The identifier to convert.</param>
/// <returns>A <see cref="string"/> representation of the provided identifier.</returns>
public virtual string ConvertIdentifierToString([CanBeNull] TKey identifier)
public virtual string? ConvertIdentifierToString([AllowNull] TKey identifier)
{
if (Equals(identifier, default(TKey)))
{

345
src/OpenIddict.EntityFramework/Stores/OpenIddictEntityFrameworkScopeStore.cs

@ -10,6 +10,7 @@ using System.Collections.Immutable;
using System.ComponentModel;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.IO;
using System.Linq;
@ -19,7 +20,6 @@ using System.Text.Encodings.Web;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using JetBrains.Annotations;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Options;
using OpenIddict.Abstractions;
@ -37,9 +37,9 @@ namespace OpenIddict.EntityFramework
where TContext : DbContext
{
public OpenIddictEntityFrameworkScopeStore(
[NotNull] IMemoryCache cache,
[NotNull] TContext context,
[NotNull] IOptionsMonitor<OpenIddictEntityFrameworkOptions> options)
IMemoryCache cache,
TContext context,
IOptionsMonitor<OpenIddictEntityFrameworkOptions> options)
: base(cache, context, options)
{
}
@ -57,9 +57,9 @@ namespace OpenIddict.EntityFramework
where TKey : IEquatable<TKey>
{
public OpenIddictEntityFrameworkScopeStore(
[NotNull] IMemoryCache cache,
[NotNull] TContext context,
[NotNull] IOptionsMonitor<OpenIddictEntityFrameworkOptions> options)
IMemoryCache cache,
TContext context,
IOptionsMonitor<OpenIddictEntityFrameworkOptions> options)
{
Cache = cache;
Context = context;
@ -86,28 +86,12 @@ namespace OpenIddict.EntityFramework
/// </summary>
private DbSet<TScope> Scopes => Context.Set<TScope>();
/// <summary>
/// Determines the number of scopes that exist in the database.
/// </summary>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the number of scopes in the database.
/// </returns>
/// <inheritdoc/>
public virtual async ValueTask<long> CountAsync(CancellationToken cancellationToken)
=> await Scopes.LongCountAsync(cancellationToken);
/// <summary>
/// Determines the number of scopes that match the specified query.
/// </summary>
/// <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="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 ValueTask<long> CountAsync<TResult>([NotNull] Func<IQueryable<TScope>, IQueryable<TResult>> query, CancellationToken cancellationToken)
/// <inheritdoc/>
public virtual async ValueTask<long> CountAsync<TResult>(Func<IQueryable<TScope>, IQueryable<TResult>> query, CancellationToken cancellationToken)
{
if (query == null)
{
@ -117,13 +101,8 @@ namespace OpenIddict.EntityFramework
return await query(Scopes).LongCountAsync(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="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual async ValueTask CreateAsync([NotNull] TScope scope, CancellationToken cancellationToken)
/// <inheritdoc/>
public virtual async ValueTask CreateAsync(TScope scope, CancellationToken cancellationToken)
{
if (scope == null)
{
@ -135,13 +114,8 @@ namespace OpenIddict.EntityFramework
await Context.SaveChangesAsync(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="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual async ValueTask DeleteAsync([NotNull] TScope scope, CancellationToken cancellationToken)
/// <inheritdoc/>
public virtual async ValueTask DeleteAsync(TScope scope, CancellationToken cancellationToken)
{
if (scope == null)
{
@ -164,16 +138,8 @@ namespace OpenIddict.EntityFramework
}
}
/// <summary>
/// Retrieves a scope using its unique identifier.
/// </summary>
/// <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="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the scope corresponding to the identifier.
/// </returns>
public virtual async ValueTask<TScope> FindByIdAsync([NotNull] string identifier, CancellationToken cancellationToken)
/// <inheritdoc/>
public virtual async ValueTask<TScope?> FindByIdAsync(string identifier, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(identifier))
{
@ -183,20 +149,12 @@ namespace OpenIddict.EntityFramework
var key = ConvertIdentifierFromString(identifier);
return await (from scope in Scopes
where scope.Id.Equals(key)
where scope.Id!.Equals(key)
select scope).FirstOrDefaultAsync(cancellationToken);
}
/// <summary>
/// Retrieves a scope using its name.
/// </summary>
/// <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="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the scope corresponding to the specified name.
/// </returns>
public virtual async ValueTask<TScope> FindByNameAsync([NotNull] string name, CancellationToken cancellationToken)
/// <inheritdoc/>
public virtual async ValueTask<TScope?> FindByNameAsync(string name, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(name))
{
@ -208,12 +166,7 @@ namespace OpenIddict.EntityFramework
select scope).FirstOrDefaultAsync(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>The scopes corresponding to the specified names.</returns>
/// <inheritdoc/>
public virtual IAsyncEnumerable<TScope> FindByNamesAsync(
ImmutableArray<string> names, CancellationToken cancellationToken)
{
@ -229,14 +182,9 @@ namespace OpenIddict.EntityFramework
select scope).AsAsyncEnumerable(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>The scopes associated with the specified resource.</returns>
/// <inheritdoc/>
public virtual IAsyncEnumerable<TScope> FindByResourceAsync(
[NotNull] string resource, CancellationToken cancellationToken)
string resource, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(resource))
{
@ -254,7 +202,7 @@ namespace OpenIddict.EntityFramework
async IAsyncEnumerable<TScope> ExecuteAsync([EnumeratorCancellation] CancellationToken cancellationToken)
{
var scopes = (from scope in Scopes
where scope.Resources.Contains(resource)
where scope.Resources!.Contains(resource)
select scope).AsAsyncEnumerable(cancellationToken);
await foreach (var scope in scopes)
@ -268,21 +216,10 @@ namespace OpenIddict.EntityFramework
}
}
/// <summary>
/// Executes the specified query and returns the first element.
/// </summary>
/// <typeparam name="TState">The state type.</typeparam>
/// <typeparam name="TResult">The result type.</typeparam>
/// <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="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the first element returned when executing the query.
/// </returns>
/// <inheritdoc/>
public virtual async ValueTask<TResult> GetAsync<TState, TResult>(
[NotNull] Func<IQueryable<TScope>, TState, IQueryable<TResult>> query,
[CanBeNull] TState state, CancellationToken cancellationToken)
Func<IQueryable<TScope>, TState, IQueryable<TResult>> query,
TState state, CancellationToken cancellationToken)
{
if (query == null)
{
@ -292,35 +229,19 @@ namespace OpenIddict.EntityFramework
return await query(Scopes, state).FirstOrDefaultAsync(cancellationToken);
}
/// <summary>
/// Retrieves the description associated with a scope.
/// </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="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
/// whose result returns the description associated with the specified scope.
/// </returns>
public virtual ValueTask<string> GetDescriptionAsync([NotNull] TScope scope, CancellationToken cancellationToken)
/// <inheritdoc/>
public virtual ValueTask<string?> GetDescriptionAsync(TScope scope, CancellationToken cancellationToken)
{
if (scope == null)
{
throw new ArgumentNullException(nameof(scope));
}
return new ValueTask<string>(scope.Description);
return new ValueTask<string?>(scope.Description);
}
/// <summary>
/// Retrieves the localized descriptions associated with a scope.
/// </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="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the localized descriptions associated with the specified scope.
/// </returns>
public virtual ValueTask<ImmutableDictionary<CultureInfo, string>> GetDescriptionsAsync([NotNull] TScope scope, CancellationToken cancellationToken)
/// <inheritdoc/>
public virtual ValueTask<ImmutableDictionary<CultureInfo, string>> GetDescriptionsAsync(TScope scope, CancellationToken cancellationToken)
{
if (scope == null)
{
@ -347,35 +268,19 @@ namespace OpenIddict.EntityFramework
return new ValueTask<ImmutableDictionary<CultureInfo, string>>(descriptions);
}
/// <summary>
/// Retrieves the display name associated with a scope.
/// </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="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
/// whose result returns the display name associated with the scope.
/// </returns>
public virtual ValueTask<string> GetDisplayNameAsync([NotNull] TScope scope, CancellationToken cancellationToken)
/// <inheritdoc/>
public virtual ValueTask<string?> GetDisplayNameAsync(TScope scope, CancellationToken cancellationToken)
{
if (scope == null)
{
throw new ArgumentNullException(nameof(scope));
}
return new ValueTask<string>(scope.DisplayName);
return new ValueTask<string?>(scope.DisplayName);
}
/// <summary>
/// Retrieves the localized display names associated with a scope.
/// </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="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the localized display names associated with the scope.
/// </returns>
public virtual ValueTask<ImmutableDictionary<CultureInfo, string>> GetDisplayNamesAsync([NotNull] TScope scope, CancellationToken cancellationToken)
/// <inheritdoc/>
public virtual ValueTask<ImmutableDictionary<CultureInfo, string>> GetDisplayNamesAsync(TScope scope, CancellationToken cancellationToken)
{
if (scope == null)
{
@ -402,54 +307,30 @@ namespace OpenIddict.EntityFramework
return new ValueTask<ImmutableDictionary<CultureInfo, string>>(names);
}
/// <summary>
/// Retrieves the unique identifier associated with a scope.
/// </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="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
/// whose result returns the unique identifier associated with the scope.
/// </returns>
public virtual ValueTask<string> GetIdAsync([NotNull] TScope scope, CancellationToken cancellationToken)
/// <inheritdoc/>
public virtual ValueTask<string?> GetIdAsync(TScope scope, CancellationToken cancellationToken)
{
if (scope == null)
{
throw new ArgumentNullException(nameof(scope));
}
return new ValueTask<string>(ConvertIdentifierToString(scope.Id));
return new ValueTask<string?>(ConvertIdentifierToString(scope.Id));
}
/// <summary>
/// Retrieves the name associated with a scope.
/// </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="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
/// whose result returns the name associated with the specified scope.
/// </returns>
public virtual ValueTask<string> GetNameAsync([NotNull] TScope scope, CancellationToken cancellationToken)
/// <inheritdoc/>
public virtual ValueTask<string?> GetNameAsync(TScope scope, CancellationToken cancellationToken)
{
if (scope == null)
{
throw new ArgumentNullException(nameof(scope));
}
return new ValueTask<string>(scope.Name);
return new ValueTask<string?>(scope.Name);
}
/// <summary>
/// Retrieves the additional properties associated with a scope.
/// </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="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the additional properties associated with the scope.
/// </returns>
public virtual ValueTask<ImmutableDictionary<string, JsonElement>> GetPropertiesAsync([NotNull] TScope scope, CancellationToken cancellationToken)
/// <inheritdoc/>
public virtual ValueTask<ImmutableDictionary<string, JsonElement>> GetPropertiesAsync(TScope scope, CancellationToken cancellationToken)
{
if (scope == null)
{
@ -475,16 +356,8 @@ namespace OpenIddict.EntityFramework
return new ValueTask<ImmutableDictionary<string, JsonElement>>(properties);
}
/// <summary>
/// Retrieves the resources associated with a scope.
/// </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="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the resources associated with the scope.
/// </returns>
public virtual ValueTask<ImmutableArray<string>> GetResourcesAsync([NotNull] TScope scope, CancellationToken cancellationToken)
/// <inheritdoc/>
public virtual ValueTask<ImmutableArray<string>> GetResourcesAsync(TScope scope, CancellationToken cancellationToken)
{
if (scope == null)
{
@ -510,14 +383,7 @@ namespace OpenIddict.EntityFramework
return new ValueTask<ImmutableArray<string>>(resources);
}
/// <summary>
/// Instantiates a new scope.
/// </summary>
/// <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 instantiated scope, that can be persisted in the database.
/// </returns>
/// <inheritdoc/>
public virtual ValueTask<TScope> InstantiateAsync(CancellationToken cancellationToken)
{
try
@ -532,17 +398,10 @@ namespace OpenIddict.EntityFramework
}
}
/// <summary>
/// Executes the specified query and returns all the corresponding elements.
/// </summary>
/// <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>All the elements returned when executing the specified query.</returns>
public virtual IAsyncEnumerable<TScope> ListAsync(
[CanBeNull] int? count, [CanBeNull] int? offset, CancellationToken cancellationToken)
/// <inheritdoc/>
public virtual IAsyncEnumerable<TScope> ListAsync(int? count, int? offset, CancellationToken cancellationToken)
{
var query = Scopes.OrderBy(scope => scope.Id).AsQueryable();
var query = Scopes.OrderBy(scope => scope.Id!).AsQueryable();
if (offset.HasValue)
{
@ -557,18 +416,10 @@ namespace OpenIddict.EntityFramework
return query.AsAsyncEnumerable(cancellationToken);
}
/// <summary>
/// Executes the specified query and returns all the corresponding elements.
/// </summary>
/// <typeparam name="TState">The state type.</typeparam>
/// <typeparam name="TResult">The result type.</typeparam>
/// <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>All the elements returned when executing the specified query.</returns>
/// <inheritdoc/>
public virtual IAsyncEnumerable<TResult> ListAsync<TState, TResult>(
[NotNull] Func<IQueryable<TScope>, TState, IQueryable<TResult>> query,
[CanBeNull] TState state, CancellationToken cancellationToken)
Func<IQueryable<TScope>, TState, IQueryable<TResult>> query,
TState state, CancellationToken cancellationToken)
{
if (query == null)
{
@ -578,14 +429,8 @@ namespace OpenIddict.EntityFramework
return query(Scopes, state).AsAsyncEnumerable(cancellationToken);
}
/// <summary>
/// Sets the description associated with a scope.
/// </summary>
/// <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="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetDescriptionAsync([NotNull] TScope scope, [CanBeNull] string description, CancellationToken cancellationToken)
/// <inheritdoc/>
public virtual ValueTask SetDescriptionAsync(TScope scope, string? description, CancellationToken cancellationToken)
{
if (scope == null)
{
@ -597,15 +442,9 @@ namespace OpenIddict.EntityFramework
return default;
}
/// <summary>
/// Sets the localized descriptions associated with a scope.
/// </summary>
/// <param name="scope">The scope.</param>
/// <param name="descriptions">The localized descriptions 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"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetDescriptionsAsync([NotNull] TScope scope,
[CanBeNull] ImmutableDictionary<CultureInfo, string> descriptions, CancellationToken cancellationToken)
/// <inheritdoc/>
public virtual ValueTask SetDescriptionsAsync(TScope scope,
ImmutableDictionary<CultureInfo, string> descriptions, CancellationToken cancellationToken)
{
if (scope == null)
{
@ -642,14 +481,8 @@ namespace OpenIddict.EntityFramework
return default;
}
/// <summary>
/// Sets the display name associated with a scope.
/// </summary>
/// <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="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetDisplayNameAsync([NotNull] TScope scope, [CanBeNull] string name, CancellationToken cancellationToken)
/// <inheritdoc/>
public virtual ValueTask SetDisplayNameAsync(TScope scope, string? name, CancellationToken cancellationToken)
{
if (scope == null)
{
@ -661,15 +494,9 @@ namespace OpenIddict.EntityFramework
return default;
}
/// <summary>
/// Sets the localized display names associated with a scope.
/// </summary>
/// <param name="scope">The scope.</param>
/// <param name="names">The localized display names 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="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetDisplayNamesAsync([NotNull] TScope scope,
[CanBeNull] ImmutableDictionary<CultureInfo, string> names, CancellationToken cancellationToken)
/// <inheritdoc/>
public virtual ValueTask SetDisplayNamesAsync(TScope scope,
ImmutableDictionary<CultureInfo, string> names, CancellationToken cancellationToken)
{
if (scope == null)
{
@ -706,14 +533,8 @@ namespace OpenIddict.EntityFramework
return default;
}
/// <summary>
/// Sets the name associated with a scope.
/// </summary>
/// <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="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetNameAsync([NotNull] TScope scope, [CanBeNull] string name, CancellationToken cancellationToken)
/// <inheritdoc/>
public virtual ValueTask SetNameAsync(TScope scope, string? name, CancellationToken cancellationToken)
{
if (scope == null)
{
@ -725,15 +546,9 @@ namespace OpenIddict.EntityFramework
return default;
}
/// <summary>
/// Sets the additional properties associated with a scope.
/// </summary>
/// <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="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetPropertiesAsync([NotNull] TScope scope,
[CanBeNull] ImmutableDictionary<string, JsonElement> properties, CancellationToken cancellationToken)
/// <inheritdoc/>
public virtual ValueTask SetPropertiesAsync(TScope scope,
ImmutableDictionary<string, JsonElement> properties, CancellationToken cancellationToken)
{
if (scope == null)
{
@ -756,14 +571,8 @@ namespace OpenIddict.EntityFramework
return default;
}
/// <summary>
/// Sets the resources associated with a scope.
/// </summary>
/// <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="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetResourcesAsync([NotNull] TScope scope, ImmutableArray<string> resources, CancellationToken cancellationToken)
/// <inheritdoc/>
public virtual ValueTask SetResourcesAsync(TScope scope, ImmutableArray<string> resources, CancellationToken cancellationToken)
{
if (scope == null)
{
@ -786,13 +595,8 @@ namespace OpenIddict.EntityFramework
return default;
}
/// <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="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual async ValueTask UpdateAsync([NotNull] TScope scope, CancellationToken cancellationToken)
/// <inheritdoc/>
public virtual async ValueTask UpdateAsync(TScope scope, CancellationToken cancellationToken)
{
if (scope == null)
{
@ -826,7 +630,8 @@ namespace OpenIddict.EntityFramework
/// </summary>
/// <param name="identifier">The identifier to convert.</param>
/// <returns>An instance of <typeparamref name="TKey"/> representing the provided identifier.</returns>
public virtual TKey ConvertIdentifierFromString([CanBeNull] string identifier)
[return: MaybeNull]
public virtual TKey ConvertIdentifierFromString(string? identifier)
{
if (string.IsNullOrEmpty(identifier))
{
@ -841,7 +646,7 @@ namespace OpenIddict.EntityFramework
/// </summary>
/// <param name="identifier">The identifier to convert.</param>
/// <returns>A <see cref="string"/> representation of the provided identifier.</returns>
public virtual string ConvertIdentifierToString([CanBeNull] TKey identifier)
public virtual string? ConvertIdentifierToString([AllowNull] TKey identifier)
{
if (Equals(identifier, default(TKey)))
{

489
src/OpenIddict.EntityFramework/Stores/OpenIddictEntityFrameworkTokenStore.cs

@ -11,12 +11,12 @@ using System.ComponentModel;
using System.Data;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Text.Encodings.Web;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using JetBrains.Annotations;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Options;
using OpenIddict.Abstractions;
@ -36,9 +36,9 @@ namespace OpenIddict.EntityFramework
where TContext : DbContext
{
public OpenIddictEntityFrameworkTokenStore(
[NotNull] IMemoryCache cache,
[NotNull] TContext context,
[NotNull] IOptionsMonitor<OpenIddictEntityFrameworkOptions> options)
IMemoryCache cache,
TContext context,
IOptionsMonitor<OpenIddictEntityFrameworkOptions> options)
: base(cache, context, options)
{
}
@ -60,9 +60,9 @@ namespace OpenIddict.EntityFramework
where TKey : IEquatable<TKey>
{
public OpenIddictEntityFrameworkTokenStore(
[NotNull] IMemoryCache cache,
[NotNull] TContext context,
[NotNull] IOptionsMonitor<OpenIddictEntityFrameworkOptions> options)
IMemoryCache cache,
TContext context,
IOptionsMonitor<OpenIddictEntityFrameworkOptions> options)
{
Cache = cache;
Context = context;
@ -99,28 +99,12 @@ namespace OpenIddict.EntityFramework
/// </summary>
private DbSet<TToken> Tokens => Context.Set<TToken>();
/// <summary>
/// Determines the number of tokens that exist in the database.
/// </summary>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the number of applications in the database.
/// </returns>
/// <inheritdoc/>
public virtual async ValueTask<long> CountAsync(CancellationToken cancellationToken)
=> await Tokens.LongCountAsync(cancellationToken);
/// <summary>
/// Determines the number of tokens that match the specified query.
/// </summary>
/// <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="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 ValueTask<long> CountAsync<TResult>([NotNull] Func<IQueryable<TToken>, IQueryable<TResult>> query, CancellationToken cancellationToken)
/// <inheritdoc/>
public virtual async ValueTask<long> CountAsync<TResult>(Func<IQueryable<TToken>, IQueryable<TResult>> query, CancellationToken cancellationToken)
{
if (query == null)
{
@ -130,13 +114,8 @@ namespace OpenIddict.EntityFramework
return await query(Tokens).LongCountAsync(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="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual async ValueTask CreateAsync([NotNull] TToken token, CancellationToken cancellationToken)
/// <inheritdoc/>
public virtual async ValueTask CreateAsync(TToken token, CancellationToken cancellationToken)
{
if (token == null)
{
@ -148,13 +127,8 @@ namespace OpenIddict.EntityFramework
await Context.SaveChangesAsync(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="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual async ValueTask DeleteAsync([NotNull] TToken token, CancellationToken cancellationToken)
/// <inheritdoc/>
public virtual async ValueTask DeleteAsync(TToken token, CancellationToken cancellationToken)
{
if (token == null)
{
@ -177,16 +151,9 @@ namespace OpenIddict.EntityFramework
}
}
/// <summary>
/// Retrieves the tokens corresponding to the specified
/// subject and associated with the application identifier.
/// </summary>
/// <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>The tokens corresponding to the subject/client.</returns>
public virtual IAsyncEnumerable<TToken> FindAsync([NotNull] string subject,
[NotNull] string client, CancellationToken cancellationToken)
/// <inheritdoc/>
public virtual IAsyncEnumerable<TToken> FindAsync(string subject,
string client, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(subject))
{
@ -202,22 +169,15 @@ namespace OpenIddict.EntityFramework
return (from token in Tokens.Include(token => token.Application).Include(token => token.Authorization)
where token.Application != null &&
token.Application.Id.Equals(key) &&
token.Application.Id!.Equals(key) &&
token.Subject == subject
select token).AsAsyncEnumerable(cancellationToken);
}
/// <summary>
/// Retrieves the tokens matching the specified parameters.
/// </summary>
/// <param name="subject">The subject associated with the token.</param>
/// <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>The tokens corresponding to the criteria.</returns>
/// <inheritdoc/>
public virtual IAsyncEnumerable<TToken> FindAsync(
[NotNull] string subject, [NotNull] string client,
[NotNull] string status, CancellationToken cancellationToken)
string subject, string client,
string status, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(subject))
{
@ -238,24 +198,16 @@ namespace OpenIddict.EntityFramework
return (from token in Tokens.Include(token => token.Application).Include(token => token.Authorization)
where token.Application != null &&
token.Application.Id.Equals(key) &&
token.Application.Id!.Equals(key) &&
token.Subject == subject &&
token.Status == status
select token).AsAsyncEnumerable(cancellationToken);
}
/// <summary>
/// Retrieves the tokens matching the specified parameters.
/// </summary>
/// <param name="subject">The subject associated with the token.</param>
/// <param name="client">The client associated with the token.</param>
/// <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>The tokens corresponding to the criteria.</returns>
/// <inheritdoc/>
public virtual IAsyncEnumerable<TToken> FindAsync(
[NotNull] string subject, [NotNull] string client,
[NotNull] string status, [NotNull] string type, CancellationToken cancellationToken)
string subject, string client,
string status, string type, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(subject))
{
@ -281,20 +233,15 @@ namespace OpenIddict.EntityFramework
return (from token in Tokens.Include(token => token.Application).Include(token => token.Authorization)
where token.Application != null &&
token.Application.Id.Equals(key) &&
token.Application.Id!.Equals(key) &&
token.Subject == subject &&
token.Status == status &&
token.Type == type
select token).AsAsyncEnumerable(cancellationToken);
}
/// <summary>
/// Retrieves the list of tokens corresponding to the specified application identifier.
/// </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>The tokens corresponding to the specified application.</returns>
public virtual IAsyncEnumerable<TToken> FindByApplicationIdAsync([NotNull] string identifier, CancellationToken cancellationToken)
/// <inheritdoc/>
public virtual IAsyncEnumerable<TToken> FindByApplicationIdAsync(string identifier, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(identifier))
{
@ -305,17 +252,12 @@ namespace OpenIddict.EntityFramework
return (from token in Tokens.Include(token => token.Application).Include(token => token.Authorization)
where token.Application != null &&
token.Application.Id.Equals(key)
token.Application.Id!.Equals(key)
select token).AsAsyncEnumerable(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>Tokens corresponding to the specified authorization.</returns>
public virtual IAsyncEnumerable<TToken> FindByAuthorizationIdAsync([NotNull] string identifier, CancellationToken cancellationToken)
/// <inheritdoc/>
public virtual IAsyncEnumerable<TToken> FindByAuthorizationIdAsync(string identifier, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(identifier))
{
@ -326,20 +268,12 @@ namespace OpenIddict.EntityFramework
return (from token in Tokens.Include(token => token.Application).Include(token => token.Authorization)
where token.Authorization != null &&
token.Authorization.Id.Equals(key)
token.Authorization.Id!.Equals(key)
select token).AsAsyncEnumerable(cancellationToken);
}
/// <summary>
/// Retrieves a token using its unique identifier.
/// </summary>
/// <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="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the token corresponding to the unique identifier.
/// </returns>
public virtual async ValueTask<TToken> FindByIdAsync([NotNull] string identifier, CancellationToken cancellationToken)
/// <inheritdoc/>
public virtual async ValueTask<TToken?> FindByIdAsync(string identifier, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(identifier))
{
@ -349,21 +283,12 @@ namespace OpenIddict.EntityFramework
var key = ConvertIdentifierFromString(identifier);
return await (from token in Tokens.Include(token => token.Application).Include(token => token.Authorization)
where token.Id.Equals(key)
where token.Id!.Equals(key)
select token).FirstOrDefaultAsync(cancellationToken);
}
/// <summary>
/// Retrieves the list of tokens corresponding to the specified reference identifier.
/// Note: the reference identifier may be hashed or encrypted for security reasons.
/// </summary>
/// <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="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 ValueTask<TToken> FindByReferenceIdAsync([NotNull] string identifier, CancellationToken cancellationToken)
/// <inheritdoc/>
public virtual async ValueTask<TToken?> FindByReferenceIdAsync(string identifier, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(identifier))
{
@ -375,13 +300,8 @@ namespace OpenIddict.EntityFramework
select token).FirstOrDefaultAsync(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>The tokens corresponding to the specified subject.</returns>
public virtual IAsyncEnumerable<TToken> FindBySubjectAsync([NotNull] string subject, CancellationToken cancellationToken)
/// <inheritdoc/>
public virtual IAsyncEnumerable<TToken> FindBySubjectAsync(string subject, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(subject))
{
@ -393,16 +313,8 @@ namespace OpenIddict.EntityFramework
select token).AsAsyncEnumerable(cancellationToken);
}
/// <summary>
/// Retrieves the optional application identifier associated with a token.
/// </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="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
/// whose result returns the application identifier associated with the token.
/// </returns>
public virtual async ValueTask<string> GetApplicationIdAsync([NotNull] TToken token, CancellationToken cancellationToken)
/// <inheritdoc/>
public virtual async ValueTask<string?> GetApplicationIdAsync(TToken token, CancellationToken cancellationToken)
{
if (token == null)
{
@ -429,21 +341,10 @@ namespace OpenIddict.EntityFramework
return ConvertIdentifierToString(token.Application.Id);
}
/// <summary>
/// Executes the specified query and returns the first element.
/// </summary>
/// <typeparam name="TState">The state type.</typeparam>
/// <typeparam name="TResult">The result type.</typeparam>
/// <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="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns the first element returned when executing the query.
/// </returns>
/// <inheritdoc/>
public virtual async ValueTask<TResult> GetAsync<TState, TResult>(
[NotNull] Func<IQueryable<TToken>, TState, IQueryable<TResult>> query,
[CanBeNull] TState state, CancellationToken cancellationToken)
Func<IQueryable<TToken>, TState, IQueryable<TResult>> query,
TState state, CancellationToken cancellationToken)
{
if (query == null)
{
@ -455,16 +356,8 @@ namespace OpenIddict.EntityFramework
.Include(token => token.Authorization), state).FirstOrDefaultAsync(cancellationToken);
}
/// <summary>
/// Retrieves the optional authorization identifier associated with a token.
/// </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="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
/// whose result returns the authorization identifier associated with the token.
/// </returns>
public virtual async ValueTask<string> GetAuthorizationIdAsync([NotNull] TToken token, CancellationToken cancellationToken)
/// <inheritdoc/>
public virtual async ValueTask<string?> GetAuthorizationIdAsync(TToken token, CancellationToken cancellationToken)
{
if (token == null)
{
@ -491,16 +384,8 @@ namespace OpenIddict.EntityFramework
return ConvertIdentifierToString(token.Authorization.Id);
}
/// <summary>
/// Retrieves the creation date associated with a token.
/// </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="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
/// whose result returns the creation date associated with the specified token.
/// </returns>
public virtual ValueTask<DateTimeOffset?> GetCreationDateAsync([NotNull] TToken token, CancellationToken cancellationToken)
/// <inheritdoc/>
public virtual ValueTask<DateTimeOffset?> GetCreationDateAsync(TToken token, CancellationToken cancellationToken)
{
if (token == null)
{
@ -510,16 +395,8 @@ namespace OpenIddict.EntityFramework
return new ValueTask<DateTimeOffset?>(token.CreationDate);
}
/// <summary>
/// Retrieves the expiration date associated with a token.
/// </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="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
/// whose result returns the expiration date associated with the specified token.
/// </returns>
public virtual ValueTask<DateTimeOffset?> GetExpirationDateAsync([NotNull] TToken token, CancellationToken cancellationToken)
/// <inheritdoc/>
public virtual ValueTask<DateTimeOffset?> GetExpirationDateAsync(TToken token, CancellationToken cancellationToken)
{
if (token == null)
{
@ -529,54 +406,30 @@ namespace OpenIddict.EntityFramework
return new ValueTask<DateTimeOffset?>(token.ExpirationDate);
}
/// <summary>
/// Retrieves the unique identifier associated with a token.
/// </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="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
/// whose result returns the unique identifier associated with the token.
/// </returns>
public virtual ValueTask<string> GetIdAsync([NotNull] TToken token, CancellationToken cancellationToken)
/// <inheritdoc/>
public virtual ValueTask<string?> GetIdAsync(TToken token, CancellationToken cancellationToken)
{
if (token == null)
{
throw new ArgumentNullException(nameof(token));
}
return new ValueTask<string>(ConvertIdentifierToString(token.Id));
return new ValueTask<string?>(ConvertIdentifierToString(token.Id));
}
/// <summary>
/// Retrieves the payload associated with a token.
/// </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="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
/// whose result returns the payload associated with the specified token.
/// </returns>
public virtual ValueTask<string> GetPayloadAsync([NotNull] TToken token, CancellationToken cancellationToken)
/// <inheritdoc/>
public virtual ValueTask<string?> GetPayloadAsync(TToken token, CancellationToken cancellationToken)
{
if (token == null)
{
throw new ArgumentNullException(nameof(token));
}
return new ValueTask<string>(token.Payload);
return new ValueTask<string?>(token.Payload);
}
/// <summary>
/// Retrieves the additional properties associated with a token.
/// </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="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the additional properties associated with the token.
/// </returns>
public virtual ValueTask<ImmutableDictionary<string, JsonElement>> GetPropertiesAsync([NotNull] TToken token, CancellationToken cancellationToken)
/// <inheritdoc/>
public virtual ValueTask<ImmutableDictionary<string, JsonElement>> GetPropertiesAsync(TToken token, CancellationToken cancellationToken)
{
if (token == null)
{
@ -602,92 +455,51 @@ namespace OpenIddict.EntityFramework
return new ValueTask<ImmutableDictionary<string, JsonElement>>(properties);
}
/// <summary>
/// Retrieves the reference identifier associated with a token.
/// Note: depending on the manager used to create the token,
/// the reference identifier may be hashed for security reasons.
/// </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="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
/// whose result returns the reference identifier associated with the specified token.
/// </returns>
public virtual ValueTask<string> GetReferenceIdAsync([NotNull] TToken token, CancellationToken cancellationToken)
/// <inheritdoc/>
public virtual ValueTask<string?> GetReferenceIdAsync(TToken token, CancellationToken cancellationToken)
{
if (token == null)
{
throw new ArgumentNullException(nameof(token));
}
return new ValueTask<string>(token.ReferenceId);
return new ValueTask<string?>(token.ReferenceId);
}
/// <summary>
/// Retrieves the status associated with a token.
/// </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="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
/// whose result returns the status associated with the specified token.
/// </returns>
public virtual ValueTask<string> GetStatusAsync([NotNull] TToken token, CancellationToken cancellationToken)
/// <inheritdoc/>
public virtual ValueTask<string?> GetStatusAsync(TToken token, CancellationToken cancellationToken)
{
if (token == null)
{
throw new ArgumentNullException(nameof(token));
}
return new ValueTask<string>(token.Status);
return new ValueTask<string?>(token.Status);
}
/// <summary>
/// Retrieves the subject associated with a token.
/// </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="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
/// whose result returns the subject associated with the specified token.
/// </returns>
public virtual ValueTask<string> GetSubjectAsync([NotNull] TToken token, CancellationToken cancellationToken)
/// <inheritdoc/>
public virtual ValueTask<string?> GetSubjectAsync(TToken token, CancellationToken cancellationToken)
{
if (token == null)
{
throw new ArgumentNullException(nameof(token));
}
return new ValueTask<string>(token.Subject);
return new ValueTask<string?>(token.Subject);
}
/// <summary>
/// Retrieves the token type associated with a token.
/// </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="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
/// whose result returns the token type associated with the specified token.
/// </returns>
public virtual ValueTask<string> GetTypeAsync([NotNull] TToken token, CancellationToken cancellationToken)
/// <inheritdoc/>
public virtual ValueTask<string?> GetTypeAsync(TToken token, CancellationToken cancellationToken)
{
if (token == null)
{
throw new ArgumentNullException(nameof(token));
}
return new ValueTask<string>(token.Type);
return new ValueTask<string?>(token.Type);
}
/// <summary>
/// Instantiates a new token.
/// </summary>
/// <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 instantiated token, that can be persisted in the database.
/// </returns>
/// <inheritdoc/>
public virtual ValueTask<TToken> InstantiateAsync(CancellationToken cancellationToken)
{
try
@ -702,19 +514,12 @@ namespace OpenIddict.EntityFramework
}
}
/// <summary>
/// Executes the specified query and returns all the corresponding elements.
/// </summary>
/// <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>All the elements returned when executing the specified query.</returns>
public virtual IAsyncEnumerable<TToken> ListAsync(
[CanBeNull] int? count, [CanBeNull] int? offset, CancellationToken cancellationToken)
/// <inheritdoc/>
public virtual IAsyncEnumerable<TToken> ListAsync(int? count, int? offset, CancellationToken cancellationToken)
{
var query = Tokens.Include(token => token.Application)
.Include(token => token.Authorization)
.OrderBy(token => token.Id)
.OrderBy(token => token.Id!)
.AsQueryable();
if (offset.HasValue)
@ -730,18 +535,10 @@ namespace OpenIddict.EntityFramework
return query.AsAsyncEnumerable(cancellationToken);
}
/// <summary>
/// Executes the specified query and returns all the corresponding elements.
/// </summary>
/// <typeparam name="TState">The state type.</typeparam>
/// <typeparam name="TResult">The result type.</typeparam>
/// <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>All the elements returned when executing the specified query.</returns>
/// <inheritdoc/>
public virtual IAsyncEnumerable<TResult> ListAsync<TState, TResult>(
[NotNull] Func<IQueryable<TToken>, TState, IQueryable<TResult>> query,
[CanBeNull] TState state, CancellationToken cancellationToken)
Func<IQueryable<TToken>, TState, IQueryable<TResult>> query,
TState state, CancellationToken cancellationToken)
{
if (query == null)
{
@ -753,20 +550,16 @@ namespace OpenIddict.EntityFramework
.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="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
/// <inheritdoc/>
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.
// To work around this limitation, entities are manually listed and deleted using a batch logic.
List<Exception> exceptions = null;
List<Exception>? exceptions = null;
DbContextTransaction CreateTransaction()
DbContextTransaction? CreateTransaction()
{
// Note: relational providers like Sqlite are known to lack proper support
// for repeatable read transactions. To ensure this method can be safely used
@ -830,15 +623,8 @@ namespace OpenIddict.EntityFramework
}
}
/// <summary>
/// Sets the application identifier associated with a token.
/// </summary>
/// <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="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual async ValueTask SetApplicationIdAsync([NotNull] TToken token,
[CanBeNull] string identifier, CancellationToken cancellationToken)
/// <inheritdoc/>
public virtual async ValueTask SetApplicationIdAsync(TToken token, string? identifier, CancellationToken cancellationToken)
{
if (token == null)
{
@ -874,15 +660,8 @@ namespace OpenIddict.EntityFramework
}
}
/// <summary>
/// Sets the authorization identifier associated with a token.
/// </summary>
/// <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="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual async ValueTask SetAuthorizationIdAsync([NotNull] TToken token,
[CanBeNull] string identifier, CancellationToken cancellationToken)
/// <inheritdoc/>
public virtual async ValueTask SetAuthorizationIdAsync(TToken token, string? identifier, CancellationToken cancellationToken)
{
if (token == null)
{
@ -918,15 +697,8 @@ namespace OpenIddict.EntityFramework
}
}
/// <summary>
/// Sets the creation date associated with a token.
/// </summary>
/// <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="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetCreationDateAsync([NotNull] TToken token,
[CanBeNull] DateTimeOffset? date, CancellationToken cancellationToken)
/// <inheritdoc/>
public virtual ValueTask SetCreationDateAsync(TToken token, DateTimeOffset? date, CancellationToken cancellationToken)
{
if (token == null)
{
@ -938,15 +710,8 @@ namespace OpenIddict.EntityFramework
return default;
}
/// <summary>
/// Sets the expiration date associated with a token.
/// </summary>
/// <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="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetExpirationDateAsync([NotNull] TToken token,
[CanBeNull] DateTimeOffset? date, CancellationToken cancellationToken)
/// <inheritdoc/>
public virtual ValueTask SetExpirationDateAsync(TToken token, DateTimeOffset? date, CancellationToken cancellationToken)
{
if (token == null)
{
@ -958,14 +723,8 @@ namespace OpenIddict.EntityFramework
return default;
}
/// <summary>
/// Sets the payload associated with a token.
/// </summary>
/// <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="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetPayloadAsync([NotNull] TToken token, [CanBeNull] string payload, CancellationToken cancellationToken)
/// <inheritdoc/>
public virtual ValueTask SetPayloadAsync(TToken token, string? payload, CancellationToken cancellationToken)
{
if (token == null)
{
@ -977,15 +736,9 @@ namespace OpenIddict.EntityFramework
return default;
}
/// <summary>
/// Sets the additional properties associated with a token.
/// </summary>
/// <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="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetPropertiesAsync([NotNull] TToken token,
[CanBeNull] ImmutableDictionary<string, JsonElement> properties, CancellationToken cancellationToken)
/// <inheritdoc/>
public virtual ValueTask SetPropertiesAsync(TToken token,
ImmutableDictionary<string, JsonElement> properties, CancellationToken cancellationToken)
{
if (token == null)
{
@ -1008,16 +761,8 @@ namespace OpenIddict.EntityFramework
return default;
}
/// <summary>
/// Sets the reference identifier associated with a token.
/// Note: depending on the manager used to create the token,
/// the reference identifier may be hashed for security reasons.
/// </summary>
/// <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="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetReferenceIdAsync([NotNull] TToken token, [CanBeNull] string identifier, CancellationToken cancellationToken)
/// <inheritdoc/>
public virtual ValueTask SetReferenceIdAsync(TToken token, string? identifier, CancellationToken cancellationToken)
{
if (token == null)
{
@ -1029,14 +774,8 @@ namespace OpenIddict.EntityFramework
return default;
}
/// <summary>
/// Sets the status associated with a token.
/// </summary>
/// <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="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetStatusAsync([NotNull] TToken token, [CanBeNull] string status, CancellationToken cancellationToken)
/// <inheritdoc/>
public virtual ValueTask SetStatusAsync(TToken token, string? status, CancellationToken cancellationToken)
{
if (token == null)
{
@ -1048,14 +787,8 @@ namespace OpenIddict.EntityFramework
return default;
}
/// <summary>
/// Sets the subject associated with a token.
/// </summary>
/// <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="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetSubjectAsync([NotNull] TToken token, [CanBeNull] string subject, CancellationToken cancellationToken)
/// <inheritdoc/>
public virtual ValueTask SetSubjectAsync(TToken token, string? subject, CancellationToken cancellationToken)
{
if (token == null)
{
@ -1067,14 +800,8 @@ namespace OpenIddict.EntityFramework
return default;
}
/// <summary>
/// Sets the token type associated with a token.
/// </summary>
/// <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="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual ValueTask SetTypeAsync([NotNull] TToken token, [CanBeNull] string type, CancellationToken cancellationToken)
/// <inheritdoc/>
public virtual ValueTask SetTypeAsync(TToken token, string? type, CancellationToken cancellationToken)
{
if (token == null)
{
@ -1086,13 +813,8 @@ namespace OpenIddict.EntityFramework
return default;
}
/// <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="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
public virtual async ValueTask UpdateAsync([NotNull] TToken token, CancellationToken cancellationToken)
/// <inheritdoc/>
public virtual async ValueTask UpdateAsync(TToken token, CancellationToken cancellationToken)
{
if (token == null)
{
@ -1126,7 +848,8 @@ namespace OpenIddict.EntityFramework
/// </summary>
/// <param name="identifier">The identifier to convert.</param>
/// <returns>An instance of <typeparamref name="TKey"/> representing the provided identifier.</returns>
public virtual TKey ConvertIdentifierFromString([CanBeNull] string identifier)
[return: MaybeNull]
public virtual TKey ConvertIdentifierFromString(string? identifier)
{
if (string.IsNullOrEmpty(identifier))
{
@ -1141,7 +864,7 @@ namespace OpenIddict.EntityFramework
/// </summary>
/// <param name="identifier">The identifier to convert.</param>
/// <returns>A <see cref="string"/> representation of the provided identifier.</returns>
public virtual string ConvertIdentifierToString([CanBeNull] TKey identifier)
public virtual string? ConvertIdentifierToString([AllowNull] TKey identifier)
{
if (Equals(identifier, default(TKey)))
{

Loading…
Cancel
Save