Browse Source

Move the OpenIddict entities mappings to separate IEntityTypeConfiguration instances

pull/649/head
Kévin Chalet 8 years ago
parent
commit
5a37afb116
  1. 72
      src/OpenIddict.EntityFramework/Configurations/OpenIddictApplicationConfiguration.cs
  2. 68
      src/OpenIddict.EntityFramework/Configurations/OpenIddictAuthorizationConfiguration.cs
  3. 57
      src/OpenIddict.EntityFramework/Configurations/OpenIddictScopeConfiguration.cs
  4. 66
      src/OpenIddict.EntityFramework/Configurations/OpenIddictTokenConfiguration.cs
  5. 152
      src/OpenIddict.EntityFramework/OpenIddictEntityFrameworkExtensions.cs
  6. 67
      src/OpenIddict.EntityFrameworkCore/Configurations/OpenIddictApplicationConfiguration.cs
  7. 62
      src/OpenIddict.EntityFrameworkCore/Configurations/OpenIddictAuthorizationConfiguration.cs
  8. 50
      src/OpenIddict.EntityFrameworkCore/Configurations/OpenIddictScopeConfiguration.cs
  9. 57
      src/OpenIddict.EntityFrameworkCore/Configurations/OpenIddictTokenConfiguration.cs
  10. 2
      src/OpenIddict.EntityFrameworkCore/OpenIddictEntityFrameworkCoreCustomizer.cs
  11. 119
      src/OpenIddict.EntityFrameworkCore/OpenIddictEntityFrameworkCoreExtensions.cs
  12. 68
      test/OpenIddict.EntityFrameworkCore.Tests/OpenIddictEntityFrameworkCoreExtensionsTests.cs

72
src/OpenIddict.EntityFramework/Configurations/OpenIddictApplicationConfiguration.cs

@ -0,0 +1,72 @@
/*
* Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
* See https://github.com/openiddict/openiddict-core for more information concerning
* the license and the contributors participating to this project.
*/
using System;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity.Infrastructure.Annotations;
using System.Data.Entity.ModelConfiguration;
using System.Text;
using OpenIddict.EntityFramework.Models;
namespace OpenIddict.EntityFramework
{
/// <summary>
/// Defines a relational mapping for the Application entity.
/// </summary>
/// <typeparam name="TApplication">The type of the Application entity.</typeparam>
/// <typeparam name="TAuthorization">The type of the Authorization entity.</typeparam>
/// <typeparam name="TToken">The type of the Token entity.</typeparam>
/// <typeparam name="TKey">The type of the Key entity.</typeparam>
[EditorBrowsable(EditorBrowsableState.Never)]
public class OpenIddictApplicationConfiguration<TApplication, TAuthorization, TToken, TKey> : EntityTypeConfiguration<TApplication>
where TApplication : OpenIddictApplication<TKey, TAuthorization, TToken>
where TAuthorization : OpenIddictAuthorization<TKey, TApplication, TToken>
where TToken : OpenIddictToken<TKey, TApplication, TAuthorization>
where TKey : IEquatable<TKey>
{
public OpenIddictApplicationConfiguration()
{
// Note: unlike Entity Framework Core 1.x/2.x, Entity Framework 6.x
// always throws an exception when using generic types as entity types.
// To ensure a better exception is thrown, a manual check is made here.
if (typeof(TApplication).IsGenericType)
{
throw new InvalidOperationException(new StringBuilder()
.AppendLine("The application entity cannot be a generic type.")
.Append("Consider creating a non-generic derived class.")
.ToString());
}
// Warning: optional foreign keys MUST NOT be added as CLR properties because
// Entity Framework would throw an exception due to the TKey generic parameter
// being non-nullable when using value types like short, int, long or Guid.
HasKey(application => application.Id);
Property(application => application.ClientId)
.IsRequired()
.HasMaxLength(450)
.HasColumnAnnotation(IndexAnnotation.AnnotationName, new IndexAnnotation(new IndexAttribute()));
Property(application => application.ConcurrencyToken)
.IsConcurrencyToken();
Property(application => application.Type)
.IsRequired();
HasMany(application => application.Authorizations)
.WithOptional(authorization => authorization.Application)
.Map(association => association.MapKey("ApplicationId"));
HasMany(application => application.Tokens)
.WithOptional(token => token.Application)
.Map(association => association.MapKey("ApplicationId"));
ToTable("OpenIddictApplications");
}
}
}

68
src/OpenIddict.EntityFramework/Configurations/OpenIddictAuthorizationConfiguration.cs

@ -0,0 +1,68 @@
/*
* Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
* See https://github.com/openiddict/openiddict-core for more information concerning
* the license and the contributors participating to this project.
*/
using System;
using System.ComponentModel;
using System.Data.Entity.ModelConfiguration;
using System.Text;
using OpenIddict.EntityFramework.Models;
namespace OpenIddict.EntityFramework
{
/// <summary>
/// Defines a relational mapping for the Authorization entity.
/// </summary>
/// <typeparam name="TAuthorization">The type of the Authorization entity.</typeparam>
/// <typeparam name="TApplication">The type of the Application entity.</typeparam>
/// <typeparam name="TToken">The type of the Token entity.</typeparam>
/// <typeparam name="TKey">The type of the Key entity.</typeparam>
[EditorBrowsable(EditorBrowsableState.Never)]
public class OpenIddictAuthorizationConfiguration<TAuthorization, TApplication, TToken, TKey> : EntityTypeConfiguration<TAuthorization>
where TAuthorization : OpenIddictAuthorization<TKey, TApplication, TToken>
where TApplication : OpenIddictApplication<TKey, TAuthorization, TToken>
where TToken : OpenIddictToken<TKey, TApplication, TAuthorization>
where TKey : IEquatable<TKey>
{
public OpenIddictAuthorizationConfiguration()
{
// Note: unlike Entity Framework Core 1.x/2.x, Entity Framework 6.x
// always throws an exception when using generic types as entity types.
// To ensure a better exception is thrown, a manual check is made here.
if (typeof(TAuthorization).IsGenericType)
{
throw new InvalidOperationException(new StringBuilder()
.AppendLine("The authorization entity cannot be a generic type.")
.Append("Consider creating a non-generic derived class.")
.ToString());
}
// Warning: optional foreign keys MUST NOT be added as CLR properties because
// Entity Framework would throw an exception due to the TKey generic parameter
// being non-nullable when using value types like short, int, long or Guid.
HasKey(authorization => authorization.Id);
Property(authorization => authorization.ConcurrencyToken)
.IsConcurrencyToken();
Property(authorization => authorization.Status)
.IsRequired();
Property(authorization => authorization.Subject)
.IsRequired();
Property(authorization => authorization.Type)
.IsRequired();
HasMany(authorization => authorization.Tokens)
.WithOptional(token => token.Authorization)
.Map(association => association.MapKey("AuthorizationId"))
.WillCascadeOnDelete();
ToTable("OpenIddictAuthorizations");
}
}
}

57
src/OpenIddict.EntityFramework/Configurations/OpenIddictScopeConfiguration.cs

@ -0,0 +1,57 @@
/*
* Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
* See https://github.com/openiddict/openiddict-core for more information concerning
* the license and the contributors participating to this project.
*/
using System;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity.Infrastructure.Annotations;
using System.Data.Entity.ModelConfiguration;
using System.Text;
using OpenIddict.EntityFramework.Models;
namespace OpenIddict.EntityFramework
{
/// <summary>
/// Defines a relational mapping for the Scope entity.
/// </summary>
/// <typeparam name="TScope">The type of the Scope entity.</typeparam>
/// <typeparam name="TKey">The type of the Key entity.</typeparam>
[EditorBrowsable(EditorBrowsableState.Never)]
public class OpenIddictScopeConfiguration<TScope, TKey> : EntityTypeConfiguration<TScope>
where TScope : OpenIddictScope<TKey>
where TKey : IEquatable<TKey>
{
public OpenIddictScopeConfiguration()
{
// Note: unlike Entity Framework Core 1.x/2.x, Entity Framework 6.x
// always throws an exception when using generic types as entity types.
// To ensure a better exception is thrown, a manual check is made here.
if (typeof(TScope).IsGenericType)
{
throw new InvalidOperationException(new StringBuilder()
.AppendLine("The scope entity cannot be a generic type.")
.Append("Consider creating a non-generic derived class.")
.ToString());
}
// Warning: optional foreign keys MUST NOT be added as CLR properties because
// Entity Framework would throw an exception due to the TKey generic parameter
// being non-nullable when using value types like short, int, long or Guid.
HasKey(scope => scope.Id);
Property(scope => scope.ConcurrencyToken)
.IsConcurrencyToken();
Property(scope => scope.Name)
.IsRequired()
.HasMaxLength(450)
.HasColumnAnnotation(IndexAnnotation.AnnotationName, new IndexAnnotation(new IndexAttribute()));
ToTable("OpenIddictScopes");
}
}
}

66
src/OpenIddict.EntityFramework/Configurations/OpenIddictTokenConfiguration.cs

@ -0,0 +1,66 @@
/*
* Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
* See https://github.com/openiddict/openiddict-core for more information concerning
* the license and the contributors participating to this project.
*/
using System;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity.Infrastructure.Annotations;
using System.Data.Entity.ModelConfiguration;
using System.Text;
using OpenIddict.EntityFramework.Models;
namespace OpenIddict.EntityFramework
{
/// <summary>
/// Defines a relational mapping for the Token entity.
/// </summary>
/// <typeparam name="TToken">The type of the Token entity.</typeparam>
/// <typeparam name="TApplication">The type of the Application entity.</typeparam>
/// <typeparam name="TAuthorization">The type of the Authorization entity.</typeparam>
/// <typeparam name="TKey">The type of the Key entity.</typeparam>
[EditorBrowsable(EditorBrowsableState.Never)]
public class OpenIddictTokenConfiguration<TToken, TApplication, TAuthorization, TKey> : EntityTypeConfiguration<TToken>
where TToken : OpenIddictToken<TKey, TApplication, TAuthorization>
where TApplication : OpenIddictApplication<TKey, TAuthorization, TToken>
where TAuthorization : OpenIddictAuthorization<TKey, TApplication, TToken>
where TKey : IEquatable<TKey>
{
public OpenIddictTokenConfiguration()
{
// Note: unlike Entity Framework Core 1.x/2.x, Entity Framework 6.x
// always throws an exception when using generic types as entity types.
// To ensure a better exception is thrown, a manual check is made here.
if (typeof(TToken).IsGenericType)
{
throw new InvalidOperationException(new StringBuilder()
.AppendLine("The token entity cannot be a generic type.")
.Append("Consider creating a non-generic derived class.")
.ToString());
}
// Warning: optional foreign keys MUST NOT be added as CLR properties because
// Entity Framework would throw an exception due to the TKey generic parameter
// being non-nullable when using value types like short, int, long or Guid.
HasKey(token => token.Id);
Property(token => token.ConcurrencyToken)
.IsConcurrencyToken();
Property(token => token.ReferenceId)
.HasMaxLength(450)
.HasColumnAnnotation(IndexAnnotation.AnnotationName, new IndexAnnotation(new IndexAttribute()));
Property(token => token.Subject)
.IsRequired();
Property(token => token.Type)
.IsRequired();
ToTable("OpenIddictTokens");
}
}
}

152
src/OpenIddict.EntityFramework/OpenIddictEntityFrameworkExtensions.cs

@ -5,10 +5,7 @@
*/
using System;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity;
using System.Data.Entity.Infrastructure.Annotations;
using System.Text;
using JetBrains.Annotations;
using Microsoft.Extensions.DependencyInjection.Extensions;
using OpenIddict.EntityFramework;
@ -80,7 +77,7 @@ namespace Microsoft.Extensions.DependencyInjection
}
/// <summary>
/// Registers the OpenIddict entity sets in the Entity Framework context
/// Registers the OpenIddict entity sets in the Entity Framework 6.x context
/// using the default OpenIddict models and the default key type (string).
/// </summary>
/// <param name="builder">The builder used to configure the Entity Framework context.</param>
@ -92,8 +89,8 @@ namespace Microsoft.Extensions.DependencyInjection
OpenIddictToken, string>();
/// <summary>
/// Registers the OpenIddict entity sets in the Entity Framework context
/// using the specified entities and the specified key type.
/// Registers the OpenIddict entity sets in the Entity Framework 6.x
/// context using the specified entities and the specified key type.
/// Note: using this method requires creating non-generic derived classes
/// for all the OpenIddict entities (application, authorization, scope, token).
/// </summary>
@ -111,145 +108,10 @@ namespace Microsoft.Extensions.DependencyInjection
throw new ArgumentNullException(nameof(builder));
}
// Note: unlike Entity Framework 6.x 1.x/2.x, Entity Framework 6.x
// always throws an exception when using generic types as entity types.
// To ensure a better exception is thrown, a manual check is made here.
if (typeof(TApplication).IsGenericType)
{
throw new InvalidOperationException(new StringBuilder()
.AppendLine("The application entity cannot be a generic type.")
.Append("Consider creating a non-generic derived class.")
.ToString());
}
if (typeof(TAuthorization).IsGenericType)
{
throw new InvalidOperationException(new StringBuilder()
.AppendLine("The authorization entity cannot be a generic type.")
.Append("Consider creating a non-generic derived class.")
.ToString());
}
if (typeof(TScope).IsGenericType)
{
throw new InvalidOperationException(new StringBuilder()
.AppendLine("The scope entity cannot be a generic type.")
.Append("Consider creating a non-generic derived class.")
.ToString());
}
if (typeof(TToken).IsGenericType)
{
throw new InvalidOperationException(new StringBuilder()
.AppendLine("The token entity cannot be a generic type.")
.Append("Consider creating a non-generic derived class.")
.ToString());
}
// Warning: optional foreign keys MUST NOT be added as CLR properties because
// Entity Framework would throw an exception due to the TKey generic parameter
// being non-nullable when using value types like short, int, long or Guid.
// Configure the TApplication entity.
builder.Entity<TApplication>()
.HasKey(application => application.Id);
builder.Entity<TApplication>()
.Property(application => application.ClientId)
.IsRequired()
.HasMaxLength(450)
.HasColumnAnnotation(IndexAnnotation.AnnotationName, new IndexAnnotation(new IndexAttribute()));
builder.Entity<TApplication>()
.Property(application => application.ConcurrencyToken)
.IsConcurrencyToken();
builder.Entity<TApplication>()
.Property(application => application.Type)
.IsRequired();
builder.Entity<TApplication>()
.HasMany(application => application.Authorizations)
.WithOptional(authorization => authorization.Application)
.Map(association => association.MapKey("ApplicationId"));
builder.Entity<TApplication>()
.HasMany(application => application.Tokens)
.WithOptional(token => token.Application)
.Map(association => association.MapKey("ApplicationId"));
builder.Entity<TApplication>()
.ToTable("OpenIddictApplications");
// Configure the TAuthorization entity.
builder.Entity<TAuthorization>()
.HasKey(authorization => authorization.Id);
builder.Entity<TAuthorization>()
.Property(authorization => authorization.ConcurrencyToken)
.IsConcurrencyToken();
builder.Entity<TAuthorization>()
.Property(authorization => authorization.Status)
.IsRequired();
builder.Entity<TAuthorization>()
.Property(authorization => authorization.Subject)
.IsRequired();
builder.Entity<TAuthorization>()
.Property(authorization => authorization.Type)
.IsRequired();
builder.Entity<TAuthorization>()
.HasMany(application => application.Tokens)
.WithOptional(token => token.Authorization)
.Map(association => association.MapKey("AuthorizationId"))
.WillCascadeOnDelete();
builder.Entity<TAuthorization>()
.ToTable("OpenIddictAuthorizations");
// Configure the TScope entity.
builder.Entity<TScope>()
.HasKey(scope => scope.Id);
builder.Entity<TScope>()
.Property(scope => scope.ConcurrencyToken)
.IsConcurrencyToken();
builder.Entity<TScope>()
.Property(scope => scope.Name)
.IsRequired()
.HasMaxLength(450)
.HasColumnAnnotation(IndexAnnotation.AnnotationName, new IndexAnnotation(new IndexAttribute()));
builder.Entity<TScope>()
.ToTable("OpenIddictScopes");
// Configure the TToken entity.
builder.Entity<TToken>()
.HasKey(token => token.Id);
builder.Entity<TToken>()
.Property(token => token.ConcurrencyToken)
.IsConcurrencyToken();
builder.Entity<TToken>()
.Property(token => token.ReferenceId)
.HasMaxLength(450)
.HasColumnAnnotation(IndexAnnotation.AnnotationName, new IndexAnnotation(new IndexAttribute()));
builder.Entity<TToken>()
.Property(token => token.Subject)
.IsRequired();
builder.Entity<TToken>()
.Property(token => token.Type)
.IsRequired();
builder.Entity<TToken>()
.ToTable("OpenIddictTokens");
builder.Configurations.Add(new OpenIddictApplicationConfiguration<TApplication, TAuthorization, TToken, TKey>());
builder.Configurations.Add(new OpenIddictAuthorizationConfiguration<TAuthorization, TApplication, TToken, TKey>());
builder.Configurations.Add(new OpenIddictScopeConfiguration<TScope, TKey>());
builder.Configurations.Add(new OpenIddictTokenConfiguration<TToken, TApplication, TAuthorization, TKey>());
return builder;
}

67
src/OpenIddict.EntityFrameworkCore/Configurations/OpenIddictApplicationConfiguration.cs

@ -0,0 +1,67 @@
/*
* Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
* See https://github.com/openiddict/openiddict-core for more information concerning
* the license and the contributors participating to this project.
*/
using System;
using System.ComponentModel;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using OpenIddict.EntityFrameworkCore.Models;
namespace OpenIddict.EntityFrameworkCore
{
/// <summary>
/// Defines a relational mapping for the Application entity.
/// </summary>
/// <typeparam name="TApplication">The type of the Application entity.</typeparam>
/// <typeparam name="TAuthorization">The type of the Authorization entity.</typeparam>
/// <typeparam name="TToken">The type of the Token entity.</typeparam>
/// <typeparam name="TKey">The type of the Key entity.</typeparam>
[EditorBrowsable(EditorBrowsableState.Never)]
public class OpenIddictApplicationConfiguration<TApplication, TAuthorization, TToken, TKey> : IEntityTypeConfiguration<TApplication>
where TApplication : OpenIddictApplication<TKey, TAuthorization, TToken>
where TAuthorization : OpenIddictAuthorization<TKey, TApplication, TToken>
where TToken : OpenIddictToken<TKey, TApplication, TAuthorization>
where TKey : IEquatable<TKey>
{
public void Configure(EntityTypeBuilder<TApplication> builder)
{
if (builder == null)
{
throw new ArgumentNullException(nameof(builder));
}
// Warning: optional foreign keys MUST NOT be added as CLR properties because
// Entity Framework would throw an exception due to the TKey generic parameter
// being non-nullable when using value types like short, int, long or Guid.
builder.HasKey(application => application.Id);
builder.HasIndex(application => application.ClientId)
.IsUnique();
builder.Property(application => application.ClientId)
.IsRequired();
builder.Property(application => application.ConcurrencyToken)
.IsConcurrencyToken();
builder.Property(application => application.Type)
.IsRequired();
builder.HasMany(application => application.Authorizations)
.WithOne(authorization => authorization.Application)
.HasForeignKey("ApplicationId")
.IsRequired(required: false);
builder.HasMany(application => application.Tokens)
.WithOne(token => token.Application)
.HasForeignKey("ApplicationId")
.IsRequired(required: false);
builder.ToTable("OpenIddictApplications");
}
}
}

62
src/OpenIddict.EntityFrameworkCore/Configurations/OpenIddictAuthorizationConfiguration.cs

@ -0,0 +1,62 @@
/*
* Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
* See https://github.com/openiddict/openiddict-core for more information concerning
* the license and the contributors participating to this project.
*/
using System;
using System.ComponentModel;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using OpenIddict.EntityFrameworkCore.Models;
namespace OpenIddict.EntityFrameworkCore
{
/// <summary>
/// Defines a relational mapping for the Authorization entity.
/// </summary>
/// <typeparam name="TAuthorization">The type of the Authorization entity.</typeparam>
/// <typeparam name="TApplication">The type of the Application entity.</typeparam>
/// <typeparam name="TToken">The type of the Token entity.</typeparam>
/// <typeparam name="TKey">The type of the Key entity.</typeparam>
[EditorBrowsable(EditorBrowsableState.Never)]
public class OpenIddictAuthorizationConfiguration<TAuthorization, TApplication, TToken, TKey> : IEntityTypeConfiguration<TAuthorization>
where TAuthorization : OpenIddictAuthorization<TKey, TApplication, TToken>
where TApplication : OpenIddictApplication<TKey, TAuthorization, TToken>
where TToken : OpenIddictToken<TKey, TApplication, TAuthorization>
where TKey : IEquatable<TKey>
{
public void Configure(EntityTypeBuilder<TAuthorization> builder)
{
if (builder == null)
{
throw new ArgumentNullException(nameof(builder));
}
// Warning: optional foreign keys MUST NOT be added as CLR properties because
// Entity Framework would throw an exception due to the TKey generic parameter
// being non-nullable when using value types like short, int, long or Guid.
builder.HasKey(authorization => authorization.Id);
builder.Property(authorization => authorization.ConcurrencyToken)
.IsConcurrencyToken();
builder.Property(authorization => authorization.Status)
.IsRequired();
builder.Property(authorization => authorization.Subject)
.IsRequired();
builder.Property(authorization => authorization.Type)
.IsRequired();
builder.HasMany(authorization => authorization.Tokens)
.WithOne(token => token.Authorization)
.HasForeignKey("AuthorizationId")
.IsRequired(required: false);
builder.ToTable("OpenIddictAuthorizations");
}
}
}

50
src/OpenIddict.EntityFrameworkCore/Configurations/OpenIddictScopeConfiguration.cs

@ -0,0 +1,50 @@
/*
* Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
* See https://github.com/openiddict/openiddict-core for more information concerning
* the license and the contributors participating to this project.
*/
using System;
using System.ComponentModel;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using OpenIddict.EntityFrameworkCore.Models;
namespace OpenIddict.EntityFrameworkCore
{
/// <summary>
/// Defines a relational mapping for the Scope entity.
/// </summary>
/// <typeparam name="TScope">The type of the Scope entity.</typeparam>
/// <typeparam name="TKey">The type of the Key entity.</typeparam>
[EditorBrowsable(EditorBrowsableState.Never)]
public class OpenIddictScopeConfiguration<TScope, TKey> : IEntityTypeConfiguration<TScope>
where TScope : OpenIddictScope<TKey>
where TKey : IEquatable<TKey>
{
public void Configure(EntityTypeBuilder<TScope> builder)
{
if (builder == null)
{
throw new ArgumentNullException(nameof(builder));
}
// Warning: optional foreign keys MUST NOT be added as CLR properties because
// Entity Framework would throw an exception due to the TKey generic parameter
// being non-nullable when using value types like short, int, long or Guid.
builder.HasKey(scope => scope.Id);
builder.HasIndex(scope => scope.Name)
.IsUnique();
builder.Property(scope => scope.ConcurrencyToken)
.IsConcurrencyToken();
builder.Property(scope => scope.Name)
.IsRequired();
builder.ToTable("OpenIddictScopes");
}
}
}

57
src/OpenIddict.EntityFrameworkCore/Configurations/OpenIddictTokenConfiguration.cs

@ -0,0 +1,57 @@
/*
* Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
* See https://github.com/openiddict/openiddict-core for more information concerning
* the license and the contributors participating to this project.
*/
using System;
using System.ComponentModel;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using OpenIddict.EntityFrameworkCore.Models;
namespace OpenIddict.EntityFrameworkCore
{
/// <summary>
/// Defines a relational mapping for the Token entity.
/// </summary>
/// <typeparam name="TToken">The type of the Token entity.</typeparam>
/// <typeparam name="TApplication">The type of the Application entity.</typeparam>
/// <typeparam name="TAuthorization">The type of the Authorization entity.</typeparam>
/// <typeparam name="TKey">The type of the Key entity.</typeparam>
[EditorBrowsable(EditorBrowsableState.Never)]
public class OpenIddictTokenConfiguration<TToken, TApplication, TAuthorization, TKey> : IEntityTypeConfiguration<TToken>
where TToken : OpenIddictToken<TKey, TApplication, TAuthorization>
where TApplication : OpenIddictApplication<TKey, TAuthorization, TToken>
where TAuthorization : OpenIddictAuthorization<TKey, TApplication, TToken>
where TKey : IEquatable<TKey>
{
public void Configure(EntityTypeBuilder<TToken> builder)
{
if (builder == null)
{
throw new ArgumentNullException(nameof(builder));
}
// Warning: optional foreign keys MUST NOT be added as CLR properties because
// Entity Framework would throw an exception due to the TKey generic parameter
// being non-nullable when using value types like short, int, long or Guid.
builder.HasKey(token => token.Id);
builder.HasIndex(token => token.ReferenceId)
.IsUnique();
builder.Property(token => token.ConcurrencyToken)
.IsConcurrencyToken();
builder.Property(token => token.Subject)
.IsRequired();
builder.Property(token => token.Type)
.IsRequired();
builder.ToTable("OpenIddictTokens");
}
}
}

2
src/OpenIddict.EntityFrameworkCore/OpenIddictEntityFrameworkCoreCustomizer.cs

@ -15,7 +15,7 @@ namespace OpenIddict.EntityFrameworkCore
{
/// <summary>
/// Represents a model customizer able to register the entity sets
/// required by the OpenIddict stack in an Entity Framework context.
/// required by the OpenIddict stack in an Entity Framework Core context.
/// </summary>
public class OpenIddictEntityFrameworkCoreCustomizer<TApplication, TAuthorization, TScope, TToken, TKey> : RelationalModelCustomizer
where TApplication : OpenIddictApplication<TKey, TAuthorization, TToken>

119
src/OpenIddict.EntityFrameworkCore/OpenIddictEntityFrameworkCoreExtensions.cs

@ -78,7 +78,7 @@ namespace Microsoft.Extensions.DependencyInjection
}
/// <summary>
/// Registers the OpenIddict entity sets in the Entity Framework context
/// Registers the OpenIddict entity sets in the Entity Framework Core context
/// using the default OpenIddict models and the default key type (string).
/// </summary>
/// <param name="builder">The builder used to configure the Entity Framework context.</param>
@ -90,8 +90,8 @@ namespace Microsoft.Extensions.DependencyInjection
OpenIddictToken, string>();
/// <summary>
/// Registers the OpenIddict entity sets in the Entity Framework context
/// using the default OpenIddict models and the specified key type.
/// Registers the OpenIddict entity sets in the Entity Framework Core
/// context using the default OpenIddict models and the specified key type.
/// </summary>
/// <param name="builder">The builder used to configure the Entity Framework context.</param>
/// <returns>The Entity Framework context builder.</returns>
@ -103,8 +103,8 @@ namespace Microsoft.Extensions.DependencyInjection
OpenIddictToken<TKey>, TKey>();
/// <summary>
/// Registers the OpenIddict entity sets in the Entity Framework context
/// using the specified entities and the specified key type.
/// Registers the OpenIddict entity sets in the Entity Framework Core
/// context using the specified entities and the specified key type.
/// </summary>
/// <param name="builder">The builder used to configure the Entity Framework context.</param>
/// <returns>The Entity Framework context builder.</returns>
@ -125,7 +125,7 @@ namespace Microsoft.Extensions.DependencyInjection
}
/// <summary>
/// Registers the OpenIddict entity sets in the Entity Framework context
/// Registers the OpenIddict entity sets in the Entity Framework Core context
/// using the default OpenIddict models and the default key type (string).
/// </summary>
/// <param name="builder">The builder used to configure the Entity Framework context.</param>
@ -137,8 +137,8 @@ namespace Microsoft.Extensions.DependencyInjection
OpenIddictToken, string>();
/// <summary>
/// Registers the OpenIddict entity sets in the Entity Framework context
/// using the default OpenIddict models and the specified key type.
/// Registers the OpenIddict entity sets in the Entity Framework Core
/// context using the default OpenIddict models and the specified key type.
/// </summary>
/// <param name="builder">The builder used to configure the Entity Framework context.</param>
/// <returns>The Entity Framework context builder.</returns>
@ -149,8 +149,8 @@ namespace Microsoft.Extensions.DependencyInjection
OpenIddictToken<TKey>, TKey>();
/// <summary>
/// Registers the OpenIddict entity sets in the Entity Framework context
/// using the specified entities and the specified key type.
/// Registers the OpenIddict entity sets in the Entity Framework Core
/// context using the specified entities and the specified key type.
/// </summary>
/// <param name="builder">The builder used to configure the Entity Framework context.</param>
/// <returns>The Entity Framework context builder.</returns>
@ -166,101 +166,10 @@ namespace Microsoft.Extensions.DependencyInjection
throw new ArgumentNullException(nameof(builder));
}
// Warning: optional foreign keys MUST NOT be added as CLR properties because
// Entity Framework would throw an exception due to the TKey generic parameter
// being non-nullable when using value types like short, int, long or Guid.
// Configure the TApplication entity.
builder.Entity<TApplication>(entity =>
{
entity.HasKey(application => application.Id);
entity.HasIndex(application => application.ClientId)
.IsUnique();
entity.Property(application => application.ClientId)
.IsRequired();
entity.Property(application => application.ConcurrencyToken)
.IsConcurrencyToken();
entity.Property(application => application.Type)
.IsRequired();
entity.HasMany(application => application.Authorizations)
.WithOne(authorization => authorization.Application)
.HasForeignKey("ApplicationId")
.IsRequired(required: false);
entity.HasMany(application => application.Tokens)
.WithOne(token => token.Application)
.HasForeignKey("ApplicationId")
.IsRequired(required: false);
entity.ToTable("OpenIddictApplications");
});
// Configure the TAuthorization entity.
builder.Entity<TAuthorization>(entity =>
{
entity.HasKey(authorization => authorization.Id);
entity.Property(authorization => authorization.ConcurrencyToken)
.IsConcurrencyToken();
entity.Property(authorization => authorization.Status)
.IsRequired();
entity.Property(authorization => authorization.Subject)
.IsRequired();
entity.Property(authorization => authorization.Type)
.IsRequired();
entity.HasMany(authorization => authorization.Tokens)
.WithOne(token => token.Authorization)
.HasForeignKey("AuthorizationId")
.IsRequired(required: false);
entity.ToTable("OpenIddictAuthorizations");
});
// Configure the TScope entity.
builder.Entity<TScope>(entity =>
{
entity.HasKey(scope => scope.Id);
entity.HasIndex(scope => scope.Name)
.IsUnique();
entity.Property(scope => scope.ConcurrencyToken)
.IsConcurrencyToken();
entity.Property(scope => scope.Name)
.IsRequired();
entity.ToTable("OpenIddictScopes");
});
// Configure the TToken entity.
builder.Entity<TToken>(entity =>
{
entity.HasKey(token => token.Id);
entity.HasIndex(token => token.ReferenceId)
.IsUnique();
entity.Property(token => token.ConcurrencyToken)
.IsConcurrencyToken();
entity.Property(token => token.Subject)
.IsRequired();
entity.Property(token => token.Type)
.IsRequired();
entity.ToTable("OpenIddictTokens");
});
builder.ApplyConfiguration(new OpenIddictApplicationConfiguration<TApplication, TAuthorization, TToken, TKey>());
builder.ApplyConfiguration(new OpenIddictAuthorizationConfiguration<TAuthorization, TApplication, TToken, TKey>());
builder.ApplyConfiguration(new OpenIddictScopeConfiguration<TScope, TKey>());
builder.ApplyConfiguration(new OpenIddictTokenConfiguration<TToken, TApplication, TAuthorization, TKey>());
return builder;
}

68
test/OpenIddict.EntityFrameworkCore.Tests/OpenIddictEntityFrameworkCoreExtensionsTests.cs

@ -5,9 +5,12 @@
*/
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Conventions;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Moq;
using OpenIddict.Abstractions;
using OpenIddict.Core;
using OpenIddict.EntityFrameworkCore.Models;
@ -112,5 +115,70 @@ namespace OpenIddict.EntityFrameworkCore.Tests
// Assert
Assert.Contains(services, service => service.ServiceType == type && service.ImplementationType == type);
}
[Fact]
public void UseOpenIddict_RegistersDefaultEntityConfigurations()
{
// Arrange
var builder = new Mock<ModelBuilder>(new ConventionSet());
// Act
builder.Object.UseOpenIddict();
// Assert
builder.Verify(mock => mock.ApplyConfiguration(
It.IsAny<OpenIddictApplicationConfiguration<OpenIddictApplication, OpenIddictAuthorization, OpenIddictToken, string>>()), Times.Once());
builder.Verify(mock => mock.ApplyConfiguration(
It.IsAny<OpenIddictAuthorizationConfiguration<OpenIddictAuthorization, OpenIddictApplication, OpenIddictToken, string>>()), Times.Once());
builder.Verify(mock => mock.ApplyConfiguration(
It.IsAny<OpenIddictScopeConfiguration<OpenIddictScope, string>>()), Times.Once());
builder.Verify(mock => mock.ApplyConfiguration(
It.IsAny<OpenIddictTokenConfiguration<OpenIddictToken, OpenIddictApplication, OpenIddictAuthorization, string>>()), Times.Once());
}
[Fact]
public void UseOpenIddict_RegistersDefaultEntityConfigurationsWithCustomKeyType()
{
// Arrange
var builder = new Mock<ModelBuilder>(new ConventionSet());
// Act
builder.Object.UseOpenIddict<long>();
// Assert
builder.Verify(mock => mock.ApplyConfiguration(
It.IsAny<OpenIddictApplicationConfiguration<OpenIddictApplication<long>, OpenIddictAuthorization<long>, OpenIddictToken<long>, long>>()), Times.Once());
builder.Verify(mock => mock.ApplyConfiguration(
It.IsAny<OpenIddictAuthorizationConfiguration<OpenIddictAuthorization<long>, OpenIddictApplication<long>, OpenIddictToken<long>, long>>()), Times.Once());
builder.Verify(mock => mock.ApplyConfiguration(
It.IsAny<OpenIddictScopeConfiguration<OpenIddictScope<long>, long>>()), Times.Once());
builder.Verify(mock => mock.ApplyConfiguration(
It.IsAny<OpenIddictTokenConfiguration<OpenIddictToken<long>, OpenIddictApplication<long>, OpenIddictAuthorization<long>, long>>()), Times.Once());
}
[Fact]
public void UseOpenIddict_RegistersCustomEntityConfigurations()
{
// Arrange
var builder = new Mock<ModelBuilder>(new ConventionSet());
// Act
builder.Object.UseOpenIddict<CustomApplication, CustomAuthorization, CustomScope, CustomToken, Guid>();
// Assert
builder.Verify(mock => mock.ApplyConfiguration(
It.IsAny<OpenIddictApplicationConfiguration<CustomApplication, CustomAuthorization, CustomToken, Guid>>()), Times.Once());
builder.Verify(mock => mock.ApplyConfiguration(
It.IsAny<OpenIddictAuthorizationConfiguration<CustomAuthorization, CustomApplication, CustomToken, Guid>>()), Times.Once());
builder.Verify(mock => mock.ApplyConfiguration(
It.IsAny<OpenIddictScopeConfiguration<CustomScope, Guid>>()), Times.Once());
builder.Verify(mock => mock.ApplyConfiguration(
It.IsAny<OpenIddictTokenConfiguration<CustomToken, CustomApplication, CustomAuthorization, Guid>>()), Times.Once());
}
public class CustomApplication : OpenIddictApplication<Guid, CustomAuthorization, CustomToken> { }
public class CustomAuthorization : OpenIddictAuthorization<Guid, CustomApplication, CustomToken> { }
public class CustomScope : OpenIddictScope<Guid> { }
public class CustomToken : OpenIddictToken<Guid, CustomApplication, CustomAuthorization> { }
}
}

Loading…
Cancel
Save