Browse Source

Update OpenIddictStore to support database contexts derived from DbContext

pull/24/head
Kévin Chalet 10 years ago
parent
commit
002eff080f
  1. 62
      src/OpenIddict.EF/OpenIddictExtensions.cs
  2. 13
      src/OpenIddict.EF/OpenIddictStore.cs

62
src/OpenIddict.EF/OpenIddictExtensions.cs

@ -9,6 +9,7 @@ using System.Linq;
using System.Reflection; using System.Reflection;
using Microsoft.AspNet.Identity; using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.EntityFramework; using Microsoft.AspNet.Identity.EntityFramework;
using Microsoft.Data.Entity;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Internal; using Microsoft.Extensions.Internal;
using OpenIddict; using OpenIddict;
@ -16,35 +17,52 @@ using OpenIddict;
namespace Microsoft.AspNet.Builder { namespace Microsoft.AspNet.Builder {
public static class OpenIddictExtensions { public static class OpenIddictExtensions {
public static OpenIddictBuilder AddEntityFrameworkStore([NotNull] this OpenIddictBuilder builder) { public static OpenIddictBuilder AddEntityFrameworkStore([NotNull] this OpenIddictBuilder builder) {
// Resolve the key type from the user type definition.
var keyType = ResolveKeyType(builder);
builder.Services.AddScoped( builder.Services.AddScoped(
typeof(IOpenIddictStore<,>).MakeGenericType(builder.UserType, builder.ApplicationType), typeof(IOpenIddictStore<,>).MakeGenericType(builder.UserType, builder.ApplicationType),
typeof(OpenIddictStore<,,,>).MakeGenericType(builder.UserType, builder.ApplicationType, builder.RoleType, keyType)); typeof(OpenIddictStore<,,,,>).MakeGenericType(
/* TUser: */ builder.UserType,
var type = typeof(OpenIddictContext<,,,>).MakeGenericType(new[] { /* TApplication: */ builder.ApplicationType,
/* TUser: */ builder.UserType, /* TRole: */ builder.RoleType,
/* TApplication: */ builder.ApplicationType, /* TContext: */ ResolveContextType(builder),
/* TRole: */ builder.RoleType, /* TKey: */ ResolveKeyType(builder)));
/* TKey: */ keyType
}); return builder;
}
private static Type ResolveContextType([NotNull] OpenIddictBuilder builder) {
var service = (from registration in builder.Services
where registration.ServiceType.IsConstructedGenericType
let definition = registration.ServiceType.GetGenericTypeDefinition()
where definition == typeof(IUserStore<>)
select registration.ImplementationType).SingleOrDefault();
builder.Services.AddScoped(type, provider => { if (service == null) {
// Resolve the user store from the parent container and extract the associated context. throw new InvalidOperationException(
dynamic store = provider.GetRequiredService(typeof(IUserStore<>).MakeGenericType(builder.UserType)); "The type of the database context cannot be automatically inferred. " +
"Make sure 'AddOpenIddict()' is the last chained call when configuring the services.");
}
dynamic context = store?.Context; TypeInfo type;
if (!type.GetTypeInfo().IsAssignableFrom(context?.GetType())) { for (type = service.GetTypeInfo(); type != null; type = type.BaseType?.GetTypeInfo()) {
throw new InvalidOperationException( if (!type.IsGenericType) {
"Only EntityFramework contexts derived from " + continue;
"OpenIddictContext can be used with OpenIddict.");
} }
return context; var definition = type.GetGenericTypeDefinition();
}); if (definition == null) {
continue;
}
return builder; if (definition != typeof(UserStore<,,,>)) {
continue;
}
return (from argument in type.AsType().GetGenericArguments()
where typeof(DbContext).IsAssignableFrom(argument)
select argument).Single();
}
throw new InvalidOperationException("The type of the database context cannot be automatically inferred.");
} }
private static Type ResolveKeyType([NotNull] OpenIddictBuilder builder) { private static Type ResolveKeyType([NotNull] OpenIddictBuilder builder) {

13
src/OpenIddict.EF/OpenIddictStore.cs

@ -6,21 +6,26 @@ using Microsoft.Data.Entity;
using OpenIddict.Models; using OpenIddict.Models;
namespace OpenIddict { namespace OpenIddict {
public class OpenIddictStore<TUser, TApplication, TRole, TKey> : UserStore<TUser, TRole, OpenIddictContext<TUser, TApplication, TRole, TKey>, TKey>, IOpenIddictStore<TUser, TApplication> public class OpenIddictStore<TUser, TApplication, TRole, TContext, TKey> : UserStore<TUser, TRole, TContext, TKey>, IOpenIddictStore<TUser, TApplication>
where TUser : IdentityUser<TKey> where TUser : IdentityUser<TKey>
where TApplication : Application where TApplication : Application
where TRole : IdentityRole<TKey> where TRole : IdentityRole<TKey>
where TContext : DbContext
where TKey : IEquatable<TKey> { where TKey : IEquatable<TKey> {
public OpenIddictStore(OpenIddictContext<TUser, TApplication, TRole, TKey> context) public OpenIddictStore(TContext context)
: base(context) { : base(context) {
} }
public DbSet<TApplication> Applications {
get { return Context.Set<TApplication>(); }
}
public virtual Task<TApplication> FindApplicationByIdAsync(string identifier, CancellationToken cancellationToken) { public virtual Task<TApplication> FindApplicationByIdAsync(string identifier, CancellationToken cancellationToken) {
return Context.Applications.SingleOrDefaultAsync(application => application.ApplicationID == identifier, cancellationToken); return Applications.SingleOrDefaultAsync(application => application.ApplicationID == identifier, cancellationToken);
} }
public virtual Task<TApplication> FindApplicationByLogoutRedirectUri(string url, CancellationToken cancellationToken) { public virtual Task<TApplication> FindApplicationByLogoutRedirectUri(string url, CancellationToken cancellationToken) {
return Context.Applications.SingleOrDefaultAsync(application => application.LogoutRedirectUri == url, cancellationToken); return Applications.SingleOrDefaultAsync(application => application.LogoutRedirectUri == url, cancellationToken);
} }
public virtual Task<string> GetApplicationTypeAsync(TApplication application, CancellationToken cancellationToken) { public virtual Task<string> GetApplicationTypeAsync(TApplication application, CancellationToken cancellationToken) {

Loading…
Cancel
Save