Browse Source

Optimize OpenIddictMongoDbContext to avoid using an async state machine when the database was already instantiated

pull/615/merge
Kévin Chalet 8 years ago
parent
commit
2433e750c4
  1. 103
      src/OpenIddict.MongoDb/OpenIddictMongoDbContext.cs
  2. 3
      src/OpenIddict.MongoDb/Stores/OpenIddictApplicationStore.cs
  3. 3
      src/OpenIddict.MongoDb/Stores/OpenIddictAuthorizationStore.cs
  4. 3
      src/OpenIddict.MongoDb/Stores/OpenIddictScopeStore.cs
  5. 3
      src/OpenIddict.MongoDb/Stores/OpenIddictTokenStore.cs

103
src/OpenIddict.MongoDb/OpenIddictMongoDbContext.cs

@ -40,69 +40,74 @@ namespace OpenIddict.MongoDb
/// A <see cref="ValueTask{TResult}"/> that can be used to monitor the
/// asynchronous operation, whose result returns the MongoDB database.
/// </returns>
public async ValueTask<IMongoDatabase> GetDatabaseAsync(CancellationToken cancellationToken)
public ValueTask<IMongoDatabase> GetDatabaseAsync(CancellationToken cancellationToken)
{
if (_database != null)
{
return _database;
return new ValueTask<IMongoDatabase>(_database);
}
var options = _options.CurrentValue;
if (options == null)
async Task<IMongoDatabase> ExecuteAsync()
{
throw new InvalidOperationException("The OpenIddict MongoDB options cannot be retrieved.");
}
var database = options.Database;
if (database == null)
{
database = _provider.GetService<IMongoDatabase>();
}
var options = _options.CurrentValue;
if (options == null)
{
throw new InvalidOperationException("The OpenIddict MongoDB options cannot be retrieved.");
}
if (database == null)
{
throw new InvalidOperationException(new StringBuilder()
.AppendLine("No suitable MongoDB database service can be found.")
.Append("To configure the OpenIddict MongoDB stores to use a specific database, use ")
.Append("'services.AddOpenIddict().AddCore().UseMongoDb().UseDatabase()' or register an ")
.Append("'IMongoDatabase' in the dependency injection container in 'ConfigureServices()'.")
.ToString());
}
var database = options.Database;
if (database == null)
{
database = _provider.GetService<IMongoDatabase>();
}
// Note: the cancellation token passed as a parameter is deliberately not used here to ensure
// the cancellation of a single store operation doesn't prevent the indexes from being created.
var applications = database.GetCollection<OpenIddictApplication>(options.ApplicationsCollectionName);
await applications.Indexes.CreateOneAsync(
Builders<OpenIddictApplication>.IndexKeys.Ascending(application => application.ClientId),
new CreateIndexOptions
if (database == null)
{
Unique = true
});
throw new InvalidOperationException(new StringBuilder()
.AppendLine("No suitable MongoDB database service can be found.")
.Append("To configure the OpenIddict MongoDB stores to use a specific database, use ")
.Append("'services.AddOpenIddict().AddCore().UseMongoDb().UseDatabase()' or register an ")
.Append("'IMongoDatabase' in the dependency injection container in 'ConfigureServices()'.")
.ToString());
}
await applications.Indexes.CreateOneAsync(
Builders<OpenIddictApplication>.IndexKeys.Ascending(application => application.PostLogoutRedirectUris));
// Note: the cancellation token passed as a parameter is deliberately not used here to ensure
// the cancellation of a single store operation doesn't prevent the indexes from being created.
var applications = database.GetCollection<OpenIddictApplication>(options.ApplicationsCollectionName);
await applications.Indexes.CreateOneAsync(
Builders<OpenIddictApplication>.IndexKeys.Ascending(application => application.ClientId),
new CreateIndexOptions
{
Unique = true
});
await applications.Indexes.CreateOneAsync(
Builders<OpenIddictApplication>.IndexKeys.Ascending(application => application.RedirectUris));
await applications.Indexes.CreateOneAsync(
Builders<OpenIddictApplication>.IndexKeys.Ascending(application => application.PostLogoutRedirectUris));
var scopes = database.GetCollection<OpenIddictScope>(options.ScopesCollectionName);
await scopes.Indexes.CreateOneAsync(
Builders<OpenIddictScope>.IndexKeys.Ascending(scope => scope.Name),
new CreateIndexOptions
{
Unique = true
});
await applications.Indexes.CreateOneAsync(
Builders<OpenIddictApplication>.IndexKeys.Ascending(application => application.RedirectUris));
var tokens = database.GetCollection<OpenIddictToken>(options.TokensCollectionName);
await tokens.Indexes.CreateOneAsync(
Builders<OpenIddictToken>.IndexKeys.Ascending(token => token.ReferenceId),
new CreateIndexOptions<OpenIddictToken>
{
PartialFilterExpression = Builders<OpenIddictToken>.Filter.Exists(token => token.ReferenceId),
Unique = true
});
var scopes = database.GetCollection<OpenIddictScope>(options.ScopesCollectionName);
await scopes.Indexes.CreateOneAsync(
Builders<OpenIddictScope>.IndexKeys.Ascending(scope => scope.Name),
new CreateIndexOptions
{
Unique = true
});
var tokens = database.GetCollection<OpenIddictToken>(options.TokensCollectionName);
await tokens.Indexes.CreateOneAsync(
Builders<OpenIddictToken>.IndexKeys.Ascending(token => token.ReferenceId),
new CreateIndexOptions<OpenIddictToken>
{
PartialFilterExpression = Builders<OpenIddictToken>.Filter.Exists(token => token.ReferenceId),
Unique = true
});
return _database = database;
}
return _database = database;
return new ValueTask<IMongoDatabase>(ExecuteAsync());
}
}
}

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

@ -794,6 +794,7 @@ namespace OpenIddict.MongoDb
// Generate a new concurrency token and attach it
// to the application before persisting the changes.
var timestamp = application.ConcurrencyToken;
application.ConcurrencyToken = Guid.NewGuid().ToString();
var database = await Context.GetDatabaseAsync(cancellationToken);
@ -801,7 +802,7 @@ namespace OpenIddict.MongoDb
if ((await collection.ReplaceOneAsync(entity =>
entity.Id == application.Id &&
entity.ConcurrencyToken == application.ConcurrencyToken, application, null, cancellationToken)).MatchedCount == 0)
entity.ConcurrencyToken == timestamp, application, null, cancellationToken)).MatchedCount == 0)
{
throw new OpenIddictException(OpenIddictConstants.Exceptions.ConcurrencyError, new StringBuilder()
.AppendLine("The application was concurrently updated and cannot be persisted in its current state.")

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

@ -745,6 +745,7 @@ namespace OpenIddict.MongoDb
// Generate a new concurrency token and attach it
// to the authorization before persisting the changes.
var timestamp = authorization.ConcurrencyToken;
authorization.ConcurrencyToken = Guid.NewGuid().ToString();
var database = await Context.GetDatabaseAsync(cancellationToken);
@ -752,7 +753,7 @@ namespace OpenIddict.MongoDb
if ((await collection.ReplaceOneAsync(entity =>
entity.Id == authorization.Id &&
entity.ConcurrencyToken == authorization.ConcurrencyToken, authorization, null, cancellationToken)).MatchedCount == 0)
entity.ConcurrencyToken == timestamp, authorization, null, cancellationToken)).MatchedCount == 0)
{
throw new OpenIddictException(OpenIddictConstants.Exceptions.ConcurrencyError, new StringBuilder()
.AppendLine("The authorization was concurrently updated and cannot be persisted in its current state.")

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

@ -591,6 +591,7 @@ namespace OpenIddict.MongoDb
// Generate a new concurrency token and attach it
// to the scope before persisting the changes.
var timestamp = scope.ConcurrencyToken;
scope.ConcurrencyToken = Guid.NewGuid().ToString();
var database = await Context.GetDatabaseAsync(cancellationToken);
@ -598,7 +599,7 @@ namespace OpenIddict.MongoDb
if ((await collection.ReplaceOneAsync(entity =>
entity.Id == scope.Id &&
entity.ConcurrencyToken == scope.ConcurrencyToken, scope, null, cancellationToken)).MatchedCount == 0)
entity.ConcurrencyToken == timestamp, scope, null, cancellationToken)).MatchedCount == 0)
{
throw new OpenIddictException(OpenIddictConstants.Exceptions.ConcurrencyError, new StringBuilder()
.AppendLine("The scope was concurrently updated and cannot be persisted in its current state.")

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

@ -855,6 +855,7 @@ namespace OpenIddict.MongoDb
// Generate a new concurrency token and attach it
// to the token before persisting the changes.
var timestamp = token.ConcurrencyToken;
token.ConcurrencyToken = Guid.NewGuid().ToString();
var database = await Context.GetDatabaseAsync(cancellationToken);
@ -862,7 +863,7 @@ namespace OpenIddict.MongoDb
if ((await collection.ReplaceOneAsync(entity =>
entity.Id == token.Id &&
entity.ConcurrencyToken == token.ConcurrencyToken, token, null, cancellationToken)).MatchedCount == 0)
entity.ConcurrencyToken == timestamp, token, null, cancellationToken)).MatchedCount == 0)
{
throw new OpenIddictException(OpenIddictConstants.Exceptions.ConcurrencyError, new StringBuilder()
.AppendLine("The token was concurrently updated and cannot be persisted in its current state.")

Loading…
Cancel
Save