Browse Source

Update the managers/stores methods to accept and return ImmutableArray instead of raw arrays

pull/487/head
Kévin Chalet 8 years ago
parent
commit
1118e77977
  1. 1
      build/dependencies.props
  2. 11
      src/OpenIddict.Core/Managers/OpenIddictApplicationManager.cs
  3. 5
      src/OpenIddict.Core/Managers/OpenIddictAuthorizationManager.cs
  4. 5
      src/OpenIddict.Core/Managers/OpenIddictScopeManager.cs
  5. 9
      src/OpenIddict.Core/Managers/OpenIddictTokenManager.cs
  6. 1
      src/OpenIddict.Core/OpenIddict.Core.csproj
  7. 19
      src/OpenIddict.Core/Stores/IOpenIddictApplicationStore.cs
  8. 5
      src/OpenIddict.Core/Stores/IOpenIddictAuthorizationStore.cs
  9. 5
      src/OpenIddict.Core/Stores/IOpenIddictScopeStore.cs
  10. 9
      src/OpenIddict.Core/Stores/IOpenIddictTokenStore.cs
  11. 130
      src/OpenIddict.Core/Stores/OpenIddictApplicationStore.cs
  12. 5
      src/OpenIddict.Core/Stores/OpenIddictAuthorizationStore.cs
  13. 5
      src/OpenIddict.Core/Stores/OpenIddictScopeStore.cs
  14. 9
      src/OpenIddict.Core/Stores/OpenIddictTokenStore.cs
  15. 5
      src/OpenIddict.EntityFramework/Stores/OpenIddictApplicationStore.cs
  16. 5
      src/OpenIddict.EntityFramework/Stores/OpenIddictAuthorizationStore.cs
  17. 5
      src/OpenIddict.EntityFramework/Stores/OpenIddictScopeStore.cs
  18. 5
      src/OpenIddict.EntityFramework/Stores/OpenIddictTokenStore.cs
  19. 5
      src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictApplicationStore.cs
  20. 5
      src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictAuthorizationStore.cs
  21. 5
      src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictScopeStore.cs
  22. 5
      src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictTokenStore.cs
  23. 19
      test/OpenIddict.Tests/OpenIddictProviderTests.Exchange.cs
  24. 13
      test/OpenIddict.Tests/OpenIddictProviderTests.Signin.cs

1
build/dependencies.props

@ -9,6 +9,7 @@
<EntityFrameworkVersion>6.1.3</EntityFrameworkVersion>
<JetBrainsVersion>10.3.0</JetBrainsVersion>
<JsonNetBsonVersion>1.0.1</JsonNetBsonVersion>
<ImmutableCollectionsVersion>1.4.0</ImmutableCollectionsVersion>
<MoqVersion>4.7.63</MoqVersion>
<NetStandardImplicitPackageVersion>2.0.0</NetStandardImplicitPackageVersion>
<NetStandardLibraryNetFrameworkVersion>2.0.0</NetStandardLibraryNetFrameworkVersion>

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

@ -5,6 +5,7 @@
*/
using System;
using System.Collections.Immutable;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
@ -239,7 +240,7 @@ namespace OpenIddict.Core
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation, whose result
/// returns the client applications corresponding to the specified post_logout_redirect_uri.
/// </returns>
public virtual Task<TApplication[]> FindByPostLogoutRedirectUriAsync([NotNull] string address, CancellationToken cancellationToken)
public virtual Task<ImmutableArray<TApplication>> FindByPostLogoutRedirectUriAsync([NotNull] string address, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(address))
{
@ -258,7 +259,7 @@ namespace OpenIddict.Core
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation, whose result
/// returns the client applications corresponding to the specified redirect_uri.
/// </returns>
public virtual Task<TApplication[]> FindByRedirectUriAsync([NotNull] string address, CancellationToken cancellationToken)
public virtual Task<ImmutableArray<TApplication>> FindByRedirectUriAsync([NotNull] string address, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(address))
{
@ -384,7 +385,7 @@ namespace OpenIddict.Core
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the tokens associated with the application.
/// </returns>
public virtual Task<string[]> GetTokensAsync([NotNull] TApplication application, CancellationToken cancellationToken)
public virtual Task<ImmutableArray<string>> GetTokensAsync([NotNull] TApplication application, CancellationToken cancellationToken)
{
if (application == null)
{
@ -471,7 +472,7 @@ namespace OpenIddict.Core
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the elements returned when executing the specified query.
/// </returns>
public virtual Task<TApplication[]> ListAsync([CanBeNull] int? count, [CanBeNull] int? offset, CancellationToken cancellationToken)
public virtual Task<ImmutableArray<TApplication>> ListAsync([CanBeNull] int? count, [CanBeNull] int? offset, CancellationToken cancellationToken)
{
return Store.ListAsync(count, offset, cancellationToken);
}
@ -486,7 +487,7 @@ namespace OpenIddict.Core
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the elements returned when executing the specified query.
/// </returns>
public virtual Task<TResult[]> ListAsync<TResult>([NotNull] Func<IQueryable<TApplication>, IQueryable<TResult>> query, CancellationToken cancellationToken)
public virtual Task<ImmutableArray<TResult>> ListAsync<TResult>([NotNull] Func<IQueryable<TApplication>, IQueryable<TResult>> query, CancellationToken cancellationToken)
{
if (query == null)
{

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

@ -5,6 +5,7 @@
*/
using System;
using System.Collections.Immutable;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
@ -280,7 +281,7 @@ namespace OpenIddict.Core
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the elements returned when executing the specified query.
/// </returns>
public virtual Task<TAuthorization[]> ListAsync([CanBeNull] int? count, [CanBeNull] int? offset, CancellationToken cancellationToken)
public virtual Task<ImmutableArray<TAuthorization>> ListAsync([CanBeNull] int? count, [CanBeNull] int? offset, CancellationToken cancellationToken)
{
return Store.ListAsync(count, offset, cancellationToken);
}
@ -295,7 +296,7 @@ namespace OpenIddict.Core
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the elements returned when executing the specified query.
/// </returns>
public virtual Task<TResult[]> ListAsync<TResult>([NotNull] Func<IQueryable<TAuthorization>, IQueryable<TResult>> query, CancellationToken cancellationToken)
public virtual Task<ImmutableArray<TResult>> ListAsync<TResult>([NotNull] Func<IQueryable<TAuthorization>, IQueryable<TResult>> query, CancellationToken cancellationToken)
{
if (query == null)
{

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

@ -5,6 +5,7 @@
*/
using System;
using System.Collections.Immutable;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
@ -154,7 +155,7 @@ namespace OpenIddict.Core
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the elements returned when executing the specified query.
/// </returns>
public virtual Task<TScope[]> ListAsync([CanBeNull] int? count, [CanBeNull] int? offset, CancellationToken cancellationToken)
public virtual Task<ImmutableArray<TScope>> ListAsync([CanBeNull] int? count, [CanBeNull] int? offset, CancellationToken cancellationToken)
{
return Store.ListAsync(count, offset, cancellationToken);
}
@ -169,7 +170,7 @@ namespace OpenIddict.Core
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the elements returned when executing the specified query.
/// </returns>
public virtual Task<TResult[]> ListAsync<TResult>([NotNull] Func<IQueryable<TScope>, IQueryable<TResult>> query, CancellationToken cancellationToken)
public virtual Task<ImmutableArray<TResult>> ListAsync<TResult>([NotNull] Func<IQueryable<TScope>, IQueryable<TResult>> query, CancellationToken cancellationToken)
{
if (query == null)
{

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

@ -5,6 +5,7 @@
*/
using System;
using System.Collections.Immutable;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
@ -138,7 +139,7 @@ namespace OpenIddict.Core
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the tokens corresponding to the specified authorization.
/// </returns>
public virtual Task<TToken[]> FindByAuthorizationIdAsync(string identifier, CancellationToken cancellationToken)
public virtual Task<ImmutableArray<TToken>> FindByAuthorizationIdAsync(string identifier, CancellationToken cancellationToken)
{
return Store.FindByAuthorizationIdAsync(identifier, cancellationToken);
}
@ -180,7 +181,7 @@ namespace OpenIddict.Core
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the tokens corresponding to the specified subject.
/// </returns>
public virtual Task<TToken[]> FindBySubjectAsync(string subject, CancellationToken cancellationToken)
public virtual Task<ImmutableArray<TToken>> FindBySubjectAsync(string subject, CancellationToken cancellationToken)
{
return Store.FindBySubjectAsync(subject, cancellationToken);
}
@ -414,7 +415,7 @@ namespace OpenIddict.Core
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the elements returned when executing the specified query.
/// </returns>
public virtual Task<TToken[]> ListAsync([CanBeNull] int? count, [CanBeNull] int? offset, CancellationToken cancellationToken)
public virtual Task<ImmutableArray<TToken>> ListAsync([CanBeNull] int? count, [CanBeNull] int? offset, CancellationToken cancellationToken)
{
return Store.ListAsync(count, offset, cancellationToken);
}
@ -429,7 +430,7 @@ namespace OpenIddict.Core
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the elements returned when executing the specified query.
/// </returns>
public virtual Task<TResult[]> ListAsync<TResult>([NotNull] Func<IQueryable<TToken>, IQueryable<TResult>> query, CancellationToken cancellationToken)
public virtual Task<ImmutableArray<TResult>> ListAsync<TResult>([NotNull] Func<IQueryable<TToken>, IQueryable<TResult>> query, CancellationToken cancellationToken)
{
if (query == null)
{

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

@ -23,6 +23,7 @@
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="$(AspNetCoreVersion)" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="$(AspNetCoreVersion)" />
<PackageReference Include="Microsoft.Extensions.Options" Version="$(AspNetCoreVersion)" />
<PackageReference Include="System.Collections.Immutable" Version="$(ImmutableCollectionsVersion)" />
</ItemGroup>
</Project>

19
src/OpenIddict.Core/Stores/IOpenIddictApplicationStore.cs

@ -6,6 +6,7 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
@ -102,7 +103,7 @@ namespace OpenIddict.Core
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation, whose result
/// returns the client applications corresponding to the specified post_logout_redirect_uri.
/// </returns>
Task<TApplication[]> FindByPostLogoutRedirectUriAsync([NotNull] string address, CancellationToken cancellationToken);
Task<ImmutableArray<TApplication>> FindByPostLogoutRedirectUriAsync([NotNull] string address, CancellationToken cancellationToken);
/// <summary>
/// Retrieves all the applications associated with the specified redirect_uri.
@ -113,7 +114,7 @@ namespace OpenIddict.Core
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation, whose result
/// returns the client applications corresponding to the specified redirect_uri.
/// </returns>
Task<TApplication[]> FindByRedirectUriAsync([NotNull] string address, CancellationToken cancellationToken);
Task<ImmutableArray<TApplication>> FindByRedirectUriAsync([NotNull] string address, CancellationToken cancellationToken);
/// <summary>
/// Executes the specified query.
@ -193,7 +194,7 @@ namespace OpenIddict.Core
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation, whose
/// result returns all the post_logout_redirect_uri associated with the application.
/// </returns>
Task<string[]> GetPostLogoutRedirectUrisAsync([NotNull] TApplication application, CancellationToken cancellationToken);
Task<ImmutableArray<string>> GetPostLogoutRedirectUrisAsync([NotNull] TApplication application, CancellationToken cancellationToken);
/// <summary>
/// Retrieves the callback addresses associated with an application.
@ -204,7 +205,7 @@ namespace OpenIddict.Core
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the redirect_uri associated with the application.
/// </returns>
Task<string[]> GetRedirectUrisAsync([NotNull] TApplication application, CancellationToken cancellationToken);
Task<ImmutableArray<string>> GetRedirectUrisAsync([NotNull] TApplication application, CancellationToken cancellationToken);
/// <summary>
/// Retrieves the token identifiers associated with an application.
@ -215,7 +216,7 @@ namespace OpenIddict.Core
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the tokens associated with the application.
/// </returns>
Task<string[]> GetTokensAsync([NotNull] TApplication application, CancellationToken cancellationToken);
Task<ImmutableArray<string>> GetTokensAsync([NotNull] TApplication application, CancellationToken cancellationToken);
/// <summary>
/// Executes the specified query.
@ -227,7 +228,7 @@ namespace OpenIddict.Core
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the elements returned when executing the specified query.
/// </returns>
Task<TApplication[]> ListAsync([CanBeNull] int? count, [CanBeNull] int? offset, CancellationToken cancellationToken);
Task<ImmutableArray<TApplication>> ListAsync([CanBeNull] int? count, [CanBeNull] int? offset, CancellationToken cancellationToken);
/// <summary>
/// Executes the specified query.
@ -239,7 +240,7 @@ namespace OpenIddict.Core
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the elements returned when executing the specified query.
/// </returns>
Task<TResult[]> ListAsync<TResult>([NotNull] Func<IQueryable<TApplication>, IQueryable<TResult>> query, CancellationToken cancellationToken);
Task<ImmutableArray<TResult>> ListAsync<TResult>([NotNull] Func<IQueryable<TApplication>, IQueryable<TResult>> query, CancellationToken cancellationToken);
/// <summary>
/// Sets the client secret associated with an application.
@ -275,7 +276,7 @@ namespace OpenIddict.Core
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
Task SetPostLogoutRedirectUrisAsync([NotNull] TApplication application,
[NotNull] string[] addresses, CancellationToken cancellationToken);
[NotNull] ImmutableArray<string> addresses, CancellationToken cancellationToken);
/// <summary>
/// Sets the callback addresses associated with an application.
@ -287,7 +288,7 @@ namespace OpenIddict.Core
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
Task SetRedirectUrisAsync([NotNull] TApplication application,
[NotNull] string[] addresses, CancellationToken cancellationToken);
[NotNull] ImmutableArray<string> addresses, CancellationToken cancellationToken);
/// <summary>
/// Updates an existing application.

5
src/OpenIddict.Core/Stores/IOpenIddictAuthorizationStore.cs

@ -5,6 +5,7 @@
*/
using System;
using System.Collections.Immutable;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
@ -159,7 +160,7 @@ namespace OpenIddict.Core
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the elements returned when executing the specified query.
/// </returns>
Task<TAuthorization[]> ListAsync([CanBeNull] int? count, [CanBeNull] int? offset, CancellationToken cancellationToken);
Task<ImmutableArray<TAuthorization>> ListAsync([CanBeNull] int? count, [CanBeNull] int? offset, CancellationToken cancellationToken);
/// <summary>
/// Executes the specified query.
@ -171,7 +172,7 @@ namespace OpenIddict.Core
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the elements returned when executing the specified query.
/// </returns>
Task<TResult[]> ListAsync<TResult>([NotNull] Func<IQueryable<TAuthorization>, IQueryable<TResult>> query, CancellationToken cancellationToken);
Task<ImmutableArray<TResult>> ListAsync<TResult>([NotNull] Func<IQueryable<TAuthorization>, IQueryable<TResult>> query, CancellationToken cancellationToken);
/// <summary>
/// Sets the status associated with an authorization.

5
src/OpenIddict.Core/Stores/IOpenIddictScopeStore.cs

@ -5,6 +5,7 @@
*/
using System;
using System.Collections.Immutable;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
@ -92,7 +93,7 @@ namespace OpenIddict.Core
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the elements returned when executing the specified query.
/// </returns>
Task<TScope[]> ListAsync([CanBeNull] int? count, [CanBeNull] int? offset, CancellationToken cancellationToken);
Task<ImmutableArray<TScope>> ListAsync([CanBeNull] int? count, [CanBeNull] int? offset, CancellationToken cancellationToken);
/// <summary>
/// Executes the specified query.
@ -104,7 +105,7 @@ namespace OpenIddict.Core
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the elements returned when executing the specified query.
/// </returns>
Task<TResult[]> ListAsync<TResult>([NotNull] Func<IQueryable<TScope>, IQueryable<TResult>> query, CancellationToken cancellationToken);
Task<ImmutableArray<TResult>> ListAsync<TResult>([NotNull] Func<IQueryable<TScope>, IQueryable<TResult>> query, CancellationToken cancellationToken);
/// <summary>
/// Updates an existing scope.

9
src/OpenIddict.Core/Stores/IOpenIddictTokenStore.cs

@ -5,6 +5,7 @@
*/
using System;
using System.Collections.Immutable;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
@ -77,7 +78,7 @@ namespace OpenIddict.Core
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the tokens corresponding to the specified authorization.
/// </returns>
Task<TToken[]> FindByAuthorizationIdAsync([NotNull] string identifier, CancellationToken cancellationToken);
Task<ImmutableArray<TToken>> FindByAuthorizationIdAsync([NotNull] string identifier, CancellationToken cancellationToken);
/// <summary>
/// Retrieves the list of tokens corresponding to the specified hash.
@ -110,7 +111,7 @@ namespace OpenIddict.Core
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the tokens corresponding to the specified subject.
/// </returns>
Task<TToken[]> FindBySubjectAsync([NotNull] string subject, CancellationToken cancellationToken);
Task<ImmutableArray<TToken>> FindBySubjectAsync([NotNull] string subject, CancellationToken cancellationToken);
/// <summary>
/// Executes the specified query.
@ -233,7 +234,7 @@ namespace OpenIddict.Core
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the elements returned when executing the specified query.
/// </returns>
Task<TToken[]> ListAsync([CanBeNull] int? count, [CanBeNull] int? offset, CancellationToken cancellationToken);
Task<ImmutableArray<TToken>> ListAsync([CanBeNull] int? count, [CanBeNull] int? offset, CancellationToken cancellationToken);
/// <summary>
/// Executes the specified query.
@ -245,7 +246,7 @@ namespace OpenIddict.Core
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the elements returned when executing the specified query.
/// </returns>
Task<TResult[]> ListAsync<TResult>([NotNull] Func<IQueryable<TToken>, IQueryable<TResult>> query, CancellationToken cancellationToken);
Task<ImmutableArray<TResult>> ListAsync<TResult>([NotNull] Func<IQueryable<TToken>, IQueryable<TResult>> query, CancellationToken cancellationToken);
/// <summary>
/// Sets the authorization associated with a token.

130
src/OpenIddict.Core/Stores/OpenIddictApplicationStore.cs

@ -5,7 +5,7 @@
*/
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.ComponentModel;
using System.Linq;
using System.Threading;
@ -134,28 +134,30 @@ namespace OpenIddict.Core
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation, whose result
/// returns the client applications corresponding to the specified post_logout_redirect_uri.
/// </returns>
public virtual async Task<TApplication[]> FindByPostLogoutRedirectUriAsync([NotNull] string address, CancellationToken cancellationToken)
public virtual async Task<ImmutableArray<TApplication>> FindByPostLogoutRedirectUriAsync([NotNull] string address, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(address))
{
throw new ArgumentException("The address cannot be null or empty.", nameof(address));
}
// To optimize the efficiency of the query, only the applications whose stringified
// To optimize the efficiency of the query, only applications whose stringified
// LogoutRedirectUris property contains the specified address are returned. Once the
// applications are retrieved, the LogoutRedirectUri property is manually split.
var candidates = await ListAsync(applications => applications.Where(application =>
application.PostLogoutRedirectUris.Contains(address)), cancellationToken);
IQueryable<TApplication> Query(IQueryable<TApplication> applications)
{
return from application in applications
where application.PostLogoutRedirectUris.Contains(address)
select application;
}
if (candidates.Length == 0)
var candidates = await ListAsync(Query, cancellationToken);
if (candidates.IsDefaultOrEmpty)
{
return Array.Empty<TApplication>();
return ImmutableArray.Create<TApplication>();
}
// Optimization: to save an allocation when no application matches
// the specified address, the results list is lazily initialized
// when at least one matching application was found in the database.
List<TApplication> results = null;
var builder = ImmutableArray.CreateBuilder<TApplication>(0);
foreach (var candidate in candidates)
{
@ -172,22 +174,16 @@ namespace OpenIddict.Core
{
// Note: the post_logout_redirect_uri must be compared
// using case-sensitive "Simple String Comparison".
if (!string.Equals(uri, address, StringComparison.Ordinal))
if (string.Equals(uri, address, StringComparison.Ordinal))
{
continue;
}
builder.Add(candidate);
// Ensure the results list was initialized before using it.
if (results == null)
{
results = new List<TApplication>(capacity: 1);
break;
}
results.Add(candidate);
}
}
return results?.ToArray() ?? Array.Empty<TApplication>();
return builder.ToImmutable();
}
/// <summary>
@ -199,28 +195,30 @@ namespace OpenIddict.Core
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation, whose result
/// returns the client applications corresponding to the specified redirect_uri.
/// </returns>
public virtual async Task<TApplication[]> FindByRedirectUriAsync([NotNull] string address, CancellationToken cancellationToken)
public virtual async Task<ImmutableArray<TApplication>> FindByRedirectUriAsync([NotNull] string address, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(address))
{
throw new ArgumentException("The address cannot be null or empty.", nameof(address));
}
// To optimize the efficiency of the query, only the applications whose stringified
// To optimize the efficiency of the query, only applications whose stringified
// RedirectUris property contains the specified address are returned. Once the
// applications are retrieved, the RedirectUri property is manually split.
var candidates = await ListAsync(applications => applications.Where(application =>
application.RedirectUris.Contains(address)), cancellationToken);
IQueryable<TApplication> Query(IQueryable<TApplication> applications)
{
return from application in applications
where application.RedirectUris.Contains(address)
select application;
}
if (candidates.Length == 0)
var candidates = await ListAsync(Query, cancellationToken);
if (candidates.IsDefaultOrEmpty)
{
return Array.Empty<TApplication>();
return ImmutableArray.Create<TApplication>();
}
// Optimization: to save an allocation when no application matches
// the specified address, the results list is lazily initialized
// when at least one matching application was found in the database.
List<TApplication> results = null;
var builder = ImmutableArray.CreateBuilder<TApplication>(0);
foreach (var candidate in candidates)
{
@ -237,22 +235,16 @@ namespace OpenIddict.Core
{
// Note: the redirect_uri must be compared using case-sensitive "Simple String Comparison".
// See http://openid.net/specs/openid-connect-core-1_0.html#AuthRequest for more information.
if (!string.Equals(uri, address, StringComparison.Ordinal))
if (string.Equals(uri, address, StringComparison.Ordinal))
{
continue;
}
builder.Add(candidate);
// Ensure the results list was initialized before using it.
if (results == null)
{
results = new List<TApplication>(capacity: 1);
break;
}
results.Add(candidate);
}
}
return results?.ToArray() ?? Array.Empty<TApplication>();
return builder.ToImmutable();
}
/// <summary>
@ -373,7 +365,7 @@ namespace OpenIddict.Core
/// A <see cref="Task"/> 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 Task<string[]> GetPostLogoutRedirectUrisAsync([NotNull] TApplication application, CancellationToken cancellationToken)
public virtual Task<ImmutableArray<string>> GetPostLogoutRedirectUrisAsync([NotNull] TApplication application, CancellationToken cancellationToken)
{
if (application == null)
{
@ -382,12 +374,14 @@ namespace OpenIddict.Core
if (string.IsNullOrEmpty(application.PostLogoutRedirectUris))
{
return Task.FromResult(Array.Empty<string>());
return Task.FromResult(ImmutableArray.Create<string>());
}
return Task.FromResult(application.PostLogoutRedirectUris.Split(
var uris = application.PostLogoutRedirectUris.Split(
OpenIdConnectConstants.Separators.Space,
StringSplitOptions.RemoveEmptyEntries));
StringSplitOptions.RemoveEmptyEntries);
return Task.FromResult(ImmutableArray.Create(uris));
}
/// <summary>
@ -399,7 +393,7 @@ namespace OpenIddict.Core
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the redirect_uri associated with the application.
/// </returns>
public virtual Task<string[]> GetRedirectUrisAsync([NotNull] TApplication application, CancellationToken cancellationToken)
public virtual Task<ImmutableArray<string>> GetRedirectUrisAsync([NotNull] TApplication application, CancellationToken cancellationToken)
{
if (application == null)
{
@ -408,12 +402,14 @@ namespace OpenIddict.Core
if (string.IsNullOrEmpty(application.RedirectUris))
{
return Task.FromResult(Array.Empty<string>());
return Task.FromResult(ImmutableArray.Create<string>());
}
return Task.FromResult(application.RedirectUris.Split(
var uris = application.RedirectUris.Split(
OpenIdConnectConstants.Separators.Space,
StringSplitOptions.RemoveEmptyEntries));
StringSplitOptions.RemoveEmptyEntries);
return Task.FromResult(ImmutableArray.Create(uris));
}
/// <summary>
@ -425,25 +421,35 @@ namespace OpenIddict.Core
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the tokens associated with the application.
/// </returns>
public virtual async Task<string[]> GetTokensAsync([NotNull] TApplication application, CancellationToken cancellationToken)
public virtual async Task<ImmutableArray<string>> GetTokensAsync([NotNull] TApplication application, CancellationToken cancellationToken)
{
if (application == null)
{
throw new ArgumentNullException(nameof(application));
}
var tokens = new List<string>();
IQueryable<TKey> Query(IQueryable<TApplication> applications)
{
return from entity in applications
where entity.Id.Equals(application.Id)
from token in entity.Tokens
select token.Id;
}
var identifiers = await ListAsync(Query, cancellationToken);
if (identifiers.IsDefaultOrEmpty)
{
return ImmutableArray.Create<string>();
}
var builder = ImmutableArray.CreateBuilder<string>(identifiers.Length);
foreach (var identifier in await ListAsync(applications =>
from entity in applications
where entity.Id.Equals(application.Id)
from token in entity.Tokens
select token.Id, cancellationToken))
foreach (var identifier in identifiers)
{
tokens.Add(ConvertIdentifierToString(identifier));
builder.Add(ConvertIdentifierToString(identifier));
}
return tokens.ToArray();
return builder.ToImmutable();
}
/// <summary>
@ -456,7 +462,7 @@ namespace OpenIddict.Core
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the elements returned when executing the specified query.
/// </returns>
public virtual Task<TApplication[]> ListAsync([CanBeNull] int? count, [CanBeNull] int? offset, CancellationToken cancellationToken)
public virtual Task<ImmutableArray<TApplication>> ListAsync([CanBeNull] int? count, [CanBeNull] int? offset, CancellationToken cancellationToken)
{
IQueryable<TApplication> Query(IQueryable<TApplication> applications)
{
@ -488,7 +494,7 @@ namespace OpenIddict.Core
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the elements returned when executing the specified query.
/// </returns>
public abstract Task<TResult[]> ListAsync<TResult>([NotNull] Func<IQueryable<TApplication>, IQueryable<TResult>> query, CancellationToken cancellationToken);
public abstract Task<ImmutableArray<TResult>> ListAsync<TResult>([NotNull] Func<IQueryable<TApplication>, IQueryable<TResult>> query, CancellationToken cancellationToken);
/// <summary>
/// Sets the client secret associated with an application.
@ -550,7 +556,7 @@ namespace OpenIddict.Core
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetPostLogoutRedirectUrisAsync([NotNull] TApplication application,
[NotNull] string[] addresses, CancellationToken cancellationToken)
[NotNull] ImmutableArray<string> addresses, CancellationToken cancellationToken)
{
if (application == null)
{
@ -587,7 +593,7 @@ namespace OpenIddict.Core
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetRedirectUrisAsync([NotNull] TApplication application,
[NotNull] string[] addresses, CancellationToken cancellationToken)
[NotNull] ImmutableArray<string> addresses, CancellationToken cancellationToken)
{
if (application == null)
{

5
src/OpenIddict.Core/Stores/OpenIddictAuthorizationStore.cs

@ -5,6 +5,7 @@
*/
using System;
using System.Collections.Immutable;
using System.ComponentModel;
using System.Linq;
using System.Threading;
@ -228,7 +229,7 @@ namespace OpenIddict.Core
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the elements returned when executing the specified query.
/// </returns>
public virtual Task<TAuthorization[]> ListAsync([CanBeNull] int? count, [CanBeNull] int? offset, CancellationToken cancellationToken)
public virtual Task<ImmutableArray<TAuthorization>> ListAsync([CanBeNull] int? count, [CanBeNull] int? offset, CancellationToken cancellationToken)
{
IQueryable<TAuthorization> Query(IQueryable<TAuthorization> authorizations)
{
@ -260,7 +261,7 @@ namespace OpenIddict.Core
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the elements returned when executing the specified query.
/// </returns>
public abstract Task<TResult[]> ListAsync<TResult>([NotNull] Func<IQueryable<TAuthorization>, IQueryable<TResult>> query, CancellationToken cancellationToken);
public abstract Task<ImmutableArray<TResult>> ListAsync<TResult>([NotNull] Func<IQueryable<TAuthorization>, IQueryable<TResult>> query, CancellationToken cancellationToken);
/// <summary>
/// Sets the status associated with an authorization.

5
src/OpenIddict.Core/Stores/OpenIddictScopeStore.cs

@ -5,6 +5,7 @@
*/
using System;
using System.Collections.Immutable;
using System.ComponentModel;
using System.Linq;
using System.Threading;
@ -101,7 +102,7 @@ namespace OpenIddict.Core
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the elements returned when executing the specified query.
/// </returns>
public virtual Task<TScope[]> ListAsync([CanBeNull] int? count, [CanBeNull] int? offset, CancellationToken cancellationToken)
public virtual Task<ImmutableArray<TScope>> ListAsync([CanBeNull] int? count, [CanBeNull] int? offset, CancellationToken cancellationToken)
{
IQueryable<TScope> Query(IQueryable<TScope> scopes)
{
@ -133,7 +134,7 @@ namespace OpenIddict.Core
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the elements returned when executing the specified query.
/// </returns>
public abstract Task<TResult[]> ListAsync<TResult>([NotNull] Func<IQueryable<TScope>, IQueryable<TResult>> query, CancellationToken cancellationToken);
public abstract Task<ImmutableArray<TResult>> ListAsync<TResult>([NotNull] Func<IQueryable<TScope>, IQueryable<TResult>> query, CancellationToken cancellationToken);
/// <summary>
/// Updates an existing scope.

9
src/OpenIddict.Core/Stores/OpenIddictTokenStore.cs

@ -5,6 +5,7 @@
*/
using System;
using System.Collections.Immutable;
using System.ComponentModel;
using System.Linq;
using System.Threading;
@ -90,7 +91,7 @@ namespace OpenIddict.Core
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the tokens corresponding to the specified authorization.
/// </returns>
public virtual Task<TToken[]> FindByAuthorizationIdAsync([NotNull] string identifier, CancellationToken cancellationToken)
public virtual Task<ImmutableArray<TToken>> FindByAuthorizationIdAsync([NotNull] string identifier, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(identifier))
{
@ -151,7 +152,7 @@ namespace OpenIddict.Core
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the tokens corresponding to the specified subject.
/// </returns>
public virtual Task<TToken[]> FindBySubjectAsync([NotNull] string subject, CancellationToken cancellationToken)
public virtual Task<ImmutableArray<TToken>> FindBySubjectAsync([NotNull] string subject, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(subject))
{
@ -364,7 +365,7 @@ namespace OpenIddict.Core
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the elements returned when executing the specified query.
/// </returns>
public virtual Task<TToken[]> ListAsync([CanBeNull] int? count, [CanBeNull] int? offset, CancellationToken cancellationToken)
public virtual Task<ImmutableArray<TToken>> ListAsync([CanBeNull] int? count, [CanBeNull] int? offset, CancellationToken cancellationToken)
{
IQueryable<TToken> Query(IQueryable<TToken> tokens)
{
@ -396,7 +397,7 @@ namespace OpenIddict.Core
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the elements returned when executing the specified query.
/// </returns>
public abstract Task<TResult[]> ListAsync<TResult>([NotNull] Func<IQueryable<TToken>, IQueryable<TResult>> query, CancellationToken cancellationToken);
public abstract Task<ImmutableArray<TResult>> ListAsync<TResult>([NotNull] Func<IQueryable<TToken>, IQueryable<TResult>> query, CancellationToken cancellationToken);
/// <summary>
/// Sets the authorization associated with a token.

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

@ -5,6 +5,7 @@
*/
using System;
using System.Collections.Immutable;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Linq;
@ -237,14 +238,14 @@ namespace OpenIddict.EntityFramework
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the elements returned when executing the specified query.
/// </returns>
public override Task<TResult[]> ListAsync<TResult>([NotNull] Func<IQueryable<TApplication>, IQueryable<TResult>> query, CancellationToken cancellationToken)
public override async Task<ImmutableArray<TResult>> ListAsync<TResult>([NotNull] Func<IQueryable<TApplication>, IQueryable<TResult>> query, CancellationToken cancellationToken)
{
if (query == null)
{
throw new ArgumentNullException(nameof(query));
}
return query.Invoke(Applications).ToArrayAsync(cancellationToken);
return ImmutableArray.Create(await query.Invoke(Applications).ToArrayAsync(cancellationToken));
}
/// <summary>

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

@ -5,6 +5,7 @@
*/
using System;
using System.Collections.Immutable;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Linq;
@ -244,14 +245,14 @@ namespace OpenIddict.EntityFramework
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the elements returned when executing the specified query.
/// </returns>
public override Task<TResult[]> ListAsync<TResult>([NotNull] Func<IQueryable<TAuthorization>, IQueryable<TResult>> query, CancellationToken cancellationToken)
public override async Task<ImmutableArray<TResult>> ListAsync<TResult>([NotNull] Func<IQueryable<TAuthorization>, IQueryable<TResult>> query, CancellationToken cancellationToken)
{
if (query == null)
{
throw new ArgumentNullException(nameof(query));
}
return query.Invoke(Authorizations).ToArrayAsync(cancellationToken);
return ImmutableArray.Create(await query.Invoke(Authorizations).ToArrayAsync(cancellationToken));
}
/// <summary>

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

@ -5,6 +5,7 @@
*/
using System;
using System.Collections.Immutable;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Linq;
@ -187,14 +188,14 @@ namespace OpenIddict.EntityFramework
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the elements returned when executing the specified query.
/// </returns>
public override Task<TResult[]> ListAsync<TResult>([NotNull] Func<IQueryable<TScope>, IQueryable<TResult>> query, CancellationToken cancellationToken)
public override async Task<ImmutableArray<TResult>> ListAsync<TResult>([NotNull] Func<IQueryable<TScope>, IQueryable<TResult>> query, CancellationToken cancellationToken)
{
if (query == null)
{
throw new ArgumentNullException(nameof(query));
}
return query.Invoke(Scopes).ToArrayAsync(cancellationToken);
return ImmutableArray.Create(await query.Invoke(Scopes).ToArrayAsync(cancellationToken));
}
/// <summary>

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

@ -5,6 +5,7 @@
*/
using System;
using System.Collections.Immutable;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Linq;
@ -258,14 +259,14 @@ namespace OpenIddict.EntityFramework
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the elements returned when executing the specified query.
/// </returns>
public override Task<TResult[]> ListAsync<TResult>([NotNull] Func<IQueryable<TToken>, IQueryable<TResult>> query, CancellationToken cancellationToken)
public override async Task<ImmutableArray<TResult>> ListAsync<TResult>([NotNull] Func<IQueryable<TToken>, IQueryable<TResult>> query, CancellationToken cancellationToken)
{
if (query == null)
{
throw new ArgumentNullException(nameof(query));
}
return query.Invoke(Tokens).ToArrayAsync(cancellationToken);
return ImmutableArray.Create(await query.Invoke(Tokens).ToArrayAsync(cancellationToken));
}
/// <summary>

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

@ -5,6 +5,7 @@
*/
using System;
using System.Collections.Immutable;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
@ -236,14 +237,14 @@ namespace OpenIddict.EntityFrameworkCore
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the elements returned when executing the specified query.
/// </returns>
public override Task<TResult[]> ListAsync<TResult>([NotNull] Func<IQueryable<TApplication>, IQueryable<TResult>> query, CancellationToken cancellationToken)
public override async Task<ImmutableArray<TResult>> ListAsync<TResult>([NotNull] Func<IQueryable<TApplication>, IQueryable<TResult>> query, CancellationToken cancellationToken)
{
if (query == null)
{
throw new ArgumentNullException(nameof(query));
}
return query.Invoke(Applications).ToArrayAsync(cancellationToken);
return ImmutableArray.Create(await query.Invoke(Applications).ToArrayAsync(cancellationToken));
}
/// <summary>

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

@ -5,6 +5,7 @@
*/
using System;
using System.Collections.Immutable;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
@ -243,14 +244,14 @@ namespace OpenIddict.EntityFrameworkCore
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the elements returned when executing the specified query.
/// </returns>
public override Task<TResult[]> ListAsync<TResult>([NotNull] Func<IQueryable<TAuthorization>, IQueryable<TResult>> query, CancellationToken cancellationToken)
public override async Task<ImmutableArray<TResult>> ListAsync<TResult>([NotNull] Func<IQueryable<TAuthorization>, IQueryable<TResult>> query, CancellationToken cancellationToken)
{
if (query == null)
{
throw new ArgumentNullException(nameof(query));
}
return query.Invoke(Authorizations).ToArrayAsync(cancellationToken);
return ImmutableArray.Create(await query.Invoke(Authorizations).ToArrayAsync(cancellationToken));
}
/// <summary>

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

@ -5,6 +5,7 @@
*/
using System;
using System.Collections.Immutable;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
@ -186,14 +187,14 @@ namespace OpenIddict.EntityFrameworkCore
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the elements returned when executing the specified query.
/// </returns>
public override Task<TResult[]> ListAsync<TResult>([NotNull] Func<IQueryable<TScope>, IQueryable<TResult>> query, CancellationToken cancellationToken)
public override async Task<ImmutableArray<TResult>> ListAsync<TResult>([NotNull] Func<IQueryable<TScope>, IQueryable<TResult>> query, CancellationToken cancellationToken)
{
if (query == null)
{
throw new ArgumentNullException(nameof(query));
}
return query.Invoke(Scopes).ToArrayAsync(cancellationToken);
return ImmutableArray.Create(await query.Invoke(Scopes).ToArrayAsync(cancellationToken));
}
/// <summary>

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

@ -5,6 +5,7 @@
*/
using System;
using System.Collections.Immutable;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
@ -257,14 +258,14 @@ namespace OpenIddict.EntityFrameworkCore
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns all the elements returned when executing the specified query.
/// </returns>
public override Task<TResult[]> ListAsync<TResult>([NotNull] Func<IQueryable<TToken>, IQueryable<TResult>> query, CancellationToken cancellationToken)
public override async Task<ImmutableArray<TResult>> ListAsync<TResult>([NotNull] Func<IQueryable<TToken>, IQueryable<TResult>> query, CancellationToken cancellationToken)
{
if (query == null)
{
throw new ArgumentNullException(nameof(query));
}
return query.Invoke(Tokens).ToArrayAsync(cancellationToken);
return ImmutableArray.Create(await query.Invoke(Tokens).ToArrayAsync(cancellationToken));
}
/// <summary>

19
test/OpenIddict.Tests/OpenIddictProviderTests.Exchange.cs

@ -4,6 +4,7 @@
* the license and the contributors participating to this project.
*/
using System.Collections.Immutable;
using System.Security.Claims;
using System.Threading;
using System.Threading.Tasks;
@ -799,6 +800,9 @@ namespace OpenIddict.Tests
instance.Setup(mock => mock.IsRedeemedAsync(token, It.IsAny<CancellationToken>()))
.ReturnsAsync(true);
instance.Setup(mock => mock.FindByAuthorizationIdAsync("18D15F73-BE2B-6867-DC01-B3C1E8AFDED0", It.IsAny<CancellationToken>()))
.ReturnsAsync(ImmutableArray.Create<OpenIddictToken>());
}));
builder.Services.AddSingleton(manager);
@ -873,6 +877,9 @@ namespace OpenIddict.Tests
instance.Setup(mock => mock.IsRedeemedAsync(token, It.IsAny<CancellationToken>()))
.ReturnsAsync(true);
instance.Setup(mock => mock.FindByAuthorizationIdAsync("18D15F73-BE2B-6867-DC01-B3C1E8AFDED0", It.IsAny<CancellationToken>()))
.ReturnsAsync(ImmutableArray.Create<OpenIddictToken>());
}));
builder.Services.AddSingleton(manager);
@ -916,12 +923,10 @@ namespace OpenIddict.Tests
format.Setup(mock => mock.Unprotect("SplxlOBeZQQYbYS6WxSbIA"))
.Returns(ticket);
var tokens = new[]
{
var tokens = ImmutableArray.Create(
new OpenIddictToken(),
new OpenIddictToken(),
new OpenIddictToken()
};
new OpenIddictToken());
var manager = CreateTokenManager(instance =>
{
@ -1001,12 +1006,10 @@ namespace OpenIddict.Tests
format.Setup(mock => mock.Unprotect("8xLOxBtZp8"))
.Returns(ticket);
var tokens = new[]
{
var tokens = ImmutableArray.Create(
new OpenIddictToken(),
new OpenIddictToken(),
new OpenIddictToken()
};
new OpenIddictToken());
var manager = CreateTokenManager(instance =>
{

13
test/OpenIddict.Tests/OpenIddictProviderTests.Signin.cs

@ -5,6 +5,7 @@
*/
using System;
using System.Collections.Immutable;
using System.Security.Claims;
using System.Threading;
using System.Threading.Tasks;
@ -410,12 +411,10 @@ namespace OpenIddict.Tests
format.Setup(mock => mock.Unprotect("8xLOxBtZp8"))
.Returns(ticket);
var tokens = new[]
{
var tokens = ImmutableArray.Create(
new OpenIddictToken(),
new OpenIddictToken(),
new OpenIddictToken()
};
new OpenIddictToken());
var manager = CreateTokenManager(instance =>
{
@ -478,12 +477,10 @@ namespace OpenIddict.Tests
format.Setup(mock => mock.Unprotect("8xLOxBtZp8"))
.Returns(ticket);
var tokens = new[]
{
var tokens = ImmutableArray.Create(
new OpenIddictToken(),
new OpenIddictToken(),
new OpenIddictToken()
};
new OpenIddictToken());
var manager = CreateTokenManager(instance =>
{

Loading…
Cancel
Save