Browse Source

Update AddEntityFrameworkCoreStores() to infer the key type from the entity generic arguments

pull/294/head
Kévin Chalet 10 years ago
parent
commit
8355dd3210
  1. 4
      src/OpenIddict.Core/OpenIddictExtensions.cs
  2. 63
      src/OpenIddict.EntityFrameworkCore/OpenIddictExtensions.cs
  3. 4
      test/OpenIddict.Core.Tests/OpenIddictExtensionsTests.cs
  4. 104
      test/OpenIddict.EntityFrameworkCore.Tests/OpenIddictExtensionsTests.cs

4
src/OpenIddict.Core/OpenIddictExtensions.cs

@ -39,8 +39,8 @@ namespace Microsoft.Extensions.DependencyInjection {
throw new ArgumentNullException(nameof(services));
}
return services.AddOpenIddict<OpenIddictApplication<TKey, OpenIddictToken<TKey>>,
OpenIddictAuthorization<TKey, OpenIddictToken<TKey>>,
return services.AddOpenIddict<OpenIddictApplication<TKey>,
OpenIddictAuthorization<TKey>,
OpenIddictScope<TKey>,
OpenIddictToken<TKey>>();
}

63
src/OpenIddict.EntityFrameworkCore/OpenIddictExtensions.cs

@ -6,6 +6,7 @@
using System;
using System.Diagnostics;
using System.Reflection;
using JetBrains.Annotations;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
@ -24,18 +25,6 @@ namespace Microsoft.Extensions.DependencyInjection {
/// <returns>The <see cref="OpenIddictBuilder"/>.</returns>
public static OpenIddictBuilder AddEntityFrameworkCoreStores<TContext>([NotNull] this OpenIddictBuilder builder)
where TContext : DbContext {
return builder.AddEntityFrameworkCoreStores<TContext, string>();
}
/// <summary>
/// Registers the Entity Framework stores. Note: when using the built-in Entity Framework stores,
/// the entities MUST be derived from the models contained in the OpenIddict.Models package.
/// </summary>
/// <param name="builder">The services builder used by OpenIddict to register new services.</param>
/// <returns>The <see cref="OpenIddictBuilder"/>.</returns>
public static OpenIddictBuilder AddEntityFrameworkCoreStores<TContext, TKey>([NotNull] this OpenIddictBuilder builder)
where TContext : DbContext
where TKey : IEquatable<TKey> {
if (builder == null) {
throw new ArgumentNullException(nameof(builder));
}
@ -45,6 +34,30 @@ namespace Microsoft.Extensions.DependencyInjection {
builder.ScopeType != null &&
builder.TokenType != null, "The entity types exposed by OpenIddictBuilder shouldn't be null.");
var application = FindGenericBaseType(builder.ApplicationType, typeof(OpenIddictApplication<,>));
if (application == null) {
throw new InvalidOperationException("The Entity Framework stores can only be used " +
"with the built-in OpenIddictApplication entity.");
}
var authorization = FindGenericBaseType(builder.AuthorizationType, typeof(OpenIddictAuthorization<,>));
if (authorization == null) {
throw new InvalidOperationException("The Entity Framework stores can only be used " +
"with the built-in OpenIddictAuthorization entity.");
}
var scope = FindGenericBaseType(builder.ScopeType, typeof(OpenIddictScope<>));
if (scope == null) {
throw new InvalidOperationException("The Entity Framework stores can only be used " +
"with the built-in OpenIddictScope entity.");
}
var token = FindGenericBaseType(builder.TokenType, typeof(OpenIddictToken<>));
if (token == null) {
throw new InvalidOperationException("The Entity Framework stores can only be used " +
"with the built-in OpenIddictToken entity.");
}
// Register the application store in the DI container.
builder.Services.TryAddScoped(
typeof(IOpenIddictApplicationStore<>).MakeGenericType(builder.ApplicationType),
@ -52,7 +65,7 @@ namespace Microsoft.Extensions.DependencyInjection {
/* TApplication: */ builder.ApplicationType,
/* TToken: */ builder.TokenType,
/* TContext: */ typeof(TContext),
/* TKey: */ typeof(TKey)));
/* TKey: */ application.GenericTypeArguments[0]));
// Register the authorization store in the DI container.
builder.Services.TryAddScoped(
@ -61,7 +74,7 @@ namespace Microsoft.Extensions.DependencyInjection {
/* TAuthorization: */ builder.AuthorizationType,
/* TToken: */ builder.TokenType,
/* TContext: */ typeof(TContext),
/* TKey: */ typeof(TKey)));
/* TKey: */ authorization.GenericTypeArguments[0]));
// Register the scope store in the DI container.
builder.Services.TryAddScoped(
@ -69,7 +82,7 @@ namespace Microsoft.Extensions.DependencyInjection {
typeof(OpenIddictScopeStore<,,>).MakeGenericType(
/* TScope: */ builder.ScopeType,
/* TContext: */ typeof(TContext),
/* TKey: */ typeof(TKey)));
/* TKey: */ scope.GenericTypeArguments[0]));
// Register the token store in the DI container.
builder.Services.TryAddScoped(
@ -78,7 +91,7 @@ namespace Microsoft.Extensions.DependencyInjection {
/* TToken: */ builder.TokenType,
/* TAuthorization: */ builder.AuthorizationType,
/* TContext: */ typeof(TContext),
/* TKey: */ typeof(TKey)));
/* TKey: */ token.GenericTypeArguments[0]));
return builder;
}
@ -100,8 +113,8 @@ namespace Microsoft.Extensions.DependencyInjection {
/// <param name="builder">The builder used to configure the Entity Framework context.</param>
/// <returns>The Entity Framework context builder.</returns>
public static DbContextOptionsBuilder UseOpenIddict<TKey>([NotNull] this DbContextOptionsBuilder builder) where TKey : IEquatable<TKey> {
return builder.UseOpenIddict<OpenIddictApplication<TKey, OpenIddictToken<TKey>>,
OpenIddictAuthorization<TKey, OpenIddictToken<TKey>>,
return builder.UseOpenIddict<OpenIddictApplication<TKey>,
OpenIddictAuthorization<TKey>,
OpenIddictScope<TKey>,
OpenIddictToken<TKey>, TKey>();
}
@ -145,8 +158,8 @@ namespace Microsoft.Extensions.DependencyInjection {
/// <param name="builder">The builder used to configure the Entity Framework context.</param>
/// <returns>The Entity Framework context builder.</returns>
public static ModelBuilder UseOpenIddict<TKey>([NotNull] this ModelBuilder builder) where TKey : IEquatable<TKey> {
return builder.UseOpenIddict<OpenIddictApplication<TKey, OpenIddictToken<TKey>>,
OpenIddictAuthorization<TKey, OpenIddictToken<TKey>>,
return builder.UseOpenIddict<OpenIddictApplication<TKey>,
OpenIddictAuthorization<TKey>,
OpenIddictScope<TKey>,
OpenIddictToken<TKey>, TKey>();
}
@ -214,5 +227,15 @@ namespace Microsoft.Extensions.DependencyInjection {
return builder;
}
private static TypeInfo FindGenericBaseType(Type type, Type definition) {
for (var candidate = type.GetTypeInfo(); candidate != null; candidate = candidate.BaseType?.GetTypeInfo()) {
if (candidate.IsGenericType && candidate.GetGenericTypeDefinition() == definition) {
return candidate;
}
}
return null;
}
}
}

4
test/OpenIddict.Core.Tests/OpenIddictExtensionsTests.cs

@ -22,8 +22,8 @@ namespace OpenIddict.Core.Tests {
}
[Theory]
[InlineData(typeof(OpenIddictApplicationManager<OpenIddictApplication<Guid, OpenIddictToken<Guid>>>))]
[InlineData(typeof(OpenIddictAuthorizationManager<OpenIddictAuthorization<Guid, OpenIddictToken<Guid>>>))]
[InlineData(typeof(OpenIddictApplicationManager<OpenIddictApplication<Guid>>))]
[InlineData(typeof(OpenIddictAuthorizationManager<OpenIddictAuthorization<Guid>>))]
[InlineData(typeof(OpenIddictScopeManager<OpenIddictScope<Guid>>))]
[InlineData(typeof(OpenIddictTokenManager<OpenIddictToken<Guid>>))]
public void AddOpenIddict_KeyTypeCanBeOverriden(Type type) {

104
test/OpenIddict.EntityFrameworkCore.Tests/OpenIddictExtensionsTests.cs

@ -6,38 +6,120 @@ using Xunit;
namespace OpenIddict.EntityFrameworkCore.Tests {
public class OpenIddictExtensionsTests {
[Fact]
public void AddEntityFrameworkCoreStores_ThrowsAnExceptionForInvalidApplicationEntity() {
// Arrange
var services = new ServiceCollection();
// Act and assert
var exception = Assert.Throws<InvalidOperationException>(delegate {
services.AddOpenIddict<object, OpenIddictAuthorization, OpenIddictScope, OpenIddictToken>()
.AddEntityFrameworkCoreStores<DbContext>();
});
Assert.Equal("The Entity Framework stores can only be used " +
"with the built-in OpenIddictApplication entity.", exception.Message);
}
[Fact]
public void AddEntityFrameworkCoreStores_ThrowsAnExceptionForInvalidAuthorizationEntity() {
// Arrange
var services = new ServiceCollection();
// Act and assert
var exception = Assert.Throws<InvalidOperationException>(delegate {
services.AddOpenIddict<OpenIddictApplication, object, OpenIddictScope, OpenIddictToken>()
.AddEntityFrameworkCoreStores<DbContext>();
});
Assert.Equal("The Entity Framework stores can only be used " +
"with the built-in OpenIddictAuthorization entity.", exception.Message);
}
[Fact]
public void AddEntityFrameworkCoreStores_ThrowsAnExceptionForInvalidScopeEntity() {
// Arrange
var services = new ServiceCollection();
// Act and assert
var exception = Assert.Throws<InvalidOperationException>(delegate {
services.AddOpenIddict<OpenIddictApplication, OpenIddictAuthorization, object, OpenIddictToken>()
.AddEntityFrameworkCoreStores<DbContext>();
});
Assert.Equal("The Entity Framework stores can only be used " +
"with the built-in OpenIddictScope entity.", exception.Message);
}
[Fact]
public void AddEntityFrameworkCoreStores_ThrowsAnExceptionForInvalidTokenEntity() {
// Arrange
var services = new ServiceCollection();
// Act and assert
var exception = Assert.Throws<InvalidOperationException>(delegate {
services.AddOpenIddict<OpenIddictApplication, OpenIddictAuthorization, OpenIddictScope, object>()
.AddEntityFrameworkCoreStores<DbContext>();
});
Assert.Equal("The Entity Framework stores can only be used " +
"with the built-in OpenIddictToken entity.", exception.Message);
}
[Theory]
[InlineData(typeof(OpenIddictApplicationStore<OpenIddictApplication<Guid, OpenIddictToken<Guid>>, OpenIddictToken<Guid>, DbContext, Guid>))]
[InlineData(typeof(OpenIddictAuthorizationStore<OpenIddictAuthorization<Guid, OpenIddictToken<Guid>>, OpenIddictToken<Guid>, DbContext, Guid>))]
[InlineData(typeof(OpenIddictScopeStore<OpenIddictScope<Guid>, DbContext, Guid>))]
[InlineData(typeof(OpenIddictTokenStore<OpenIddictToken<Guid>, OpenIddictAuthorization<Guid, OpenIddictToken<Guid>>, DbContext, Guid>))]
[InlineData(typeof(OpenIddictApplicationStore<OpenIddictApplication, OpenIddictToken, DbContext, string>))]
[InlineData(typeof(OpenIddictAuthorizationStore<OpenIddictAuthorization, OpenIddictToken, DbContext, string>))]
[InlineData(typeof(OpenIddictScopeStore<OpenIddictScope, DbContext, string>))]
[InlineData(typeof(OpenIddictTokenStore<OpenIddictToken, OpenIddictAuthorization, DbContext, string>))]
public void AddEntityFrameworkCoreStores_RegistersEntityFrameworkStores(Type type) {
// Arrange
var services = new ServiceCollection();
// Act
services.AddOpenIddict()
.AddEntityFrameworkCoreStores<DbContext>();
// Assert
Assert.Contains(services, service => service.ImplementationType == type);
}
[Theory]
[InlineData(typeof(OpenIddictApplicationStore<OpenIddictApplication<Guid>, OpenIddictToken<Guid>, DbContext, Guid>))]
[InlineData(typeof(OpenIddictAuthorizationStore<OpenIddictAuthorization<Guid>, OpenIddictToken<Guid>, DbContext, Guid>))]
[InlineData(typeof(OpenIddictScopeStore<OpenIddictScope<Guid>, DbContext, Guid>))]
[InlineData(typeof(OpenIddictTokenStore<OpenIddictToken<Guid>, OpenIddictAuthorization<Guid>, DbContext, Guid>))]
public void AddEntityFrameworkCoreStores_KeyTypeIsInferredFromEntities(Type type) {
// Arrange
var services = new ServiceCollection();
// Act
services.AddOpenIddict<Guid>()
.AddEntityFrameworkCoreStores<DbContext, Guid>();
.AddEntityFrameworkCoreStores<DbContext>();
// Assert
Assert.Contains(services, service => service.ImplementationType == type);
}
[Theory]
[InlineData(typeof(OpenIddictApplicationStore<OpenIddictApplication, OpenIddictToken, DbContext, string>))]
[InlineData(typeof(OpenIddictAuthorizationStore<OpenIddictAuthorization, OpenIddictToken, DbContext, string>))]
[InlineData(typeof(OpenIddictScopeStore<OpenIddictScope, DbContext, string>))]
[InlineData(typeof(OpenIddictTokenStore<OpenIddictToken, OpenIddictAuthorization, DbContext, string>))]
public void AddEntityFrameworkCoreStores_KeyTypeDefaultsToString(Type type) {
[InlineData(typeof(OpenIddictApplicationStore<CustomApplication, CustomToken, DbContext, long>))]
[InlineData(typeof(OpenIddictAuthorizationStore<CustomAuthorization, CustomToken, DbContext, long>))]
[InlineData(typeof(OpenIddictScopeStore<CustomScope, DbContext, long>))]
[InlineData(typeof(OpenIddictTokenStore<CustomToken, CustomAuthorization, DbContext, long>))]
public void AddEntityFrameworkCoreStores_DefaultEntitiesCanBeReplaced(Type type) {
// Arrange
var services = new ServiceCollection();
// Act
services.AddOpenIddict()
services.AddOpenIddict<CustomApplication, CustomAuthorization, CustomScope, CustomToken>()
.AddEntityFrameworkCoreStores<DbContext>();
// Assert
Assert.Contains(services, service => service.ImplementationType == type);
}
public class CustomApplication : OpenIddictApplication<long, CustomToken> { }
public class CustomAuthorization : OpenIddictAuthorization<long, CustomToken> { }
public class CustomScope : OpenIddictScope<long> { }
public class CustomToken : OpenIddictToken<long> { }
}
}

Loading…
Cancel
Save