Browse Source

Add nullable annotations to OpenIddict.EntityFrameworkCore

pull/1038/head
Kévin Chalet 6 years ago
parent
commit
c277fbabda
  1. 15
      src/OpenIddict.EntityFrameworkCore/Configurations/OpenIddictEntityFrameworkCoreApplicationConfiguration.cs
  2. 13
      src/OpenIddict.EntityFrameworkCore/Configurations/OpenIddictEntityFrameworkCoreAuthorizationConfiguration.cs
  3. 8
      src/OpenIddict.EntityFrameworkCore/Configurations/OpenIddictEntityFrameworkCoreScopeConfiguration.cs
  4. 11
      src/OpenIddict.EntityFrameworkCore/Configurations/OpenIddictEntityFrameworkCoreTokenConfiguration.cs
  5. 1
      src/OpenIddict.EntityFrameworkCore/OpenIddict.EntityFrameworkCore.csproj
  6. 11
      src/OpenIddict.EntityFrameworkCore/OpenIddictEntityFrameworkCoreBuilder.cs
  7. 5
      src/OpenIddict.EntityFrameworkCore/OpenIddictEntityFrameworkCoreCustomizer.cs
  8. 6
      src/OpenIddict.EntityFrameworkCore/OpenIddictEntityFrameworkCoreExtensions.cs
  9. 15
      src/OpenIddict.EntityFrameworkCore/OpenIddictEntityFrameworkCoreHelpers.cs
  10. 2
      src/OpenIddict.EntityFrameworkCore/OpenIddictEntityFrameworkCoreOptions.cs
  11. 7
      src/OpenIddict.EntityFrameworkCore/Resolvers/OpenIddictEntityFrameworkCoreApplicationStoreResolver.cs
  12. 7
      src/OpenIddict.EntityFrameworkCore/Resolvers/OpenIddictEntityFrameworkCoreAuthorizationStoreResolver.cs
  13. 7
      src/OpenIddict.EntityFrameworkCore/Resolvers/OpenIddictEntityFrameworkCoreScopeStoreResolver.cs
  14. 7
      src/OpenIddict.EntityFrameworkCore/Resolvers/OpenIddictEntityFrameworkCoreTokenStoreResolver.cs
  15. 457
      src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictEntityFrameworkCoreApplicationStore.cs
  16. 409
      src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictEntityFrameworkCoreAuthorizationStore.cs
  17. 351
      src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictEntityFrameworkCoreScopeStore.cs
  18. 530
      src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictEntityFrameworkCoreTokenStore.cs

15
src/OpenIddict.EntityFrameworkCore/Configurations/OpenIddictEntityFrameworkCoreApplicationConfiguration.cs

@ -6,7 +6,6 @@
using System; using System;
using System.ComponentModel; using System.ComponentModel;
using JetBrains.Annotations;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders; using Microsoft.EntityFrameworkCore.Metadata.Builders;
using OpenIddict.EntityFrameworkCore.Models; using OpenIddict.EntityFrameworkCore.Models;
@ -27,7 +26,7 @@ namespace OpenIddict.EntityFrameworkCore
where TToken : OpenIddictEntityFrameworkCoreToken<TKey, TApplication, TAuthorization> where TToken : OpenIddictEntityFrameworkCoreToken<TKey, TApplication, TAuthorization>
where TKey : IEquatable<TKey> where TKey : IEquatable<TKey>
{ {
public void Configure([NotNull] EntityTypeBuilder<TApplication> builder) public void Configure(EntityTypeBuilder<TApplication> builder)
{ {
if (builder == null) if (builder == null)
{ {
@ -47,28 +46,26 @@ namespace OpenIddict.EntityFrameworkCore
.IsUnique(); .IsUnique();
builder.Property(application => application.ClientId) builder.Property(application => application.ClientId)
.HasMaxLength(100) .HasMaxLength(100);
.IsRequired();
builder.Property(application => application.ConcurrencyToken) builder.Property(application => application.ConcurrencyToken)
.HasMaxLength(50) .HasMaxLength(50)
.IsConcurrencyToken(); .IsConcurrencyToken();
builder.Property(application => application.Id) builder.Property(application => application.Id!)
.ValueGeneratedOnAdd(); .ValueGeneratedOnAdd();
builder.Property(application => application.Type) builder.Property(application => application.Type)
.HasMaxLength(25) .HasMaxLength(25);
.IsRequired();
builder.HasMany(application => application.Authorizations) builder.HasMany(application => application.Authorizations)
.WithOne(authorization => authorization.Application) .WithOne(authorization => authorization.Application!)
.HasForeignKey(nameof(OpenIddictEntityFrameworkCoreAuthorization.Application) + .HasForeignKey(nameof(OpenIddictEntityFrameworkCoreAuthorization.Application) +
nameof(OpenIddictEntityFrameworkCoreApplication.Id)) nameof(OpenIddictEntityFrameworkCoreApplication.Id))
.IsRequired(required: false); .IsRequired(required: false);
builder.HasMany(application => application.Tokens) builder.HasMany(application => application.Tokens)
.WithOne(token => token.Application) .WithOne(token => token.Application!)
.HasForeignKey(nameof(OpenIddictEntityFrameworkCoreToken.Application) + nameof(OpenIddictEntityFrameworkCoreApplication.Id)) .HasForeignKey(nameof(OpenIddictEntityFrameworkCoreToken.Application) + nameof(OpenIddictEntityFrameworkCoreApplication.Id))
.IsRequired(required: false); .IsRequired(required: false);

13
src/OpenIddict.EntityFrameworkCore/Configurations/OpenIddictEntityFrameworkCoreAuthorizationConfiguration.cs

@ -6,7 +6,6 @@
using System; using System;
using System.ComponentModel; using System.ComponentModel;
using JetBrains.Annotations;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders; using Microsoft.EntityFrameworkCore.Metadata.Builders;
using OpenIddict.EntityFrameworkCore.Models; using OpenIddict.EntityFrameworkCore.Models;
@ -27,7 +26,7 @@ namespace OpenIddict.EntityFrameworkCore
where TToken : OpenIddictEntityFrameworkCoreToken<TKey, TApplication, TAuthorization> where TToken : OpenIddictEntityFrameworkCoreToken<TKey, TApplication, TAuthorization>
where TKey : IEquatable<TKey> where TKey : IEquatable<TKey>
{ {
public void Configure([NotNull] EntityTypeBuilder<TAuthorization> builder) public void Configure(EntityTypeBuilder<TAuthorization> builder)
{ {
if (builder == null) if (builder == null)
{ {
@ -50,22 +49,20 @@ namespace OpenIddict.EntityFrameworkCore
.HasMaxLength(50) .HasMaxLength(50)
.IsConcurrencyToken(); .IsConcurrencyToken();
builder.Property(authorization => authorization.Id) builder.Property(authorization => authorization.Id!)
.ValueGeneratedOnAdd(); .ValueGeneratedOnAdd();
builder.Property(authorization => authorization.Status) builder.Property(authorization => authorization.Status)
.HasMaxLength(25) .HasMaxLength(25);
.IsRequired();
builder.Property(authorization => authorization.Subject) builder.Property(authorization => authorization.Subject)
.HasMaxLength(450); .HasMaxLength(450);
builder.Property(authorization => authorization.Type) builder.Property(authorization => authorization.Type)
.HasMaxLength(25) .HasMaxLength(25);
.IsRequired();
builder.HasMany(authorization => authorization.Tokens) builder.HasMany(authorization => authorization.Tokens)
.WithOne(token => token.Authorization) .WithOne(token => token.Authorization!)
.HasForeignKey(nameof(OpenIddictEntityFrameworkCoreToken.Authorization) + .HasForeignKey(nameof(OpenIddictEntityFrameworkCoreToken.Authorization) +
nameof(OpenIddictEntityFrameworkCoreAuthorization.Id)) nameof(OpenIddictEntityFrameworkCoreAuthorization.Id))
.IsRequired(required: false); .IsRequired(required: false);

8
src/OpenIddict.EntityFrameworkCore/Configurations/OpenIddictEntityFrameworkCoreScopeConfiguration.cs

@ -6,7 +6,6 @@
using System; using System;
using System.ComponentModel; using System.ComponentModel;
using JetBrains.Annotations;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders; using Microsoft.EntityFrameworkCore.Metadata.Builders;
using OpenIddict.EntityFrameworkCore.Models; using OpenIddict.EntityFrameworkCore.Models;
@ -23,7 +22,7 @@ namespace OpenIddict.EntityFrameworkCore
where TScope : OpenIddictEntityFrameworkCoreScope<TKey> where TScope : OpenIddictEntityFrameworkCoreScope<TKey>
where TKey : IEquatable<TKey> where TKey : IEquatable<TKey>
{ {
public void Configure([NotNull] EntityTypeBuilder<TScope> builder) public void Configure(EntityTypeBuilder<TScope> builder)
{ {
if (builder == null) if (builder == null)
{ {
@ -46,12 +45,11 @@ namespace OpenIddict.EntityFrameworkCore
.HasMaxLength(50) .HasMaxLength(50)
.IsConcurrencyToken(); .IsConcurrencyToken();
builder.Property(scope => scope.Id) builder.Property(scope => scope.Id!)
.ValueGeneratedOnAdd(); .ValueGeneratedOnAdd();
builder.Property(scope => scope.Name) builder.Property(scope => scope.Name)
.HasMaxLength(200) .HasMaxLength(200);
.IsRequired();
builder.ToTable("OpenIddictScopes"); builder.ToTable("OpenIddictScopes");
} }

11
src/OpenIddict.EntityFrameworkCore/Configurations/OpenIddictEntityFrameworkCoreTokenConfiguration.cs

@ -6,7 +6,6 @@
using System; using System;
using System.ComponentModel; using System.ComponentModel;
using JetBrains.Annotations;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders; using Microsoft.EntityFrameworkCore.Metadata.Builders;
using OpenIddict.EntityFrameworkCore.Models; using OpenIddict.EntityFrameworkCore.Models;
@ -27,7 +26,7 @@ namespace OpenIddict.EntityFrameworkCore
where TAuthorization : OpenIddictEntityFrameworkCoreAuthorization<TKey, TApplication, TToken> where TAuthorization : OpenIddictEntityFrameworkCoreAuthorization<TKey, TApplication, TToken>
where TKey : IEquatable<TKey> where TKey : IEquatable<TKey>
{ {
public void Configure([NotNull] EntityTypeBuilder<TToken> builder) public void Configure(EntityTypeBuilder<TToken> builder)
{ {
if (builder == null) if (builder == null)
{ {
@ -56,22 +55,20 @@ namespace OpenIddict.EntityFrameworkCore
.HasMaxLength(50) .HasMaxLength(50)
.IsConcurrencyToken(); .IsConcurrencyToken();
builder.Property(token => token.Id) builder.Property(token => token.Id!)
.ValueGeneratedOnAdd(); .ValueGeneratedOnAdd();
builder.Property(token => token.ReferenceId) builder.Property(token => token.ReferenceId)
.HasMaxLength(100); .HasMaxLength(100);
builder.Property(token => token.Status) builder.Property(token => token.Status)
.HasMaxLength(25) .HasMaxLength(25);
.IsRequired();
builder.Property(token => token.Subject) builder.Property(token => token.Subject)
.HasMaxLength(450); .HasMaxLength(450);
builder.Property(token => token.Type) builder.Property(token => token.Type)
.HasMaxLength(25) .HasMaxLength(25);
.IsRequired();
builder.ToTable("OpenIddictTokens"); builder.ToTable("OpenIddictTokens");
} }

1
src/OpenIddict.EntityFrameworkCore/OpenIddict.EntityFrameworkCore.csproj

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

11
src/OpenIddict.EntityFrameworkCore/OpenIddictEntityFrameworkCoreBuilder.cs

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

5
src/OpenIddict.EntityFrameworkCore/OpenIddictEntityFrameworkCoreCustomizer.cs

@ -5,7 +5,6 @@
*/ */
using System; using System;
using JetBrains.Annotations;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Infrastructure;
using OpenIddict.EntityFrameworkCore.Models; using OpenIddict.EntityFrameworkCore.Models;
@ -23,12 +22,12 @@ namespace OpenIddict.EntityFrameworkCore
where TToken : OpenIddictEntityFrameworkCoreToken<TKey, TApplication, TAuthorization> where TToken : OpenIddictEntityFrameworkCoreToken<TKey, TApplication, TAuthorization>
where TKey : IEquatable<TKey> where TKey : IEquatable<TKey>
{ {
public OpenIddictEntityFrameworkCoreCustomizer([NotNull] ModelCustomizerDependencies dependencies) public OpenIddictEntityFrameworkCoreCustomizer(ModelCustomizerDependencies dependencies)
: base(dependencies) : base(dependencies)
{ {
} }
public override void Customize([NotNull] ModelBuilder modelBuilder, [NotNull] DbContext context) public override void Customize(ModelBuilder modelBuilder, DbContext context)
{ {
if (modelBuilder == null) if (modelBuilder == null)
{ {

6
src/OpenIddict.EntityFrameworkCore/OpenIddictEntityFrameworkCoreExtensions.cs

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

15
src/OpenIddict.EntityFrameworkCore/OpenIddictEntityFrameworkCoreHelpers.cs

@ -9,7 +9,6 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Threading; using System.Threading;
using JetBrains.Annotations;
using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using OpenIddict.EntityFrameworkCore; using OpenIddict.EntityFrameworkCore;
@ -28,7 +27,7 @@ namespace Microsoft.EntityFrameworkCore
/// </summary> /// </summary>
/// <param name="builder">The builder used to configure the Entity Framework context.</param> /// <param name="builder">The builder used to configure the Entity Framework context.</param>
/// <returns>The Entity Framework context builder.</returns> /// <returns>The Entity Framework context builder.</returns>
public static DbContextOptionsBuilder UseOpenIddict([NotNull] this DbContextOptionsBuilder builder) public static DbContextOptionsBuilder UseOpenIddict(this DbContextOptionsBuilder builder)
=> builder.UseOpenIddict<OpenIddictEntityFrameworkCoreApplication, => builder.UseOpenIddict<OpenIddictEntityFrameworkCoreApplication,
OpenIddictEntityFrameworkCoreAuthorization, OpenIddictEntityFrameworkCoreAuthorization,
OpenIddictEntityFrameworkCoreScope, OpenIddictEntityFrameworkCoreScope,
@ -44,7 +43,7 @@ namespace Microsoft.EntityFrameworkCore
/// </remarks> /// </remarks>
/// <param name="builder">The builder used to configure the Entity Framework context.</param> /// <param name="builder">The builder used to configure the Entity Framework context.</param>
/// <returns>The Entity Framework context builder.</returns> /// <returns>The Entity Framework context builder.</returns>
public static DbContextOptionsBuilder UseOpenIddict<TKey>([NotNull] this DbContextOptionsBuilder builder) public static DbContextOptionsBuilder UseOpenIddict<TKey>(this DbContextOptionsBuilder builder)
where TKey : IEquatable<TKey> where TKey : IEquatable<TKey>
=> builder.UseOpenIddict<OpenIddictEntityFrameworkCoreApplication<TKey>, => builder.UseOpenIddict<OpenIddictEntityFrameworkCoreApplication<TKey>,
OpenIddictEntityFrameworkCoreAuthorization<TKey>, OpenIddictEntityFrameworkCoreAuthorization<TKey>,
@ -62,7 +61,7 @@ namespace Microsoft.EntityFrameworkCore
/// <param name="builder">The builder used to configure the Entity Framework context.</param> /// <param name="builder">The builder used to configure the Entity Framework context.</param>
/// <returns>The Entity Framework context builder.</returns> /// <returns>The Entity Framework context builder.</returns>
public static DbContextOptionsBuilder UseOpenIddict<TApplication, TAuthorization, TScope, TToken, TKey>( public static DbContextOptionsBuilder UseOpenIddict<TApplication, TAuthorization, TScope, TToken, TKey>(
[NotNull] this DbContextOptionsBuilder builder) this DbContextOptionsBuilder builder)
where TApplication : OpenIddictEntityFrameworkCoreApplication<TKey, TAuthorization, TToken> where TApplication : OpenIddictEntityFrameworkCoreApplication<TKey, TAuthorization, TToken>
where TAuthorization : OpenIddictEntityFrameworkCoreAuthorization<TKey, TApplication, TToken> where TAuthorization : OpenIddictEntityFrameworkCoreAuthorization<TKey, TApplication, TToken>
where TScope : OpenIddictEntityFrameworkCoreScope<TKey> where TScope : OpenIddictEntityFrameworkCoreScope<TKey>
@ -84,7 +83,7 @@ namespace Microsoft.EntityFrameworkCore
/// </summary> /// </summary>
/// <param name="builder">The builder used to configure the Entity Framework context.</param> /// <param name="builder">The builder used to configure the Entity Framework context.</param>
/// <returns>The Entity Framework context builder.</returns> /// <returns>The Entity Framework context builder.</returns>
public static ModelBuilder UseOpenIddict([NotNull] this ModelBuilder builder) public static ModelBuilder UseOpenIddict(this ModelBuilder builder)
=> builder.UseOpenIddict<OpenIddictEntityFrameworkCoreApplication, => builder.UseOpenIddict<OpenIddictEntityFrameworkCoreApplication,
OpenIddictEntityFrameworkCoreAuthorization, OpenIddictEntityFrameworkCoreAuthorization,
OpenIddictEntityFrameworkCoreScope, OpenIddictEntityFrameworkCoreScope,
@ -100,7 +99,7 @@ namespace Microsoft.EntityFrameworkCore
/// </remarks> /// </remarks>
/// <param name="builder">The builder used to configure the Entity Framework context.</param> /// <param name="builder">The builder used to configure the Entity Framework context.</param>
/// <returns>The Entity Framework context builder.</returns> /// <returns>The Entity Framework context builder.</returns>
public static ModelBuilder UseOpenIddict<TKey>([NotNull] this ModelBuilder builder) where TKey : IEquatable<TKey> public static ModelBuilder UseOpenIddict<TKey>(this ModelBuilder builder) where TKey : IEquatable<TKey>
=> builder.UseOpenIddict<OpenIddictEntityFrameworkCoreApplication<TKey>, => builder.UseOpenIddict<OpenIddictEntityFrameworkCoreApplication<TKey>,
OpenIddictEntityFrameworkCoreAuthorization<TKey>, OpenIddictEntityFrameworkCoreAuthorization<TKey>,
OpenIddictEntityFrameworkCoreScope<TKey>, OpenIddictEntityFrameworkCoreScope<TKey>,
@ -116,7 +115,7 @@ namespace Microsoft.EntityFrameworkCore
/// </remarks> /// </remarks>
/// <param name="builder">The builder used to configure the Entity Framework context.</param> /// <param name="builder">The builder used to configure the Entity Framework context.</param>
/// <returns>The Entity Framework context builder.</returns> /// <returns>The Entity Framework context builder.</returns>
public static ModelBuilder UseOpenIddict<TApplication, TAuthorization, TScope, TToken, TKey>([NotNull] this ModelBuilder builder) public static ModelBuilder UseOpenIddict<TApplication, TAuthorization, TScope, TToken, TKey>(this ModelBuilder builder)
where TApplication : OpenIddictEntityFrameworkCoreApplication<TKey, TAuthorization, TToken> where TApplication : OpenIddictEntityFrameworkCoreApplication<TKey, TAuthorization, TToken>
where TAuthorization : OpenIddictEntityFrameworkCoreAuthorization<TKey, TApplication, TToken> where TAuthorization : OpenIddictEntityFrameworkCoreAuthorization<TKey, TApplication, TToken>
where TScope : OpenIddictEntityFrameworkCoreScope<TKey> where TScope : OpenIddictEntityFrameworkCoreScope<TKey>
@ -144,7 +143,7 @@ namespace Microsoft.EntityFrameworkCore
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</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> /// <returns>The non-streamed async enumeration containing the results.</returns>
internal static IAsyncEnumerable<T> AsAsyncEnumerable<T>( internal static IAsyncEnumerable<T> AsAsyncEnumerable<T>(
[NotNull] this IQueryable<T> source, CancellationToken cancellationToken = default) this IQueryable<T> source, CancellationToken cancellationToken = default)
{ {
if (source == null) if (source == null)
{ {

2
src/OpenIddict.EntityFrameworkCore/OpenIddictEntityFrameworkCoreOptions.cs

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

7
src/OpenIddict.EntityFrameworkCore/Resolvers/OpenIddictEntityFrameworkCoreApplicationStoreResolver.cs

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

7
src/OpenIddict.EntityFrameworkCore/Resolvers/OpenIddictEntityFrameworkCoreAuthorizationStoreResolver.cs

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

7
src/OpenIddict.EntityFrameworkCore/Resolvers/OpenIddictEntityFrameworkCoreScopeStoreResolver.cs

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

7
src/OpenIddict.EntityFrameworkCore/Resolvers/OpenIddictEntityFrameworkCoreTokenStoreResolver.cs

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

457
src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictEntityFrameworkCoreApplicationStore.cs

@ -9,6 +9,7 @@ using System.Collections.Generic;
using System.Collections.Immutable; using System.Collections.Immutable;
using System.ComponentModel; using System.ComponentModel;
using System.Data; using System.Data;
using System.Diagnostics.CodeAnalysis;
using System.Globalization; using System.Globalization;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
@ -18,7 +19,6 @@ using System.Text.Encodings.Web;
using System.Text.Json; using System.Text.Json;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using JetBrains.Annotations;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Storage; using Microsoft.EntityFrameworkCore.Storage;
@ -41,9 +41,9 @@ namespace OpenIddict.EntityFrameworkCore
where TContext : DbContext where TContext : DbContext
{ {
public OpenIddictEntityFrameworkCoreApplicationStore( public OpenIddictEntityFrameworkCoreApplicationStore(
[NotNull] IMemoryCache cache, IMemoryCache cache,
[NotNull] TContext context, TContext context,
[NotNull] IOptionsMonitor<OpenIddictEntityFrameworkCoreOptions> options) IOptionsMonitor<OpenIddictEntityFrameworkCoreOptions> options)
: base(cache, context, options) : base(cache, context, options)
{ {
} }
@ -62,9 +62,9 @@ namespace OpenIddict.EntityFrameworkCore
where TKey : IEquatable<TKey> where TKey : IEquatable<TKey>
{ {
public OpenIddictEntityFrameworkCoreApplicationStore( public OpenIddictEntityFrameworkCoreApplicationStore(
[NotNull] IMemoryCache cache, IMemoryCache cache,
[NotNull] TContext context, TContext context,
[NotNull] IOptionsMonitor<OpenIddictEntityFrameworkCoreOptions> options) IOptionsMonitor<OpenIddictEntityFrameworkCoreOptions> options)
: base(cache, context, options) : base(cache, context, options)
{ {
} }
@ -86,9 +86,9 @@ namespace OpenIddict.EntityFrameworkCore
where TKey : IEquatable<TKey> where TKey : IEquatable<TKey>
{ {
public OpenIddictEntityFrameworkCoreApplicationStore( public OpenIddictEntityFrameworkCoreApplicationStore(
[NotNull] IMemoryCache cache, IMemoryCache cache,
[NotNull] TContext context, TContext context,
[NotNull] IOptionsMonitor<OpenIddictEntityFrameworkCoreOptions> options) IOptionsMonitor<OpenIddictEntityFrameworkCoreOptions> options)
{ {
Cache = cache; Cache = cache;
Context = context; Context = context;
@ -136,17 +136,8 @@ namespace OpenIddict.EntityFrameworkCore
public virtual async ValueTask<long> CountAsync(CancellationToken cancellationToken) public virtual async ValueTask<long> CountAsync(CancellationToken cancellationToken)
=> await Applications.AsQueryable().LongCountAsync(cancellationToken); => await Applications.AsQueryable().LongCountAsync(cancellationToken);
/// <summary> /// <inheritdoc/>
/// Determines the number of applications that match the specified query. public virtual async ValueTask<long> CountAsync<TResult>(Func<IQueryable<TApplication>, IQueryable<TResult>> query, CancellationToken cancellationToken)
/// </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)
{ {
if (query == null) if (query == null)
{ {
@ -156,13 +147,8 @@ namespace OpenIddict.EntityFrameworkCore
return await query(Applications).LongCountAsync(cancellationToken); return await query(Applications).LongCountAsync(cancellationToken);
} }
/// <summary> /// <inheritdoc/>
/// Creates a new application. public virtual async ValueTask CreateAsync(TApplication application, CancellationToken cancellationToken)
/// </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)
{ {
if (application == null) if (application == null)
{ {
@ -174,20 +160,15 @@ namespace OpenIddict.EntityFrameworkCore
await Context.SaveChangesAsync(cancellationToken); await Context.SaveChangesAsync(cancellationToken);
} }
/// <summary> /// <inheritdoc/>
/// Removes an existing application. public virtual async ValueTask DeleteAsync(TApplication application, CancellationToken cancellationToken)
/// </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)
{ {
if (application == null) if (application == null)
{ {
throw new ArgumentNullException(nameof(application)); throw new ArgumentNullException(nameof(application));
} }
async ValueTask<IDbContextTransaction> CreateTransactionAsync() async ValueTask<IDbContextTransaction?> CreateTransactionAsync()
{ {
// Note: transactions that specify an explicit isolation level are only supported by // Note: transactions that specify an explicit isolation level are only supported by
// relational providers and trying to use them with a different provider results in // relational providers and trying to use them with a different provider results in
@ -217,8 +198,8 @@ namespace OpenIddict.EntityFrameworkCore
Task<List<TAuthorization>> ListAuthorizationsAsync() Task<List<TAuthorization>> ListAuthorizationsAsync()
=> (from authorization in Authorizations.Include(authorization => authorization.Tokens).AsTracking() => (from authorization in Authorizations.Include(authorization => authorization.Tokens).AsTracking()
join element in Applications.AsTracking() on authorization.Application.Id equals element.Id join element in Applications.AsTracking() on authorization.Application!.Id equals element.Id
where element.Id.Equals(application.Id) where element.Id!.Equals(application.Id)
select authorization).ToListAsync(cancellationToken); select authorization).ToListAsync(cancellationToken);
// Note: due to a bug in Entity Framework Core's query visitor, the tokens can't be // Note: due to a bug in Entity Framework Core's query visitor, the tokens can't be
@ -229,8 +210,8 @@ namespace OpenIddict.EntityFrameworkCore
Task<List<TToken>> ListTokensAsync() Task<List<TToken>> ListTokensAsync()
=> (from token in Tokens.AsTracking() => (from token in Tokens.AsTracking()
where token.Authorization == null where token.Authorization == null
join element in Applications.AsTracking() on token.Application.Id equals element.Id join element in Applications.AsTracking() on token.Application!.Id equals element.Id
where element.Id.Equals(application.Id) where element.Id!.Equals(application.Id)
select token).ToListAsync(cancellationToken); select token).ToListAsync(cancellationToken);
// To prevent an SQL exception from being thrown if a new associated entity is // To prevent an SQL exception from being thrown if a new associated entity is
@ -285,16 +266,8 @@ namespace OpenIddict.EntityFrameworkCore
} }
} }
/// <summary> /// <inheritdoc/>
/// Retrieves an application using its client identifier. public virtual async ValueTask<TApplication?> FindByClientIdAsync(string identifier, CancellationToken cancellationToken)
/// </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)
{ {
if (string.IsNullOrEmpty(identifier)) if (string.IsNullOrEmpty(identifier))
{ {
@ -306,16 +279,8 @@ namespace OpenIddict.EntityFrameworkCore
select application).FirstOrDefaultAsync(cancellationToken); select application).FirstOrDefaultAsync(cancellationToken);
} }
/// <summary> /// <inheritdoc/>
/// Retrieves an application using its unique identifier. public virtual async ValueTask<TApplication?> FindByIdAsync(string identifier, CancellationToken cancellationToken)
/// </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)
{ {
if (string.IsNullOrEmpty(identifier)) if (string.IsNullOrEmpty(identifier))
{ {
@ -325,18 +290,13 @@ namespace OpenIddict.EntityFrameworkCore
var key = ConvertIdentifierFromString(identifier); var key = ConvertIdentifierFromString(identifier);
return await (from application in Applications.AsTracking() return await (from application in Applications.AsTracking()
where application.Id.Equals(key) where application.Id!.Equals(key)
select application).FirstOrDefaultAsync(cancellationToken); select application).FirstOrDefaultAsync(cancellationToken);
} }
/// <summary> /// <inheritdoc/>
/// 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>
public virtual IAsyncEnumerable<TApplication> FindByPostLogoutRedirectUriAsync( public virtual IAsyncEnumerable<TApplication> FindByPostLogoutRedirectUriAsync(
[NotNull] string address, CancellationToken cancellationToken) string address, CancellationToken cancellationToken)
{ {
if (string.IsNullOrEmpty(address)) if (string.IsNullOrEmpty(address))
{ {
@ -354,7 +314,7 @@ namespace OpenIddict.EntityFrameworkCore
async IAsyncEnumerable<TApplication> ExecuteAsync([EnumeratorCancellation] CancellationToken cancellationToken) async IAsyncEnumerable<TApplication> ExecuteAsync([EnumeratorCancellation] CancellationToken cancellationToken)
{ {
var applications = (from application in Applications.AsTracking() var applications = (from application in Applications.AsTracking()
where application.PostLogoutRedirectUris.Contains(address) where application.PostLogoutRedirectUris!.Contains(address)
select application).AsAsyncEnumerable(); select application).AsAsyncEnumerable();
await foreach (var application in applications) await foreach (var application in applications)
@ -368,14 +328,9 @@ namespace OpenIddict.EntityFrameworkCore
} }
} }
/// <summary> /// <inheritdoc/>
/// 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>
public virtual IAsyncEnumerable<TApplication> FindByRedirectUriAsync( public virtual IAsyncEnumerable<TApplication> FindByRedirectUriAsync(
[NotNull] string address, CancellationToken cancellationToken) string address, CancellationToken cancellationToken)
{ {
if (string.IsNullOrEmpty(address)) if (string.IsNullOrEmpty(address))
{ {
@ -393,7 +348,7 @@ namespace OpenIddict.EntityFrameworkCore
async IAsyncEnumerable<TApplication> ExecuteAsync([EnumeratorCancellation] CancellationToken cancellationToken) async IAsyncEnumerable<TApplication> ExecuteAsync([EnumeratorCancellation] CancellationToken cancellationToken)
{ {
var applications = (from application in Applications.AsTracking() var applications = (from application in Applications.AsTracking()
where application.RedirectUris.Contains(address) where application.RedirectUris!.Contains(address)
select application).AsAsyncEnumerable(); select application).AsAsyncEnumerable();
await foreach (var application in applications) await foreach (var application in applications)
@ -407,21 +362,10 @@ namespace OpenIddict.EntityFrameworkCore
} }
} }
/// <summary> /// <inheritdoc/>
/// 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>
public virtual async ValueTask<TResult> GetAsync<TState, TResult>( public virtual async ValueTask<TResult> GetAsync<TState, TResult>(
[NotNull] Func<IQueryable<TApplication>, TState, IQueryable<TResult>> query, Func<IQueryable<TApplication>, TState, IQueryable<TResult>> query,
[CanBeNull] TState state, CancellationToken cancellationToken) TState state, CancellationToken cancellationToken)
{ {
if (query == null) if (query == null)
{ {
@ -431,113 +375,63 @@ namespace OpenIddict.EntityFrameworkCore
return await query(Applications.AsTracking(), state).FirstOrDefaultAsync(cancellationToken); return await query(Applications.AsTracking(), state).FirstOrDefaultAsync(cancellationToken);
} }
/// <summary> /// <inheritdoc/>
/// Retrieves the client identifier associated with an application. public virtual ValueTask<string?> GetClientIdAsync(TApplication application, CancellationToken cancellationToken)
/// </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)
{ {
if (application == null) if (application == null)
{ {
throw new ArgumentNullException(nameof(application)); throw new ArgumentNullException(nameof(application));
} }
return new ValueTask<string>(application.ClientId); return new ValueTask<string?>(application.ClientId);
} }
/// <summary> /// <inheritdoc/>
/// Retrieves the client secret associated with an application. public virtual ValueTask<string?> GetClientSecretAsync(TApplication application, CancellationToken cancellationToken)
/// 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)
{ {
if (application == null) if (application == null)
{ {
throw new ArgumentNullException(nameof(application)); throw new ArgumentNullException(nameof(application));
} }
return new ValueTask<string>(application.ClientSecret); return new ValueTask<string?>(application.ClientSecret);
} }
/// <summary> /// <inheritdoc/>
/// Retrieves the client type associated with an application. public virtual ValueTask<string?> GetClientTypeAsync(TApplication application, CancellationToken cancellationToken)
/// </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)
{ {
if (application == null) if (application == null)
{ {
throw new ArgumentNullException(nameof(application)); throw new ArgumentNullException(nameof(application));
} }
return new ValueTask<string>(application.Type); return new ValueTask<string?>(application.Type);
} }
/// <summary> /// <inheritdoc/>
/// Retrieves the consent type associated with an application. public virtual ValueTask<string?> GetConsentTypeAsync(TApplication application, CancellationToken cancellationToken)
/// </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)
{ {
if (application == null) if (application == null)
{ {
throw new ArgumentNullException(nameof(application)); throw new ArgumentNullException(nameof(application));
} }
return new ValueTask<string>(application.ConsentType); return new ValueTask<string?>(application.ConsentType);
} }
/// <summary> /// <inheritdoc/>
/// Retrieves the display name associated with an application. public virtual ValueTask<string?> GetDisplayNameAsync(TApplication application, CancellationToken cancellationToken)
/// </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)
{ {
if (application == null) if (application == null)
{ {
throw new ArgumentNullException(nameof(application)); throw new ArgumentNullException(nameof(application));
} }
return new ValueTask<string>(application.DisplayName); return new ValueTask<string?>(application.DisplayName);
} }
/// <summary> /// <inheritdoc/>
/// Retrieves the localized display names associated with an application. public virtual ValueTask<ImmutableDictionary<CultureInfo, string>> GetDisplayNamesAsync(TApplication application, CancellationToken cancellationToken)
/// </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)
{ {
if (application == null) if (application == null)
{ {
@ -564,35 +458,19 @@ namespace OpenIddict.EntityFrameworkCore
return new ValueTask<ImmutableDictionary<CultureInfo, string>>(names); return new ValueTask<ImmutableDictionary<CultureInfo, string>>(names);
} }
/// <summary> /// <inheritdoc/>
/// Retrieves the unique identifier associated with an application. public virtual ValueTask<string?> GetIdAsync(TApplication application, CancellationToken cancellationToken)
/// </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)
{ {
if (application == null) if (application == null)
{ {
throw new ArgumentNullException(nameof(application)); throw new ArgumentNullException(nameof(application));
} }
return new ValueTask<string>(ConvertIdentifierToString(application.Id)); return new ValueTask<string?>(ConvertIdentifierToString(application.Id));
} }
/// <summary> /// <inheritdoc/>
/// Retrieves the permissions associated with an application. public virtual ValueTask<ImmutableArray<string>> GetPermissionsAsync(TApplication application, CancellationToken cancellationToken)
/// </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)
{ {
if (application == null) if (application == null)
{ {
@ -618,16 +496,8 @@ namespace OpenIddict.EntityFrameworkCore
return new ValueTask<ImmutableArray<string>>(permissions); return new ValueTask<ImmutableArray<string>>(permissions);
} }
/// <summary> /// <inheritdoc/>
/// Retrieves the logout callback addresses associated with an application. public virtual ValueTask<ImmutableArray<string>> GetPostLogoutRedirectUrisAsync(TApplication application, CancellationToken cancellationToken)
/// </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)
{ {
if (application == null) if (application == null)
{ {
@ -653,16 +523,8 @@ namespace OpenIddict.EntityFrameworkCore
return new ValueTask<ImmutableArray<string>>(addresses); return new ValueTask<ImmutableArray<string>>(addresses);
} }
/// <summary> /// <inheritdoc/>
/// Retrieves the additional properties associated with an application. public virtual ValueTask<ImmutableDictionary<string, JsonElement>> GetPropertiesAsync(TApplication application, CancellationToken cancellationToken)
/// </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)
{ {
if (application == null) if (application == null)
{ {
@ -688,16 +550,8 @@ namespace OpenIddict.EntityFrameworkCore
return new ValueTask<ImmutableDictionary<string, JsonElement>>(properties); return new ValueTask<ImmutableDictionary<string, JsonElement>>(properties);
} }
/// <summary> /// <inheritdoc/>
/// Retrieves the callback addresses associated with an application. public virtual ValueTask<ImmutableArray<string>> GetRedirectUrisAsync(TApplication application, CancellationToken cancellationToken)
/// </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)
{ {
if (application == null) if (application == null)
{ {
@ -723,16 +577,8 @@ namespace OpenIddict.EntityFrameworkCore
return new ValueTask<ImmutableArray<string>>(addresses); return new ValueTask<ImmutableArray<string>>(addresses);
} }
/// <summary> /// <inheritdoc/>
/// Retrieves the requirements associated with an application. public virtual ValueTask<ImmutableArray<string>> GetRequirementsAsync(TApplication application, CancellationToken cancellationToken)
/// </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)
{ {
if (application == null) if (application == null)
{ {
@ -758,14 +604,7 @@ namespace OpenIddict.EntityFrameworkCore
return new ValueTask<ImmutableArray<string>>(requirements); return new ValueTask<ImmutableArray<string>>(requirements);
} }
/// <summary> /// <inheritdoc/>
/// 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>
public virtual ValueTask<TApplication> InstantiateAsync(CancellationToken cancellationToken) public virtual ValueTask<TApplication> InstantiateAsync(CancellationToken cancellationToken)
{ {
try try
@ -780,17 +619,10 @@ namespace OpenIddict.EntityFrameworkCore
} }
} }
/// <summary> /// <inheritdoc/>
/// Executes the specified query and returns all the corresponding elements. public virtual IAsyncEnumerable<TApplication> ListAsync(int? count, int? offset, CancellationToken cancellationToken)
/// </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<TApplication> ListAsync(
[CanBeNull] int? count, [CanBeNull] int? offset, CancellationToken cancellationToken)
{ {
var query = Applications.AsQueryable().OrderBy(application => application.Id).AsTracking(); var query = Applications.AsQueryable().OrderBy(application => application.Id!).AsTracking();
if (offset.HasValue) if (offset.HasValue)
{ {
@ -805,18 +637,10 @@ namespace OpenIddict.EntityFrameworkCore
return query.AsAsyncEnumerable(); return query.AsAsyncEnumerable();
} }
/// <summary> /// <inheritdoc/>
/// 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>
public virtual IAsyncEnumerable<TResult> ListAsync<TState, TResult>( public virtual IAsyncEnumerable<TResult> ListAsync<TState, TResult>(
[NotNull] Func<IQueryable<TApplication>, TState, IQueryable<TResult>> query, Func<IQueryable<TApplication>, TState, IQueryable<TResult>> query,
[CanBeNull] TState state, CancellationToken cancellationToken) TState state, CancellationToken cancellationToken)
{ {
if (query == null) if (query == null)
{ {
@ -826,15 +650,8 @@ namespace OpenIddict.EntityFrameworkCore
return query(Applications.AsTracking(), state).AsAsyncEnumerable(); return query(Applications.AsTracking(), state).AsAsyncEnumerable();
} }
/// <summary> /// <inheritdoc/>
/// Sets the client identifier associated with an application. public virtual ValueTask SetClientIdAsync(TApplication application, string? identifier, CancellationToken cancellationToken)
/// </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)
{ {
if (application == null) if (application == null)
{ {
@ -846,17 +663,8 @@ namespace OpenIddict.EntityFrameworkCore
return default; return default;
} }
/// <summary> /// <inheritdoc/>
/// Sets the client secret associated with an application. public virtual ValueTask SetClientSecretAsync(TApplication application, string? secret, CancellationToken cancellationToken)
/// 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)
{ {
if (application == null) if (application == null)
{ {
@ -868,15 +676,8 @@ namespace OpenIddict.EntityFrameworkCore
return default; return default;
} }
/// <summary> /// <inheritdoc/>
/// Sets the client type associated with an application. public virtual ValueTask SetClientTypeAsync(TApplication application, string? type, CancellationToken cancellationToken)
/// </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)
{ {
if (application == null) if (application == null)
{ {
@ -888,15 +689,8 @@ namespace OpenIddict.EntityFrameworkCore
return default; return default;
} }
/// <summary> /// <inheritdoc/>
/// Sets the consent type associated with an application. public virtual ValueTask SetConsentTypeAsync(TApplication application, string? type, CancellationToken cancellationToken)
/// </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)
{ {
if (application == null) if (application == null)
{ {
@ -908,15 +702,8 @@ namespace OpenIddict.EntityFrameworkCore
return default; return default;
} }
/// <summary> /// <inheritdoc/>
/// Sets the display name associated with an application. public virtual ValueTask SetDisplayNameAsync(TApplication application, string? name, CancellationToken cancellationToken)
/// </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)
{ {
if (application == null) if (application == null)
{ {
@ -928,15 +715,9 @@ namespace OpenIddict.EntityFrameworkCore
return default; return default;
} }
/// <summary> /// <inheritdoc/>
/// Sets the localized display names associated with an application. public virtual ValueTask SetDisplayNamesAsync(TApplication application,
/// </summary> ImmutableDictionary<CultureInfo, string> names, CancellationToken cancellationToken)
/// <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)
{ {
if (application == null) if (application == null)
{ {
@ -958,7 +739,7 @@ namespace OpenIddict.EntityFrameworkCore
}); });
writer.WriteStartObject(); writer.WriteStartObject();
foreach (var pair in names) foreach (var pair in names)
{ {
writer.WritePropertyName(pair.Key.Name); writer.WritePropertyName(pair.Key.Name);
@ -973,14 +754,8 @@ namespace OpenIddict.EntityFrameworkCore
return default; return default;
} }
/// <summary> /// <inheritdoc/>
/// Sets the permissions associated with an application. public virtual ValueTask SetPermissionsAsync(TApplication application, ImmutableArray<string> permissions, CancellationToken cancellationToken)
/// </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)
{ {
if (application == null) if (application == null)
{ {
@ -1003,14 +778,8 @@ namespace OpenIddict.EntityFrameworkCore
return default; return default;
} }
/// <summary> /// <inheritdoc/>
/// Sets the logout callback addresses associated with an application. public virtual ValueTask SetPostLogoutRedirectUrisAsync(TApplication 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,
ImmutableArray<string> addresses, CancellationToken cancellationToken) ImmutableArray<string> addresses, CancellationToken cancellationToken)
{ {
if (application == null) if (application == null)
@ -1034,15 +803,9 @@ namespace OpenIddict.EntityFrameworkCore
return default; return default;
} }
/// <summary> /// <inheritdoc/>
/// Sets the additional properties associated with an application. public virtual ValueTask SetPropertiesAsync(TApplication application,
/// </summary> ImmutableDictionary<string, JsonElement> properties, CancellationToken cancellationToken)
/// <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)
{ {
if (application == null) if (application == null)
{ {
@ -1065,14 +828,8 @@ namespace OpenIddict.EntityFrameworkCore
return default; return default;
} }
/// <summary> /// <inheritdoc/>
/// Sets the callback addresses associated with an application. public virtual ValueTask SetRedirectUrisAsync(TApplication 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,
ImmutableArray<string> addresses, CancellationToken cancellationToken) ImmutableArray<string> addresses, CancellationToken cancellationToken)
{ {
if (application == null) if (application == null)
@ -1096,14 +853,8 @@ namespace OpenIddict.EntityFrameworkCore
return default; return default;
} }
/// <summary> /// <inheritdoc/>
/// Sets the requirements associated with an application. public virtual ValueTask SetRequirementsAsync(TApplication application, ImmutableArray<string> requirements, CancellationToken cancellationToken)
/// </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)
{ {
if (application == null) if (application == null)
{ {
@ -1126,13 +877,8 @@ namespace OpenIddict.EntityFrameworkCore
return default; return default;
} }
/// <summary> /// <inheritdoc/>
/// Updates an existing application. public virtual async ValueTask UpdateAsync(TApplication application, CancellationToken cancellationToken)
/// </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)
{ {
if (application == null) if (application == null)
{ {
@ -1166,7 +912,8 @@ namespace OpenIddict.EntityFrameworkCore
/// </summary> /// </summary>
/// <param name="identifier">The identifier to convert.</param> /// <param name="identifier">The identifier to convert.</param>
/// <returns>An instance of <typeparamref name="TKey"/> representing the provided identifier.</returns> /// <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)) if (string.IsNullOrEmpty(identifier))
{ {
@ -1181,7 +928,7 @@ namespace OpenIddict.EntityFrameworkCore
/// </summary> /// </summary>
/// <param name="identifier">The identifier to convert.</param> /// <param name="identifier">The identifier to convert.</param>
/// <returns>A <see cref="string"/> representation of the provided identifier.</returns> /// <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))) if (Equals(identifier, default(TKey)))
{ {

409
src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictEntityFrameworkCoreAuthorizationStore.cs

@ -9,13 +9,13 @@ using System.Collections.Generic;
using System.Collections.Immutable; using System.Collections.Immutable;
using System.ComponentModel; using System.ComponentModel;
using System.Data; using System.Data;
using System.Diagnostics.CodeAnalysis;
using System.Linq; using System.Linq;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Text.Encodings.Web; using System.Text.Encodings.Web;
using System.Text.Json; using System.Text.Json;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using JetBrains.Annotations;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Storage; using Microsoft.EntityFrameworkCore.Storage;
@ -38,9 +38,9 @@ namespace OpenIddict.EntityFrameworkCore
where TContext : DbContext where TContext : DbContext
{ {
public OpenIddictEntityFrameworkCoreAuthorizationStore( public OpenIddictEntityFrameworkCoreAuthorizationStore(
[NotNull] IMemoryCache cache, IMemoryCache cache,
[NotNull] TContext context, TContext context,
[NotNull] IOptionsMonitor<OpenIddictEntityFrameworkCoreOptions> options) IOptionsMonitor<OpenIddictEntityFrameworkCoreOptions> options)
: base(cache, context, options) : base(cache, context, options)
{ {
} }
@ -59,9 +59,9 @@ namespace OpenIddict.EntityFrameworkCore
where TKey : IEquatable<TKey> where TKey : IEquatable<TKey>
{ {
public OpenIddictEntityFrameworkCoreAuthorizationStore( public OpenIddictEntityFrameworkCoreAuthorizationStore(
[NotNull] IMemoryCache cache, IMemoryCache cache,
[NotNull] TContext context, TContext context,
[NotNull] IOptionsMonitor<OpenIddictEntityFrameworkCoreOptions> options) IOptionsMonitor<OpenIddictEntityFrameworkCoreOptions> options)
: base(cache, context, options) : base(cache, context, options)
{ {
} }
@ -83,9 +83,9 @@ namespace OpenIddict.EntityFrameworkCore
where TKey : IEquatable<TKey> where TKey : IEquatable<TKey>
{ {
public OpenIddictEntityFrameworkCoreAuthorizationStore( public OpenIddictEntityFrameworkCoreAuthorizationStore(
[NotNull] IMemoryCache cache, IMemoryCache cache,
[NotNull] TContext context, TContext context,
[NotNull] IOptionsMonitor<OpenIddictEntityFrameworkCoreOptions> options) IOptionsMonitor<OpenIddictEntityFrameworkCoreOptions> options)
{ {
Cache = cache; Cache = cache;
Context = context; Context = context;
@ -122,28 +122,12 @@ namespace OpenIddict.EntityFrameworkCore
/// </summary> /// </summary>
private DbSet<TToken> Tokens => Context.Set<TToken>(); private DbSet<TToken> Tokens => Context.Set<TToken>();
/// <summary> /// <inheritdoc/>
/// 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>
public virtual async ValueTask<long> CountAsync(CancellationToken cancellationToken) public virtual async ValueTask<long> CountAsync(CancellationToken cancellationToken)
=> await Authorizations.AsQueryable().LongCountAsync(cancellationToken); => await Authorizations.AsQueryable().LongCountAsync(cancellationToken);
/// <summary> /// <inheritdoc/>
/// Determines the number of authorizations that match the specified query. public virtual async ValueTask<long> CountAsync<TResult>(Func<IQueryable<TAuthorization>, IQueryable<TResult>> query, CancellationToken cancellationToken)
/// </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)
{ {
if (query == null) if (query == null)
{ {
@ -153,13 +137,8 @@ namespace OpenIddict.EntityFrameworkCore
return await query(Authorizations).LongCountAsync(cancellationToken); return await query(Authorizations).LongCountAsync(cancellationToken);
} }
/// <summary> /// <inheritdoc/>
/// Creates a new authorization. public virtual async ValueTask CreateAsync(TAuthorization authorization, CancellationToken cancellationToken)
/// </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)
{ {
if (authorization == null) if (authorization == null)
{ {
@ -171,20 +150,15 @@ namespace OpenIddict.EntityFrameworkCore
await Context.SaveChangesAsync(cancellationToken); await Context.SaveChangesAsync(cancellationToken);
} }
/// <summary> /// <inheritdoc/>
/// Removes an existing authorization. public virtual async ValueTask DeleteAsync(TAuthorization authorization, CancellationToken cancellationToken)
/// </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)
{ {
if (authorization == null) if (authorization == null)
{ {
throw new ArgumentNullException(nameof(authorization)); throw new ArgumentNullException(nameof(authorization));
} }
async ValueTask<IDbContextTransaction> CreateTransactionAsync() async ValueTask<IDbContextTransaction?> CreateTransactionAsync()
{ {
// Note: transactions that specify an explicit isolation level are only supported by // Note: transactions that specify an explicit isolation level are only supported by
// relational providers and trying to use them with a different provider results in // relational providers and trying to use them with a different provider results in
@ -214,8 +188,8 @@ namespace OpenIddict.EntityFrameworkCore
Task<List<TToken>> ListTokensAsync() Task<List<TToken>> ListTokensAsync()
=> (from token in Tokens.AsTracking() => (from token in Tokens.AsTracking()
join element in Authorizations.AsTracking() on token.Authorization.Id equals element.Id join element in Authorizations.AsTracking() on token.Authorization!.Id equals element.Id
where element.Id.Equals(authorization.Id) where element.Id!.Equals(authorization.Id)
select token).ToListAsync(cancellationToken); select token).ToListAsync(cancellationToken);
// To prevent an SQL exception from being thrown if a new associated entity is // To prevent an SQL exception from being thrown if a new associated entity is
@ -252,16 +226,9 @@ namespace OpenIddict.EntityFrameworkCore
} }
} }
/// <summary> /// <inheritdoc/>
/// 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>
public virtual IAsyncEnumerable<TAuthorization> FindAsync( public virtual IAsyncEnumerable<TAuthorization> FindAsync(
[NotNull] string subject, [NotNull] string client, CancellationToken cancellationToken) string subject, string client, CancellationToken cancellationToken)
{ {
if (string.IsNullOrEmpty(subject)) if (string.IsNullOrEmpty(subject))
{ {
@ -282,22 +249,15 @@ namespace OpenIddict.EntityFrameworkCore
return (from authorization in Authorizations.Include(authorization => authorization.Application).AsTracking() return (from authorization in Authorizations.Include(authorization => authorization.Application).AsTracking()
where authorization.Subject == subject where authorization.Subject == subject
join application in Applications.AsTracking() on authorization.Application.Id equals application.Id join application in Applications.AsTracking() on authorization.Application!.Id equals application.Id
where application.Id.Equals(key) where application.Id!.Equals(key)
select authorization).AsAsyncEnumerable(); select authorization).AsAsyncEnumerable();
} }
/// <summary> /// <inheritdoc/>
/// 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>
public virtual IAsyncEnumerable<TAuthorization> FindAsync( public virtual IAsyncEnumerable<TAuthorization> FindAsync(
[NotNull] string subject, [NotNull] string client, string subject, string client,
[NotNull] string status, CancellationToken cancellationToken) string status, CancellationToken cancellationToken)
{ {
if (string.IsNullOrEmpty(subject)) if (string.IsNullOrEmpty(subject))
{ {
@ -323,23 +283,15 @@ namespace OpenIddict.EntityFrameworkCore
return (from authorization in Authorizations.Include(authorization => authorization.Application).AsTracking() return (from authorization in Authorizations.Include(authorization => authorization.Application).AsTracking()
where authorization.Subject == subject && authorization.Status == status where authorization.Subject == subject && authorization.Status == status
join application in Applications.AsTracking() on authorization.Application.Id equals application.Id join application in Applications.AsTracking() on authorization.Application!.Id equals application.Id
where application.Id.Equals(key) where application.Id!.Equals(key)
select authorization).AsAsyncEnumerable(); select authorization).AsAsyncEnumerable();
} }
/// <summary> /// <inheritdoc/>
/// 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>
public virtual IAsyncEnumerable<TAuthorization> FindAsync( public virtual IAsyncEnumerable<TAuthorization> FindAsync(
[NotNull] string subject, [NotNull] string client, string subject, string client,
[NotNull] string status, [NotNull] string type, CancellationToken cancellationToken) string status, string type, CancellationToken cancellationToken)
{ {
if (string.IsNullOrEmpty(subject)) if (string.IsNullOrEmpty(subject))
{ {
@ -372,24 +324,15 @@ namespace OpenIddict.EntityFrameworkCore
where authorization.Subject == subject && where authorization.Subject == subject &&
authorization.Status == status && authorization.Status == status &&
authorization.Type == type authorization.Type == type
join application in Applications.AsTracking() on authorization.Application.Id equals application.Id join application in Applications.AsTracking() on authorization.Application!.Id equals application.Id
where application.Id.Equals(key) where application.Id!.Equals(key)
select authorization).AsAsyncEnumerable(); select authorization).AsAsyncEnumerable();
} }
/// <summary> /// <inheritdoc/>
/// 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>
public virtual IAsyncEnumerable<TAuthorization> FindAsync( public virtual IAsyncEnumerable<TAuthorization> FindAsync(
[NotNull] string subject, [NotNull] string client, string subject, string client,
[NotNull] string status, [NotNull] string type, string status, string type,
ImmutableArray<string> scopes, CancellationToken cancellationToken) ImmutableArray<string> scopes, CancellationToken cancellationToken)
{ {
if (string.IsNullOrEmpty(subject)) if (string.IsNullOrEmpty(subject))
@ -427,8 +370,8 @@ namespace OpenIddict.EntityFrameworkCore
where authorization.Subject == subject && where authorization.Subject == subject &&
authorization.Status == status && authorization.Status == status &&
authorization.Type == type authorization.Type == type
join application in Applications.AsTracking() on authorization.Application.Id equals application.Id join application in Applications.AsTracking() on authorization.Application!.Id equals application.Id
where application.Id.Equals(key) where application.Id!.Equals(key)
select authorization).AsAsyncEnumerable(); select authorization).AsAsyncEnumerable();
await foreach (var authorization in authorizations) await foreach (var authorization in authorizations)
@ -441,14 +384,9 @@ namespace OpenIddict.EntityFrameworkCore
} }
} }
/// <summary> /// <inheritdoc/>
/// 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>
public virtual IAsyncEnumerable<TAuthorization> FindByApplicationIdAsync( public virtual IAsyncEnumerable<TAuthorization> FindByApplicationIdAsync(
[NotNull] string identifier, CancellationToken cancellationToken) string identifier, CancellationToken cancellationToken)
{ {
if (string.IsNullOrEmpty(identifier)) if (string.IsNullOrEmpty(identifier))
{ {
@ -463,18 +401,13 @@ namespace OpenIddict.EntityFrameworkCore
var key = ConvertIdentifierFromString(identifier); var key = ConvertIdentifierFromString(identifier);
return (from authorization in Authorizations.Include(authorization => authorization.Application).AsTracking() return (from authorization in Authorizations.Include(authorization => authorization.Application).AsTracking()
join application in Applications.AsTracking() on authorization.Application.Id equals application.Id join application in Applications.AsTracking() on authorization.Application!.Id equals application.Id
where application.Id.Equals(identifier) where application.Id!.Equals(identifier)
select authorization).AsAsyncEnumerable(); select authorization).AsAsyncEnumerable();
} }
/// <summary> /// <inheritdoc/>
/// Retrieves an authorization using its unique identifier. public virtual async ValueTask<TAuthorization?> FindByIdAsync(string identifier, CancellationToken cancellationToken)
/// </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>The authorization corresponding to the identifier.</returns>
public virtual async ValueTask<TAuthorization> FindByIdAsync([NotNull] string identifier, CancellationToken cancellationToken)
{ {
if (string.IsNullOrEmpty(identifier)) if (string.IsNullOrEmpty(identifier))
{ {
@ -484,18 +417,13 @@ namespace OpenIddict.EntityFrameworkCore
var key = ConvertIdentifierFromString(identifier); var key = ConvertIdentifierFromString(identifier);
return await (from authorization in Authorizations.Include(authorization => authorization.Application).AsTracking() return await (from authorization in Authorizations.Include(authorization => authorization.Application).AsTracking()
where authorization.Id.Equals(key) where authorization.Id!.Equals(key)
select authorization).FirstOrDefaultAsync(cancellationToken); select authorization).FirstOrDefaultAsync(cancellationToken);
} }
/// <summary> /// <inheritdoc/>
/// Retrieves the subject associated with an authorization.
/// </summary>
/// <param name="subject">The subject associated with the authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>The authorizations corresponding to the specified subject.</returns>
public virtual IAsyncEnumerable<TAuthorization> FindBySubjectAsync( public virtual IAsyncEnumerable<TAuthorization> FindBySubjectAsync(
[NotNull] string subject, CancellationToken cancellationToken) string subject, CancellationToken cancellationToken)
{ {
if (string.IsNullOrEmpty(subject)) if (string.IsNullOrEmpty(subject))
{ {
@ -507,16 +435,8 @@ namespace OpenIddict.EntityFrameworkCore
select authorization).AsAsyncEnumerable(); select authorization).AsAsyncEnumerable();
} }
/// <summary> /// <inheritdoc/>
/// Retrieves the optional application identifier associated with an authorization. public virtual async ValueTask<string?> GetApplicationIdAsync(TAuthorization authorization, CancellationToken cancellationToken)
/// </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)
{ {
if (authorization == null) if (authorization == null)
{ {
@ -543,21 +463,10 @@ namespace OpenIddict.EntityFrameworkCore
return ConvertIdentifierToString(authorization.Application.Id); return ConvertIdentifierToString(authorization.Application.Id);
} }
/// <summary> /// <inheritdoc/>
/// 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>
public virtual async ValueTask<TResult> GetAsync<TState, TResult>( public virtual async ValueTask<TResult> GetAsync<TState, TResult>(
[NotNull] Func<IQueryable<TAuthorization>, TState, IQueryable<TResult>> query, Func<IQueryable<TAuthorization>, TState, IQueryable<TResult>> query,
[CanBeNull] TState state, CancellationToken cancellationToken) TState state, CancellationToken cancellationToken)
{ {
if (query == null) if (query == null)
{ {
@ -569,35 +478,19 @@ namespace OpenIddict.EntityFrameworkCore
.AsTracking(), state).FirstOrDefaultAsync(cancellationToken); .AsTracking(), state).FirstOrDefaultAsync(cancellationToken);
} }
/// <summary> /// <inheritdoc/>
/// Retrieves the unique identifier associated with an authorization. public virtual ValueTask<string?> GetIdAsync(TAuthorization authorization, CancellationToken cancellationToken)
/// </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)
{ {
if (authorization == null) if (authorization == null)
{ {
throw new ArgumentNullException(nameof(authorization)); throw new ArgumentNullException(nameof(authorization));
} }
return new ValueTask<string>(ConvertIdentifierToString(authorization.Id)); return new ValueTask<string?>(ConvertIdentifierToString(authorization.Id));
} }
/// <summary> /// <inheritdoc/>
/// Retrieves the additional properties associated with an authorization. public virtual ValueTask<ImmutableDictionary<string, JsonElement>> GetPropertiesAsync(TAuthorization authorization, CancellationToken cancellationToken)
/// </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)
{ {
if (authorization == null) if (authorization == null)
{ {
@ -623,16 +516,8 @@ namespace OpenIddict.EntityFrameworkCore
return new ValueTask<ImmutableDictionary<string, JsonElement>>(properties); return new ValueTask<ImmutableDictionary<string, JsonElement>>(properties);
} }
/// <summary> /// <inheritdoc/>
/// Retrieves the scopes associated with an authorization. public virtual ValueTask<ImmutableArray<string>> GetScopesAsync(TAuthorization authorization, CancellationToken cancellationToken)
/// </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)
{ {
if (authorization == null) if (authorization == null)
{ {
@ -658,71 +543,40 @@ namespace OpenIddict.EntityFrameworkCore
return new ValueTask<ImmutableArray<string>>(scopes); return new ValueTask<ImmutableArray<string>>(scopes);
} }
/// <summary> /// <inheritdoc/>
/// Retrieves the status associated with an authorization. public virtual ValueTask<string?> GetStatusAsync(TAuthorization authorization, CancellationToken cancellationToken)
/// </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)
{ {
if (authorization == null) if (authorization == null)
{ {
throw new ArgumentNullException(nameof(authorization)); throw new ArgumentNullException(nameof(authorization));
} }
return new ValueTask<string>(authorization.Status); return new ValueTask<string?>(authorization.Status);
} }
/// <summary> /// <inheritdoc/>
/// Retrieves the subject associated with an authorization. public virtual ValueTask<string?> GetSubjectAsync(TAuthorization authorization, CancellationToken cancellationToken)
/// </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)
{ {
if (authorization == null) if (authorization == null)
{ {
throw new ArgumentNullException(nameof(authorization)); throw new ArgumentNullException(nameof(authorization));
} }
return new ValueTask<string>(authorization.Subject); return new ValueTask<string?>(authorization.Subject);
} }
/// <summary> /// <inheritdoc/>
/// Retrieves the type associated with an authorization. public virtual ValueTask<string?> GetTypeAsync(TAuthorization authorization, CancellationToken cancellationToken)
/// </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)
{ {
if (authorization == null) if (authorization == null)
{ {
throw new ArgumentNullException(nameof(authorization)); throw new ArgumentNullException(nameof(authorization));
} }
return new ValueTask<string>(authorization.Type); return new ValueTask<string?>(authorization.Type);
} }
/// <summary> /// <inheritdoc/>
/// 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>
public virtual ValueTask<TAuthorization> InstantiateAsync(CancellationToken cancellationToken) public virtual ValueTask<TAuthorization> InstantiateAsync(CancellationToken cancellationToken)
{ {
try try
@ -737,18 +591,11 @@ namespace OpenIddict.EntityFrameworkCore
} }
} }
/// <summary> /// <inheritdoc/>
/// Executes the specified query and returns all the corresponding elements. public virtual IAsyncEnumerable<TAuthorization> ListAsync(int? count, int? offset, CancellationToken cancellationToken)
/// </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)
{ {
var query = Authorizations.Include(authorization => authorization.Application) var query = Authorizations.Include(authorization => authorization.Application)
.OrderBy(authorization => authorization.Id) .OrderBy(authorization => authorization.Id!)
.AsTracking(); .AsTracking();
if (offset.HasValue) if (offset.HasValue)
@ -764,18 +611,10 @@ namespace OpenIddict.EntityFrameworkCore
return query.AsAsyncEnumerable(); return query.AsAsyncEnumerable();
} }
/// <summary> /// <inheritdoc/>
/// 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>
public virtual IAsyncEnumerable<TResult> ListAsync<TState, TResult>( public virtual IAsyncEnumerable<TResult> ListAsync<TState, TResult>(
[NotNull] Func<IQueryable<TAuthorization>, TState, IQueryable<TResult>> query, Func<IQueryable<TAuthorization>, TState, IQueryable<TResult>> query,
[CanBeNull] TState state, CancellationToken cancellationToken) TState state, CancellationToken cancellationToken)
{ {
if (query == null) if (query == null)
{ {
@ -787,20 +626,16 @@ namespace OpenIddict.EntityFrameworkCore
.AsTracking(), state).AsAsyncEnumerable(); .AsTracking(), state).AsAsyncEnumerable();
} }
/// <summary> /// <inheritdoc/>
/// 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>
public virtual async ValueTask PruneAsync(CancellationToken cancellationToken) public virtual async ValueTask PruneAsync(CancellationToken cancellationToken)
{ {
// Note: Entity Framework Core doesn't support set-based deletes, which prevents removing // Note: Entity Framework Core doesn't support set-based deletes, which prevents removing
// entities in a single command without having to retrieve and materialize them first. // 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. // To work around this limitation, entities are manually listed and deleted using a batch logic.
List<Exception> exceptions = null; List<Exception>? exceptions = null;
async ValueTask<IDbContextTransaction> CreateTransactionAsync() async ValueTask<IDbContextTransaction?> CreateTransactionAsync()
{ {
// Note: transactions that specify an explicit isolation level are only supported by // Note: transactions that specify an explicit isolation level are only supported by
// relational providers and trying to use them with a different provider results in // relational providers and trying to use them with a different provider results in
@ -880,15 +715,9 @@ namespace OpenIddict.EntityFrameworkCore
} }
} }
/// <summary> /// <inheritdoc/>
/// Sets the application identifier associated with an authorization. public virtual async ValueTask SetApplicationIdAsync(TAuthorization authorization,
/// </summary> string? identifier, CancellationToken cancellationToken)
/// <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)
{ {
if (authorization == null) if (authorization == null)
{ {
@ -902,7 +731,7 @@ namespace OpenIddict.EntityFrameworkCore
// Warning: FindAsync() is deliberately not used to work around a breaking change introduced // Warning: FindAsync() is deliberately not used to work around a breaking change introduced
// in Entity Framework Core 3.x (where a ValueTask instead of a Task is now returned). // in Entity Framework Core 3.x (where a ValueTask instead of a Task is now returned).
var application = await Applications.AsQueryable() var application = await Applications.AsQueryable()
.FirstOrDefaultAsync(application => application.Id.Equals(key), cancellationToken); .FirstOrDefaultAsync(application => application.Id!.Equals(key), cancellationToken);
if (application == null) if (application == null)
{ {
@ -930,15 +759,9 @@ namespace OpenIddict.EntityFrameworkCore
} }
} }
/// <summary> /// <inheritdoc/>
/// Sets the additional properties associated with an authorization. public virtual ValueTask SetPropertiesAsync(TAuthorization authorization,
/// </summary> ImmutableDictionary<string, JsonElement> properties, CancellationToken cancellationToken)
/// <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)
{ {
if (authorization == null) if (authorization == null)
{ {
@ -961,14 +784,8 @@ namespace OpenIddict.EntityFrameworkCore
return default; return default;
} }
/// <summary> /// <inheritdoc/>
/// Sets the scopes associated with an authorization. public virtual ValueTask SetScopesAsync(TAuthorization 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,
ImmutableArray<string> scopes, CancellationToken cancellationToken) ImmutableArray<string> scopes, CancellationToken cancellationToken)
{ {
if (authorization == null) if (authorization == null)
@ -992,15 +809,9 @@ namespace OpenIddict.EntityFrameworkCore
return default; return default;
} }
/// <summary> /// <inheritdoc/>
/// Sets the status associated with an authorization. public virtual ValueTask SetStatusAsync(TAuthorization authorization,
/// </summary> string? status, CancellationToken cancellationToken)
/// <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)
{ {
if (authorization == null) if (authorization == null)
{ {
@ -1012,15 +823,9 @@ namespace OpenIddict.EntityFrameworkCore
return default; return default;
} }
/// <summary> /// <inheritdoc/>
/// Sets the subject associated with an authorization. public virtual ValueTask SetSubjectAsync(TAuthorization authorization,
/// </summary> string? subject, CancellationToken cancellationToken)
/// <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)
{ {
if (authorization == null) if (authorization == null)
{ {
@ -1032,15 +837,9 @@ namespace OpenIddict.EntityFrameworkCore
return default; return default;
} }
/// <summary> /// <inheritdoc/>
/// Sets the type associated with an authorization. public virtual ValueTask SetTypeAsync(TAuthorization authorization,
/// </summary> string? type, CancellationToken cancellationToken)
/// <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)
{ {
if (authorization == null) if (authorization == null)
{ {
@ -1052,13 +851,8 @@ namespace OpenIddict.EntityFrameworkCore
return default; return default;
} }
/// <summary> /// <inheritdoc/>
/// Updates an existing authorization. public virtual async ValueTask UpdateAsync(TAuthorization authorization, CancellationToken cancellationToken)
/// </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)
{ {
if (authorization == null) if (authorization == null)
{ {
@ -1092,7 +886,8 @@ namespace OpenIddict.EntityFrameworkCore
/// </summary> /// </summary>
/// <param name="identifier">The identifier to convert.</param> /// <param name="identifier">The identifier to convert.</param>
/// <returns>An instance of <typeparamref name="TKey"/> representing the provided identifier.</returns> /// <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)) if (string.IsNullOrEmpty(identifier))
{ {
@ -1107,7 +902,7 @@ namespace OpenIddict.EntityFrameworkCore
/// </summary> /// </summary>
/// <param name="identifier">The identifier to convert.</param> /// <param name="identifier">The identifier to convert.</param>
/// <returns>A <see cref="string"/> representation of the provided identifier.</returns> /// <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))) if (Equals(identifier, default(TKey)))
{ {

351
src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictEntityFrameworkCoreScopeStore.cs

@ -8,6 +8,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Immutable; using System.Collections.Immutable;
using System.ComponentModel; using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using System.Globalization; using System.Globalization;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
@ -17,7 +18,6 @@ using System.Text.Encodings.Web;
using System.Text.Json; using System.Text.Json;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using JetBrains.Annotations;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
@ -35,9 +35,9 @@ namespace OpenIddict.EntityFrameworkCore
where TContext : DbContext where TContext : DbContext
{ {
public OpenIddictEntityFrameworkCoreScopeStore( public OpenIddictEntityFrameworkCoreScopeStore(
[NotNull] IMemoryCache cache, IMemoryCache cache,
[NotNull] TContext context, TContext context,
[NotNull] IOptionsMonitor<OpenIddictEntityFrameworkCoreOptions> options) IOptionsMonitor<OpenIddictEntityFrameworkCoreOptions> options)
: base(cache, context, options) : base(cache, context, options)
{ {
} }
@ -53,9 +53,9 @@ namespace OpenIddict.EntityFrameworkCore
where TKey : IEquatable<TKey> where TKey : IEquatable<TKey>
{ {
public OpenIddictEntityFrameworkCoreScopeStore( public OpenIddictEntityFrameworkCoreScopeStore(
[NotNull] IMemoryCache cache, IMemoryCache cache,
[NotNull] TContext context, TContext context,
[NotNull] IOptionsMonitor<OpenIddictEntityFrameworkCoreOptions> options) IOptionsMonitor<OpenIddictEntityFrameworkCoreOptions> options)
: base(cache, context, options) : base(cache, context, options)
{ {
} }
@ -73,9 +73,9 @@ namespace OpenIddict.EntityFrameworkCore
where TKey : IEquatable<TKey> where TKey : IEquatable<TKey>
{ {
public OpenIddictEntityFrameworkCoreScopeStore( public OpenIddictEntityFrameworkCoreScopeStore(
[NotNull] IMemoryCache cache, IMemoryCache cache,
[NotNull] TContext context, TContext context,
[NotNull] IOptionsMonitor<OpenIddictEntityFrameworkCoreOptions> options) IOptionsMonitor<OpenIddictEntityFrameworkCoreOptions> options)
{ {
Cache = cache; Cache = cache;
Context = context; Context = context;
@ -102,28 +102,12 @@ namespace OpenIddict.EntityFrameworkCore
/// </summary> /// </summary>
private DbSet<TScope> Scopes => Context.Set<TScope>(); private DbSet<TScope> Scopes => Context.Set<TScope>();
/// <summary> /// <inheritdoc/>
/// 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>
public virtual async ValueTask<long> CountAsync(CancellationToken cancellationToken) public virtual async ValueTask<long> CountAsync(CancellationToken cancellationToken)
=> await Scopes.AsQueryable().LongCountAsync(cancellationToken); => await Scopes.AsQueryable().LongCountAsync(cancellationToken);
/// <summary> /// <inheritdoc/>
/// Determines the number of scopes that match the specified query. public virtual async ValueTask<long> CountAsync<TResult>(Func<IQueryable<TScope>, IQueryable<TResult>> query, CancellationToken cancellationToken)
/// </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)
{ {
if (query == null) if (query == null)
{ {
@ -133,13 +117,8 @@ namespace OpenIddict.EntityFrameworkCore
return await query(Scopes).LongCountAsync(cancellationToken); return await query(Scopes).LongCountAsync(cancellationToken);
} }
/// <summary> /// <inheritdoc/>
/// Creates a new scope. public virtual async ValueTask CreateAsync(TScope scope, CancellationToken cancellationToken)
/// </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)
{ {
if (scope == null) if (scope == null)
{ {
@ -151,13 +130,8 @@ namespace OpenIddict.EntityFrameworkCore
await Context.SaveChangesAsync(cancellationToken); await Context.SaveChangesAsync(cancellationToken);
} }
/// <summary> /// <inheritdoc/>
/// Removes an existing scope. public virtual async ValueTask DeleteAsync(TScope scope, CancellationToken cancellationToken)
/// </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)
{ {
if (scope == null) if (scope == null)
{ {
@ -180,16 +154,8 @@ namespace OpenIddict.EntityFrameworkCore
} }
} }
/// <summary> /// <inheritdoc/>
/// Retrieves a scope using its unique identifier. public virtual async ValueTask<TScope?> FindByIdAsync(string identifier, CancellationToken cancellationToken)
/// </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)
{ {
if (string.IsNullOrEmpty(identifier)) if (string.IsNullOrEmpty(identifier))
{ {
@ -199,20 +165,12 @@ namespace OpenIddict.EntityFrameworkCore
var key = ConvertIdentifierFromString(identifier); var key = ConvertIdentifierFromString(identifier);
return await (from scope in Scopes.AsTracking() return await (from scope in Scopes.AsTracking()
where scope.Id.Equals(key) where scope.Id!.Equals(key)
select scope).FirstOrDefaultAsync(cancellationToken); select scope).FirstOrDefaultAsync(cancellationToken);
} }
/// <summary> /// <inheritdoc/>
/// Retrieves a scope using its name. public virtual async ValueTask<TScope?> FindByNameAsync(string name, CancellationToken cancellationToken)
/// </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)
{ {
if (string.IsNullOrEmpty(name)) if (string.IsNullOrEmpty(name))
{ {
@ -224,12 +182,7 @@ namespace OpenIddict.EntityFrameworkCore
select scope).FirstOrDefaultAsync(cancellationToken); select scope).FirstOrDefaultAsync(cancellationToken);
} }
/// <summary> /// <inheritdoc/>
/// 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>
public virtual IAsyncEnumerable<TScope> FindByNamesAsync( public virtual IAsyncEnumerable<TScope> FindByNamesAsync(
ImmutableArray<string> names, CancellationToken cancellationToken) ImmutableArray<string> names, CancellationToken cancellationToken)
{ {
@ -245,14 +198,9 @@ namespace OpenIddict.EntityFrameworkCore
select scope).AsAsyncEnumerable(); select scope).AsAsyncEnumerable();
} }
/// <summary> /// <inheritdoc/>
/// 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>
public virtual IAsyncEnumerable<TScope> FindByResourceAsync( public virtual IAsyncEnumerable<TScope> FindByResourceAsync(
[NotNull] string resource, CancellationToken cancellationToken) string resource, CancellationToken cancellationToken)
{ {
if (string.IsNullOrEmpty(resource)) if (string.IsNullOrEmpty(resource))
{ {
@ -270,7 +218,7 @@ namespace OpenIddict.EntityFrameworkCore
async IAsyncEnumerable<TScope> ExecuteAsync([EnumeratorCancellation] CancellationToken cancellationToken) async IAsyncEnumerable<TScope> ExecuteAsync([EnumeratorCancellation] CancellationToken cancellationToken)
{ {
var scopes = (from scope in Scopes.AsTracking() var scopes = (from scope in Scopes.AsTracking()
where scope.Resources.Contains(resource) where scope.Resources!.Contains(resource)
select scope).AsAsyncEnumerable(); select scope).AsAsyncEnumerable();
await foreach (var scope in scopes) await foreach (var scope in scopes)
@ -284,21 +232,10 @@ namespace OpenIddict.EntityFrameworkCore
} }
} }
/// <summary> /// <inheritdoc/>
/// 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>
public virtual async ValueTask<TResult> GetAsync<TState, TResult>( public virtual async ValueTask<TResult> GetAsync<TState, TResult>(
[NotNull] Func<IQueryable<TScope>, TState, IQueryable<TResult>> query, Func<IQueryable<TScope>, TState, IQueryable<TResult>> query,
[CanBeNull] TState state, CancellationToken cancellationToken) TState state, CancellationToken cancellationToken)
{ {
if (query == null) if (query == null)
{ {
@ -308,35 +245,19 @@ namespace OpenIddict.EntityFrameworkCore
return await query(Scopes.AsTracking(), state).FirstOrDefaultAsync(cancellationToken); return await query(Scopes.AsTracking(), state).FirstOrDefaultAsync(cancellationToken);
} }
/// <summary> /// <inheritdoc/>
/// Retrieves the description associated with a scope. public virtual ValueTask<string?> GetDescriptionAsync(TScope scope, CancellationToken cancellationToken)
/// </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)
{ {
if (scope == null) if (scope == null)
{ {
throw new ArgumentNullException(nameof(scope)); throw new ArgumentNullException(nameof(scope));
} }
return new ValueTask<string>(scope.Description); return new ValueTask<string?>(scope.Description);
} }
/// <summary> /// <inheritdoc/>
/// Retrieves the localized descriptions associated with a scope. public virtual ValueTask<ImmutableDictionary<CultureInfo, string>> GetDescriptionsAsync(TScope scope, CancellationToken cancellationToken)
/// </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)
{ {
if (scope == null) if (scope == null)
{ {
@ -363,35 +284,19 @@ namespace OpenIddict.EntityFrameworkCore
return new ValueTask<ImmutableDictionary<CultureInfo, string>>(descriptions); return new ValueTask<ImmutableDictionary<CultureInfo, string>>(descriptions);
} }
/// <summary> /// <inheritdoc/>
/// Retrieves the display name associated with a scope. public virtual ValueTask<string?> GetDisplayNameAsync(TScope scope, CancellationToken cancellationToken)
/// </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)
{ {
if (scope == null) if (scope == null)
{ {
throw new ArgumentNullException(nameof(scope)); throw new ArgumentNullException(nameof(scope));
} }
return new ValueTask<string>(scope.DisplayName); return new ValueTask<string?>(scope.DisplayName);
} }
/// <summary> /// <inheritdoc/>
/// Retrieves the localized display names associated with a scope. public virtual ValueTask<ImmutableDictionary<CultureInfo, string>> GetDisplayNamesAsync(TScope scope, CancellationToken cancellationToken)
/// </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)
{ {
if (scope == null) if (scope == null)
{ {
@ -418,54 +323,30 @@ namespace OpenIddict.EntityFrameworkCore
return new ValueTask<ImmutableDictionary<CultureInfo, string>>(names); return new ValueTask<ImmutableDictionary<CultureInfo, string>>(names);
} }
/// <summary> /// <inheritdoc/>
/// Retrieves the unique identifier associated with a scope. public virtual ValueTask<string?> GetIdAsync(TScope scope, CancellationToken cancellationToken)
/// </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)
{ {
if (scope == null) if (scope == null)
{ {
throw new ArgumentNullException(nameof(scope)); throw new ArgumentNullException(nameof(scope));
} }
return new ValueTask<string>(ConvertIdentifierToString(scope.Id)); return new ValueTask<string?>(ConvertIdentifierToString(scope.Id));
} }
/// <summary> /// <inheritdoc/>
/// Retrieves the name associated with a scope. public virtual ValueTask<string?> GetNameAsync(TScope scope, CancellationToken cancellationToken)
/// </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)
{ {
if (scope == null) if (scope == null)
{ {
throw new ArgumentNullException(nameof(scope)); throw new ArgumentNullException(nameof(scope));
} }
return new ValueTask<string>(scope.Name); return new ValueTask<string?>(scope.Name);
} }
/// <summary> /// <inheritdoc/>
/// Retrieves the additional properties associated with a scope. public virtual ValueTask<ImmutableDictionary<string, JsonElement>> GetPropertiesAsync(TScope scope, CancellationToken cancellationToken)
/// </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)
{ {
if (scope == null) if (scope == null)
{ {
@ -491,16 +372,8 @@ namespace OpenIddict.EntityFrameworkCore
return new ValueTask<ImmutableDictionary<string, JsonElement>>(properties); return new ValueTask<ImmutableDictionary<string, JsonElement>>(properties);
} }
/// <summary> /// <inheritdoc/>
/// Retrieves the resources associated with a scope. public virtual ValueTask<ImmutableArray<string>> GetResourcesAsync(TScope scope, CancellationToken cancellationToken)
/// </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)
{ {
if (scope == null) if (scope == null)
{ {
@ -526,14 +399,7 @@ namespace OpenIddict.EntityFrameworkCore
return new ValueTask<ImmutableArray<string>>(resources); return new ValueTask<ImmutableArray<string>>(resources);
} }
/// <summary> /// <inheritdoc/>
/// 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>
public virtual ValueTask<TScope> InstantiateAsync(CancellationToken cancellationToken) public virtual ValueTask<TScope> InstantiateAsync(CancellationToken cancellationToken)
{ {
try try
@ -548,17 +414,10 @@ namespace OpenIddict.EntityFrameworkCore
} }
} }
/// <summary> /// <inheritdoc/>
/// Executes the specified query and returns all the corresponding elements. public virtual IAsyncEnumerable<TScope> ListAsync(int? count, int? offset, CancellationToken cancellationToken)
/// </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)
{ {
var query = Scopes.AsQueryable().OrderBy(scope => scope.Id).AsTracking(); var query = Scopes.AsQueryable().OrderBy(scope => scope.Id!).AsTracking();
if (offset.HasValue) if (offset.HasValue)
{ {
@ -573,18 +432,10 @@ namespace OpenIddict.EntityFrameworkCore
return query.AsAsyncEnumerable(); return query.AsAsyncEnumerable();
} }
/// <summary> /// <inheritdoc/>
/// 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>
public virtual IAsyncEnumerable<TResult> ListAsync<TState, TResult>( public virtual IAsyncEnumerable<TResult> ListAsync<TState, TResult>(
[NotNull] Func<IQueryable<TScope>, TState, IQueryable<TResult>> query, Func<IQueryable<TScope>, TState, IQueryable<TResult>> query,
[CanBeNull] TState state, CancellationToken cancellationToken) TState state, CancellationToken cancellationToken)
{ {
if (query == null) if (query == null)
{ {
@ -594,14 +445,8 @@ namespace OpenIddict.EntityFrameworkCore
return query(Scopes.AsTracking(), state).AsAsyncEnumerable(); return query(Scopes.AsTracking(), state).AsAsyncEnumerable();
} }
/// <summary> /// <inheritdoc/>
/// Sets the description associated with a scope. public virtual ValueTask SetDescriptionAsync(TScope scope, string? description, CancellationToken cancellationToken)
/// </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)
{ {
if (scope == null) if (scope == null)
{ {
@ -613,15 +458,9 @@ namespace OpenIddict.EntityFrameworkCore
return default; return default;
} }
/// <summary> /// <inheritdoc/>
/// Sets the localized descriptions associated with a scope. public virtual ValueTask SetDescriptionsAsync(TScope scope,
/// </summary> ImmutableDictionary<CultureInfo, string> descriptions, CancellationToken cancellationToken)
/// <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)
{ {
if (scope == null) if (scope == null)
{ {
@ -658,14 +497,8 @@ namespace OpenIddict.EntityFrameworkCore
return default; return default;
} }
/// <summary> /// <inheritdoc/>
/// Sets the display name associated with a scope. public virtual ValueTask SetDisplayNameAsync(TScope scope, string? name, CancellationToken cancellationToken)
/// </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)
{ {
if (scope == null) if (scope == null)
{ {
@ -677,15 +510,9 @@ namespace OpenIddict.EntityFrameworkCore
return default; return default;
} }
/// <summary> /// <inheritdoc/>
/// Sets the localized display names associated with a scope. public virtual ValueTask SetDisplayNamesAsync(TScope scope,
/// </summary> ImmutableDictionary<CultureInfo, string> names, CancellationToken cancellationToken)
/// <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)
{ {
if (scope == null) if (scope == null)
{ {
@ -722,14 +549,8 @@ namespace OpenIddict.EntityFrameworkCore
return default; return default;
} }
/// <summary> /// <inheritdoc/>
/// Sets the name associated with a scope. public virtual ValueTask SetNameAsync(TScope scope, string? name, CancellationToken cancellationToken)
/// </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)
{ {
if (scope == null) if (scope == null)
{ {
@ -741,15 +562,9 @@ namespace OpenIddict.EntityFrameworkCore
return default; return default;
} }
/// <summary> /// <inheritdoc/>
/// Sets the additional properties associated with a scope. public virtual ValueTask SetPropertiesAsync(TScope scope,
/// </summary> ImmutableDictionary<string, JsonElement> properties, CancellationToken cancellationToken)
/// <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)
{ {
if (scope == null) if (scope == null)
{ {
@ -772,14 +587,8 @@ namespace OpenIddict.EntityFrameworkCore
return default; return default;
} }
/// <summary> /// <inheritdoc/>
/// Sets the resources associated with a scope. public virtual ValueTask SetResourcesAsync(TScope scope, ImmutableArray<string> resources, CancellationToken cancellationToken)
/// </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)
{ {
if (scope == null) if (scope == null)
{ {
@ -802,13 +611,8 @@ namespace OpenIddict.EntityFrameworkCore
return default; return default;
} }
/// <summary> /// <inheritdoc/>
/// Updates an existing scope. public virtual async ValueTask UpdateAsync(TScope scope, CancellationToken cancellationToken)
/// </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)
{ {
if (scope == null) if (scope == null)
{ {
@ -842,7 +646,8 @@ namespace OpenIddict.EntityFrameworkCore
/// </summary> /// </summary>
/// <param name="identifier">The identifier to convert.</param> /// <param name="identifier">The identifier to convert.</param>
/// <returns>An instance of <typeparamref name="TKey"/> representing the provided identifier.</returns> /// <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)) if (string.IsNullOrEmpty(identifier))
{ {
@ -857,7 +662,7 @@ namespace OpenIddict.EntityFrameworkCore
/// </summary> /// </summary>
/// <param name="identifier">The identifier to convert.</param> /// <param name="identifier">The identifier to convert.</param>
/// <returns>A <see cref="string"/> representation of the provided identifier.</returns> /// <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))) if (Equals(identifier, default(TKey)))
{ {

530
src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictEntityFrameworkCoreTokenStore.cs

@ -9,12 +9,12 @@ using System.Collections.Generic;
using System.Collections.Immutable; using System.Collections.Immutable;
using System.ComponentModel; using System.ComponentModel;
using System.Data; using System.Data;
using System.Diagnostics.CodeAnalysis;
using System.Linq; using System.Linq;
using System.Text.Encodings.Web; using System.Text.Encodings.Web;
using System.Text.Json; using System.Text.Json;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using JetBrains.Annotations;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Storage; using Microsoft.EntityFrameworkCore.Storage;
@ -37,9 +37,9 @@ namespace OpenIddict.EntityFrameworkCore
where TContext : DbContext where TContext : DbContext
{ {
public OpenIddictEntityFrameworkCoreTokenStore( public OpenIddictEntityFrameworkCoreTokenStore(
[NotNull] IMemoryCache cache, IMemoryCache cache,
[NotNull] TContext context, TContext context,
[NotNull] IOptionsMonitor<OpenIddictEntityFrameworkCoreOptions> options) IOptionsMonitor<OpenIddictEntityFrameworkCoreOptions> options)
: base(cache, context, options) : base(cache, context, options)
{ {
} }
@ -58,9 +58,9 @@ namespace OpenIddict.EntityFrameworkCore
where TKey : IEquatable<TKey> where TKey : IEquatable<TKey>
{ {
public OpenIddictEntityFrameworkCoreTokenStore( public OpenIddictEntityFrameworkCoreTokenStore(
[NotNull] IMemoryCache cache, IMemoryCache cache,
[NotNull] TContext context, TContext context,
[NotNull] IOptionsMonitor<OpenIddictEntityFrameworkCoreOptions> options) IOptionsMonitor<OpenIddictEntityFrameworkCoreOptions> options)
: base(cache, context, options) : base(cache, context, options)
{ {
} }
@ -82,9 +82,9 @@ namespace OpenIddict.EntityFrameworkCore
where TKey : IEquatable<TKey> where TKey : IEquatable<TKey>
{ {
public OpenIddictEntityFrameworkCoreTokenStore( public OpenIddictEntityFrameworkCoreTokenStore(
[NotNull] IMemoryCache cache, IMemoryCache cache,
[NotNull] TContext context, TContext context,
[NotNull] IOptionsMonitor<OpenIddictEntityFrameworkCoreOptions> options) IOptionsMonitor<OpenIddictEntityFrameworkCoreOptions> options)
{ {
Cache = cache; Cache = cache;
Context = context; Context = context;
@ -121,28 +121,12 @@ namespace OpenIddict.EntityFrameworkCore
/// </summary> /// </summary>
private DbSet<TToken> Tokens => Context.Set<TToken>(); private DbSet<TToken> Tokens => Context.Set<TToken>();
/// <summary> /// <inheritdoc/>
/// 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>
public virtual async ValueTask<long> CountAsync(CancellationToken cancellationToken) public virtual async ValueTask<long> CountAsync(CancellationToken cancellationToken)
=> await Tokens.AsQueryable().LongCountAsync(cancellationToken); => await Tokens.AsQueryable().LongCountAsync(cancellationToken);
/// <summary> /// <inheritdoc/>
/// Determines the number of tokens that match the specified query. public virtual async ValueTask<long> CountAsync<TResult>(Func<IQueryable<TToken>, IQueryable<TResult>> query, CancellationToken cancellationToken)
/// </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)
{ {
if (query == null) if (query == null)
{ {
@ -152,13 +136,8 @@ namespace OpenIddict.EntityFrameworkCore
return await query(Tokens).LongCountAsync(cancellationToken); return await query(Tokens).LongCountAsync(cancellationToken);
} }
/// <summary> /// <inheritdoc/>
/// Creates a new token. public virtual async ValueTask CreateAsync(TToken token, CancellationToken cancellationToken)
/// </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)
{ {
if (token == null) if (token == null)
{ {
@ -170,13 +149,8 @@ namespace OpenIddict.EntityFrameworkCore
await Context.SaveChangesAsync(cancellationToken); await Context.SaveChangesAsync(cancellationToken);
} }
/// <summary> /// <inheritdoc/>
/// Removes a token. public virtual async ValueTask DeleteAsync(TToken token, CancellationToken cancellationToken)
/// </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)
{ {
if (token == null) if (token == null)
{ {
@ -199,16 +173,8 @@ namespace OpenIddict.EntityFrameworkCore
} }
} }
/// <summary> /// <inheritdoc/>
/// Retrieves the tokens corresponding to the specified public virtual IAsyncEnumerable<TToken> FindAsync(string subject, string client, CancellationToken cancellationToken)
/// 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)
{ {
if (string.IsNullOrEmpty(subject)) if (string.IsNullOrEmpty(subject))
{ {
@ -229,22 +195,15 @@ namespace OpenIddict.EntityFrameworkCore
return (from token in Tokens.Include(token => token.Application).Include(token => token.Authorization).AsTracking() return (from token in Tokens.Include(token => token.Application).Include(token => token.Authorization).AsTracking()
where token.Subject == subject where token.Subject == subject
join application in Applications.AsTracking() on token.Application.Id equals application.Id join application in Applications.AsTracking() on token.Application!.Id equals application.Id
where application.Id.Equals(key) where application.Id!.Equals(key)
select token).AsAsyncEnumerable(); select token).AsAsyncEnumerable();
} }
/// <summary> /// <inheritdoc/>
/// 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>
public virtual IAsyncEnumerable<TToken> FindAsync( public virtual IAsyncEnumerable<TToken> FindAsync(
[NotNull] string subject, [NotNull] string client, string subject, string client,
[NotNull] string status, CancellationToken cancellationToken) string status, CancellationToken cancellationToken)
{ {
if (string.IsNullOrEmpty(subject)) if (string.IsNullOrEmpty(subject))
{ {
@ -271,23 +230,15 @@ namespace OpenIddict.EntityFrameworkCore
return (from token in Tokens.Include(token => token.Application).Include(token => token.Authorization).AsTracking() return (from token in Tokens.Include(token => token.Application).Include(token => token.Authorization).AsTracking()
where token.Subject == subject && where token.Subject == subject &&
token.Status == status token.Status == status
join application in Applications.AsTracking() on token.Application.Id equals application.Id join application in Applications.AsTracking() on token.Application!.Id equals application.Id
where application.Id.Equals(key) where application.Id!.Equals(key)
select token).AsAsyncEnumerable(); select token).AsAsyncEnumerable();
} }
/// <summary> /// <inheritdoc/>
/// 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>
public virtual IAsyncEnumerable<TToken> FindAsync( public virtual IAsyncEnumerable<TToken> FindAsync(
[NotNull] string subject, [NotNull] string client, string subject, string client,
[NotNull] string status, [NotNull] string type, CancellationToken cancellationToken) string status, string type, CancellationToken cancellationToken)
{ {
if (string.IsNullOrEmpty(subject)) if (string.IsNullOrEmpty(subject))
{ {
@ -320,18 +271,13 @@ namespace OpenIddict.EntityFrameworkCore
where token.Subject == subject && where token.Subject == subject &&
token.Status == status && token.Status == status &&
token.Type == type token.Type == type
join application in Applications.AsTracking() on token.Application.Id equals application.Id join application in Applications.AsTracking() on token.Application!.Id equals application.Id
where application.Id.Equals(key) where application.Id!.Equals(key)
select token).AsAsyncEnumerable(); select token).AsAsyncEnumerable();
} }
/// <summary> /// <inheritdoc/>
/// Retrieves the list of tokens corresponding to the specified application identifier. public virtual IAsyncEnumerable<TToken> FindByApplicationIdAsync(string identifier, CancellationToken cancellationToken)
/// </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)
{ {
if (string.IsNullOrEmpty(identifier)) if (string.IsNullOrEmpty(identifier))
{ {
@ -346,18 +292,13 @@ namespace OpenIddict.EntityFrameworkCore
var key = ConvertIdentifierFromString(identifier); var key = ConvertIdentifierFromString(identifier);
return (from token in Tokens.Include(token => token.Application).Include(token => token.Authorization).AsTracking() return (from token in Tokens.Include(token => token.Application).Include(token => token.Authorization).AsTracking()
join application in Applications.AsTracking() on token.Application.Id equals application.Id join application in Applications.AsTracking() on token.Application!.Id equals application.Id
where application.Id.Equals(key) where application.Id!.Equals(key)
select token).AsAsyncEnumerable(); select token).AsAsyncEnumerable();
} }
/// <summary> /// <inheritdoc/>
/// Retrieves the list of tokens corresponding to the specified authorization identifier. public virtual IAsyncEnumerable<TToken> FindByAuthorizationIdAsync(string identifier, CancellationToken cancellationToken)
/// </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>The tokens corresponding to the specified authorization.</returns>
public virtual IAsyncEnumerable<TToken> FindByAuthorizationIdAsync([NotNull] string identifier, CancellationToken cancellationToken)
{ {
if (string.IsNullOrEmpty(identifier)) if (string.IsNullOrEmpty(identifier))
{ {
@ -372,21 +313,13 @@ namespace OpenIddict.EntityFrameworkCore
var key = ConvertIdentifierFromString(identifier); var key = ConvertIdentifierFromString(identifier);
return (from token in Tokens.Include(token => token.Application).Include(token => token.Authorization).AsTracking() return (from token in Tokens.Include(token => token.Application).Include(token => token.Authorization).AsTracking()
join authorization in Authorizations.AsTracking() on token.Authorization.Id equals authorization.Id join authorization in Authorizations.AsTracking() on token.Authorization!.Id equals authorization.Id
where authorization.Id.Equals(key) where authorization.Id!.Equals(key)
select token).AsAsyncEnumerable(); select token).AsAsyncEnumerable();
} }
/// <summary> /// <inheritdoc/>
/// Retrieves a token using its unique identifier. public virtual async ValueTask<TToken?> FindByIdAsync(string identifier, CancellationToken cancellationToken)
/// </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)
{ {
if (string.IsNullOrEmpty(identifier)) if (string.IsNullOrEmpty(identifier))
{ {
@ -396,21 +329,12 @@ namespace OpenIddict.EntityFrameworkCore
var key = ConvertIdentifierFromString(identifier); var key = ConvertIdentifierFromString(identifier);
return await (from token in Tokens.Include(token => token.Application).Include(token => token.Authorization).AsTracking() return await (from token in Tokens.Include(token => token.Application).Include(token => token.Authorization).AsTracking()
where token.Id.Equals(key) where token.Id!.Equals(key)
select token).FirstOrDefaultAsync(cancellationToken); select token).FirstOrDefaultAsync(cancellationToken);
} }
/// <summary> /// <inheritdoc/>
/// Retrieves the list of tokens corresponding to the specified reference identifier. public virtual async ValueTask<TToken?> FindByReferenceIdAsync(string identifier, CancellationToken cancellationToken)
/// 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)
{ {
if (string.IsNullOrEmpty(identifier)) if (string.IsNullOrEmpty(identifier))
{ {
@ -422,13 +346,8 @@ namespace OpenIddict.EntityFrameworkCore
select token).FirstOrDefaultAsync(cancellationToken); select token).FirstOrDefaultAsync(cancellationToken);
} }
/// <summary> /// <inheritdoc/>
/// Retrieves the list of tokens corresponding to the specified subject. public virtual IAsyncEnumerable<TToken> FindBySubjectAsync(string subject, CancellationToken cancellationToken)
/// </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)
{ {
if (string.IsNullOrEmpty(subject)) if (string.IsNullOrEmpty(subject))
{ {
@ -440,16 +359,8 @@ namespace OpenIddict.EntityFrameworkCore
select token).AsAsyncEnumerable(); select token).AsAsyncEnumerable();
} }
/// <summary> /// <inheritdoc/>
/// Retrieves the optional application identifier associated with a token. public virtual async ValueTask<string?> GetApplicationIdAsync(TToken token, CancellationToken cancellationToken)
/// </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)
{ {
if (token == null) if (token == null)
{ {
@ -476,21 +387,10 @@ namespace OpenIddict.EntityFrameworkCore
return ConvertIdentifierToString(token.Application.Id); return ConvertIdentifierToString(token.Application.Id);
} }
/// <summary> /// <inheritdoc/>
/// 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>
public virtual ValueTask<TResult> GetAsync<TState, TResult>( public virtual ValueTask<TResult> GetAsync<TState, TResult>(
[NotNull] Func<IQueryable<TToken>, TState, IQueryable<TResult>> query, Func<IQueryable<TToken>, TState, IQueryable<TResult>> query,
[CanBeNull] TState state, CancellationToken cancellationToken) TState state, CancellationToken cancellationToken)
{ {
if (query == null) if (query == null)
{ {
@ -503,16 +403,8 @@ namespace OpenIddict.EntityFrameworkCore
.AsTracking(), state).FirstOrDefaultAsync(cancellationToken)); .AsTracking(), state).FirstOrDefaultAsync(cancellationToken));
} }
/// <summary> /// <inheritdoc/>
/// Retrieves the optional authorization identifier associated with a token. public virtual async ValueTask<string?> GetAuthorizationIdAsync(TToken token, CancellationToken cancellationToken)
/// </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)
{ {
if (token == null) if (token == null)
{ {
@ -539,16 +431,8 @@ namespace OpenIddict.EntityFrameworkCore
return ConvertIdentifierToString(token.Authorization.Id); return ConvertIdentifierToString(token.Authorization.Id);
} }
/// <summary> /// <inheritdoc/>
/// Retrieves the creation date associated with a token. public virtual ValueTask<DateTimeOffset?> GetCreationDateAsync(TToken token, CancellationToken cancellationToken)
/// </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)
{ {
if (token == null) if (token == null)
{ {
@ -558,16 +442,8 @@ namespace OpenIddict.EntityFrameworkCore
return new ValueTask<DateTimeOffset?>(token.CreationDate); return new ValueTask<DateTimeOffset?>(token.CreationDate);
} }
/// <summary> /// <inheritdoc/>
/// Retrieves the expiration date associated with a token. public virtual ValueTask<DateTimeOffset?> GetExpirationDateAsync(TToken token, CancellationToken cancellationToken)
/// </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)
{ {
if (token == null) if (token == null)
{ {
@ -577,54 +453,30 @@ namespace OpenIddict.EntityFrameworkCore
return new ValueTask<DateTimeOffset?>(token.ExpirationDate); return new ValueTask<DateTimeOffset?>(token.ExpirationDate);
} }
/// <summary> /// <inheritdoc/>
/// Retrieves the unique identifier associated with a token. public virtual ValueTask<string?> GetIdAsync(TToken token, CancellationToken cancellationToken)
/// </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)
{ {
if (token == null) if (token == null)
{ {
throw new ArgumentNullException(nameof(token)); throw new ArgumentNullException(nameof(token));
} }
return new ValueTask<string>(ConvertIdentifierToString(token.Id)); return new ValueTask<string?>(ConvertIdentifierToString(token.Id));
} }
/// <summary> /// <inheritdoc/>
/// Retrieves the payload associated with a token. public virtual ValueTask<string?> GetPayloadAsync(TToken token, CancellationToken cancellationToken)
/// </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)
{ {
if (token == null) if (token == null)
{ {
throw new ArgumentNullException(nameof(token)); throw new ArgumentNullException(nameof(token));
} }
return new ValueTask<string>(token.Payload); return new ValueTask<string?>(token.Payload);
} }
/// <summary> /// <inheritdoc/>
/// Retrieves the additional properties associated with a token. public virtual ValueTask<ImmutableDictionary<string, JsonElement>> GetPropertiesAsync(TToken token, CancellationToken cancellationToken)
/// </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)
{ {
if (token == null) if (token == null)
{ {
@ -650,92 +502,51 @@ namespace OpenIddict.EntityFrameworkCore
return new ValueTask<ImmutableDictionary<string, JsonElement>>(properties); return new ValueTask<ImmutableDictionary<string, JsonElement>>(properties);
} }
/// <summary> /// <inheritdoc/>
/// Retrieves the reference identifier associated with a token. public virtual ValueTask<string?> GetReferenceIdAsync(TToken token, CancellationToken cancellationToken)
/// 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)
{ {
if (token == null) if (token == null)
{ {
throw new ArgumentNullException(nameof(token)); throw new ArgumentNullException(nameof(token));
} }
return new ValueTask<string>(token.ReferenceId); return new ValueTask<string?>(token.ReferenceId);
} }
/// <summary> /// <inheritdoc/>
/// Retrieves the status associated with a token. public virtual ValueTask<string?> GetStatusAsync(TToken token, CancellationToken cancellationToken)
/// </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)
{ {
if (token == null) if (token == null)
{ {
throw new ArgumentNullException(nameof(token)); throw new ArgumentNullException(nameof(token));
} }
return new ValueTask<string>(token.Status); return new ValueTask<string?>(token.Status);
} }
/// <summary> /// <inheritdoc/>
/// Retrieves the subject associated with a token. public virtual ValueTask<string?> GetSubjectAsync(TToken token, CancellationToken cancellationToken)
/// </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)
{ {
if (token == null) if (token == null)
{ {
throw new ArgumentNullException(nameof(token)); throw new ArgumentNullException(nameof(token));
} }
return new ValueTask<string>(token.Subject); return new ValueTask<string?>(token.Subject);
} }
/// <summary> /// <inheritdoc/>
/// Retrieves the token type associated with a token. public virtual ValueTask<string?> GetTypeAsync(TToken token, CancellationToken cancellationToken)
/// </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)
{ {
if (token == null) if (token == null)
{ {
throw new ArgumentNullException(nameof(token)); throw new ArgumentNullException(nameof(token));
} }
return new ValueTask<string>(token.Type); return new ValueTask<string?>(token.Type);
} }
/// <summary> /// <inheritdoc/>
/// 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>
public virtual ValueTask<TToken> InstantiateAsync(CancellationToken cancellationToken) public virtual ValueTask<TToken> InstantiateAsync(CancellationToken cancellationToken)
{ {
try try
@ -750,19 +561,12 @@ namespace OpenIddict.EntityFrameworkCore
} }
} }
/// <summary> /// <inheritdoc/>
/// Executes the specified query and returns all the corresponding elements. public virtual IAsyncEnumerable<TToken> ListAsync(int? count, int? offset, CancellationToken cancellationToken)
/// </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)
{ {
var query = Tokens.Include(token => token.Application) var query = Tokens.Include(token => token.Application)
.Include(token => token.Authorization) .Include(token => token.Authorization)
.OrderBy(token => token.Id) .OrderBy(token => token.Id!)
.AsTracking(); .AsTracking();
if (offset.HasValue) if (offset.HasValue)
@ -778,18 +582,10 @@ namespace OpenIddict.EntityFrameworkCore
return query.AsAsyncEnumerable(); return query.AsAsyncEnumerable();
} }
/// <summary> /// <inheritdoc/>
/// 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>
public virtual IAsyncEnumerable<TResult> ListAsync<TState, TResult>( public virtual IAsyncEnumerable<TResult> ListAsync<TState, TResult>(
[NotNull] Func<IQueryable<TToken>, TState, IQueryable<TResult>> query, Func<IQueryable<TToken>, TState, IQueryable<TResult>> query,
[CanBeNull] TState state, CancellationToken cancellationToken) TState state, CancellationToken cancellationToken)
{ {
if (query == null) if (query == null)
{ {
@ -802,20 +598,16 @@ namespace OpenIddict.EntityFrameworkCore
.AsTracking(), state).AsAsyncEnumerable(); .AsTracking(), state).AsAsyncEnumerable();
} }
/// <summary> /// <inheritdoc/>
/// 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>
public virtual async ValueTask PruneAsync(CancellationToken cancellationToken) public virtual async ValueTask PruneAsync(CancellationToken cancellationToken)
{ {
// Note: Entity Framework Core doesn't support set-based deletes, which prevents removing // Note: Entity Framework Core doesn't support set-based deletes, which prevents removing
// entities in a single command without having to retrieve and materialize them first. // 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. // To work around this limitation, entities are manually listed and deleted using a batch logic.
List<Exception> exceptions = null; List<Exception>? exceptions = null;
async ValueTask<IDbContextTransaction> CreateTransactionAsync() async ValueTask<IDbContextTransaction?> CreateTransactionAsync()
{ {
// Note: transactions that specify an explicit isolation level are only supported by // Note: transactions that specify an explicit isolation level are only supported by
// relational providers and trying to use them with a different provider results in // relational providers and trying to use them with a different provider results in
@ -889,17 +681,8 @@ namespace OpenIddict.EntityFrameworkCore
} }
} }
/// <summary> /// <inheritdoc/>
/// Sets the application identifier associated with a token. public virtual async ValueTask SetApplicationIdAsync(TToken token, string? identifier, CancellationToken cancellationToken)
/// </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)
{ {
if (token == null) if (token == null)
{ {
@ -913,7 +696,7 @@ namespace OpenIddict.EntityFrameworkCore
// Warning: FindAsync() is deliberately not used to work around a breaking change introduced // Warning: FindAsync() is deliberately not used to work around a breaking change introduced
// in Entity Framework Core 3.x (where a ValueTask instead of a Task is now returned). // in Entity Framework Core 3.x (where a ValueTask instead of a Task is now returned).
var application = await Applications.AsQueryable() var application = await Applications.AsQueryable()
.FirstOrDefaultAsync(application => application.Id.Equals(key), cancellationToken); .FirstOrDefaultAsync(application => application.Id!.Equals(key), cancellationToken);
if (application == null) if (application == null)
{ {
@ -941,17 +724,8 @@ namespace OpenIddict.EntityFrameworkCore
} }
} }
/// <summary> /// <inheritdoc/>
/// Sets the authorization identifier associated with a token. public virtual async ValueTask SetAuthorizationIdAsync(TToken token, string? identifier, CancellationToken cancellationToken)
/// </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)
{ {
if (token == null) if (token == null)
{ {
@ -965,7 +739,7 @@ namespace OpenIddict.EntityFrameworkCore
// Warning: FindAsync() is deliberately not used to work around a breaking change introduced // Warning: FindAsync() is deliberately not used to work around a breaking change introduced
// in Entity Framework Core 3.x (where a ValueTask instead of a Task is now returned). // in Entity Framework Core 3.x (where a ValueTask instead of a Task is now returned).
var authorization = await Authorizations.AsQueryable() var authorization = await Authorizations.AsQueryable()
.FirstOrDefaultAsync(authorization => authorization.Id.Equals(key), cancellationToken); .FirstOrDefaultAsync(authorization => authorization.Id!.Equals(key), cancellationToken);
if (authorization == null) if (authorization == null)
{ {
@ -993,17 +767,8 @@ namespace OpenIddict.EntityFrameworkCore
} }
} }
/// <summary> /// <inheritdoc/>
/// Sets the creation date associated with a token. public virtual ValueTask SetCreationDateAsync(TToken token, DateTimeOffset? date, CancellationToken cancellationToken)
/// </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)
{ {
if (token == null) if (token == null)
{ {
@ -1015,17 +780,8 @@ namespace OpenIddict.EntityFrameworkCore
return default; return default;
} }
/// <summary> /// <inheritdoc/>
/// Sets the expiration date associated with a token. public virtual ValueTask SetExpirationDateAsync(TToken token, DateTimeOffset? date, CancellationToken cancellationToken)
/// </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)
{ {
if (token == null) if (token == null)
{ {
@ -1037,16 +793,8 @@ namespace OpenIddict.EntityFrameworkCore
return default; return default;
} }
/// <summary> /// <inheritdoc/>
/// Sets the payload associated with a token. public virtual ValueTask SetPayloadAsync(TToken token, string? payload, CancellationToken cancellationToken)
/// </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)
{ {
if (token == null) if (token == null)
{ {
@ -1058,17 +806,9 @@ namespace OpenIddict.EntityFrameworkCore
return default; return default;
} }
/// <summary> /// <inheritdoc/>
/// Sets the additional properties associated with a token. public virtual ValueTask SetPropertiesAsync(TToken token,
/// </summary> ImmutableDictionary<string, JsonElement> properties, CancellationToken cancellationToken)
/// <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)
{ {
if (token == null) if (token == null)
{ {
@ -1091,18 +831,8 @@ namespace OpenIddict.EntityFrameworkCore
return default; return default;
} }
/// <summary> /// <inheritdoc/>
/// Sets the reference identifier associated with a token. public virtual ValueTask SetReferenceIdAsync(TToken token, string? identifier, CancellationToken cancellationToken)
/// 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)
{ {
if (token == null) if (token == null)
{ {
@ -1114,16 +844,8 @@ namespace OpenIddict.EntityFrameworkCore
return default; return default;
} }
/// <summary> /// <inheritdoc/>
/// Sets the status associated with a token. public virtual ValueTask SetStatusAsync(TToken token, string? status, CancellationToken cancellationToken)
/// </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)
{ {
if (token == null) if (token == null)
{ {
@ -1135,16 +857,8 @@ namespace OpenIddict.EntityFrameworkCore
return default; return default;
} }
/// <summary> /// <inheritdoc/>
/// Sets the subject associated with a token. public virtual ValueTask SetSubjectAsync(TToken token, string? subject, CancellationToken cancellationToken)
/// </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)
{ {
if (token == null) if (token == null)
{ {
@ -1156,16 +870,8 @@ namespace OpenIddict.EntityFrameworkCore
return default; return default;
} }
/// <summary> /// <inheritdoc/>
/// Sets the token type associated with a token. public virtual ValueTask SetTypeAsync(TToken token, string? type, CancellationToken cancellationToken)
/// </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)
{ {
if (token == null) if (token == null)
{ {
@ -1177,15 +883,8 @@ namespace OpenIddict.EntityFrameworkCore
return default; return default;
} }
/// <summary> /// <inheritdoc/>
/// Updates an existing token. public virtual async ValueTask UpdateAsync(TToken token, CancellationToken cancellationToken)
/// </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)
{ {
if (token == null) if (token == null)
{ {
@ -1219,7 +918,8 @@ namespace OpenIddict.EntityFrameworkCore
/// </summary> /// </summary>
/// <param name="identifier">The identifier to convert.</param> /// <param name="identifier">The identifier to convert.</param>
/// <returns>An instance of <typeparamref name="TKey"/> representing the provided identifier.</returns> /// <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)) if (string.IsNullOrEmpty(identifier))
{ {
@ -1234,7 +934,7 @@ namespace OpenIddict.EntityFrameworkCore
/// </summary> /// </summary>
/// <param name="identifier">The identifier to convert.</param> /// <param name="identifier">The identifier to convert.</param>
/// <returns>A <see cref="string"/> representation of the provided identifier.</returns> /// <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))) if (Equals(identifier, default(TKey)))
{ {

Loading…
Cancel
Save