我不得不将所有 IdentityFramework 类和接口移动到单独的库中,这意味着新的 Common.Models.Interfaces
接口库只能引用其他接口库(或 .net 库(。这意味着我所有的ApplicationUser
参数和变量都变得IApplicationUser
。
经过几个小时的更改,我完成了所有构建,但是在运行时出现以下错误:
当前类型 Microsoft.AspNet.Identity.IUserStore'1[Common.Models.Interfaces.Account.IApplicationUser] 是一个接口,无法构造。是否缺少类型映射?
所以我的问题是:我可能缺少什么类型映射?
我之前已经解决了以下代码的dbcontext
问题 http://tech.trailmax.info/2014/09/aspnet-identity-and-ioc-container-registration (特别是InjectionConstructor
的使用(
container.RegisterType<IApplicationUser, ApplicationUser>();
container.RegisterType<DbContext, ApplicationDbContext>();
container.RegisterType<IdentityDbContext<ApplicationUser>, ApplicationDbContext>();
container.RegisterType<IIdentityMessageService, EmailService>();
container.RegisterType<IApplicationSignInManager, ApplicationSignInManager>();
container.RegisterType<IUserStore<ApplicationUser>, UserStore<ApplicationUser>>(new InjectionConstructor(typeof(ApplicationDbContext)));
注意:此处提到的其他错误已删除,因为它具有误导性。看起来我需要额外的映射,但不知道是什么。
应用程序用户界面和类如下所示(修剪(,以便您可能会发现我出错的地方:
I应用用户.cs
public interface IApplicationUser : IUser, IUser<string>
{
...
}
应用程序用户.cs
public class ApplicationUser : IdentityUser, IApplicationUser
{
...
}
ApplicationDbContext.cs
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
显然,不可能包含所有相关代码来重现这一点,因为它运行到 1000 行,并且不需要重现,因此只有 IOC 专家应该申请。 :)
第二次尝试:
在@guillaume31
的有用链接之后,我尝试了以下内容:
container.RegisterType(typeof(IUserStore<>), typeof(UserStore<>), new InjectionConstructor(typeof(ApplicationDbContext)));
这编译了,但我收到一个新错误:
GenericArguments[0], 'Common.Models.Interfaces.Account.IApplicationUser', on 'Microsoft.AspNet.Identity.EntityFramework.UserStore'6[TUser,TRole,TKey,TUserLogin,TUserRole,TUserClaim]"违反了类型参数"TUser"的约束
第三次尝试
container.RegisterType(typeof(IUserStore<>), typeof(UserStore<ApplicationUser>), new InjectionConstructor(typeof(ApplicationDbContext)));
导致此错误:
无法强制转换类型为"Microsoft.AspNet.Identity.EntityFramework.UserStore
1[Vero.Common.Verofy.Models.Account.ApplicationUser]' to type 'Microsoft.AspNet.Identity.IUserStore
1[Vero.Common.Verofy.Models.Interfaces.Account.IApplicationUser]"的对象。
第四次尝试
container.RegisterType(typeof(IUserStore<IApplicationUser>), typeof(UserStore<ApplicationUser>), new InjectionConstructor(typeof(ApplicationDbContext)));
这编译了,但我收到此错误(与以前的测试相同(:
无法强制转换类型的对象 'Microsoft.AspNet.Identity.EntityFramework.UserStore
1[Common.Models.Account.ApplicationUser]' to type 'Microsoft.AspNet.Identity.IUserStore
1[Common.Models.Interfaces.Account.IApplicationUser]'.
第五次尝试(使用已注册的实例(:
var applicationDbContext = new ApplicationDbContext();
container.RegisterInstance<DbContext>(applicationDbContext);
var userStore = new UserStore<ApplicationUser>(applicationDbContext);
container.RegisterInstance(typeof(IUserStore<IApplicationUser>), userStore);
新错误为:
类型 Microsoft.AspNet.Identity.EntityFramework.UserStore
1[[Vero.Common.Verofy.Models.Account.ApplicationUser, Vero.Common.Verofy.Models, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]] cannot be assigned to variables of type Microsoft.AspNet.Identity.IUserStore
1[Vero.Common.Verofy.Models.Interfaces.Account.IApplicationUser]。 参数名称:实例
第六次尝试(旁路注射(:
以下简单行在运行时也会失败:
IUserStore<IApplicationUser> test = (IUserStore<IApplicationUser>)new UserStore<ApplicationUser>(applicationDbContext);
错误是:
无法强制转换类型为> 'Microsoft.AspNet.Identity.EntityFramework.UserStore 1[Common.Models.Account.ApplicationUser]' to type 'Microsoft.AspNet.Identity.IUserStore
1[Common.Models.Interfaces.Account.IApplicationUser]'的对象。
总结
所有这些问题都表明我的IUserStore<IApplicationUser>
和UserStore<ApplicationUser>
类实现之间不兼容。询问您认为可能有帮助的任何课程的更多详细信息。
更新
基本问题归结为这种依赖关系:
- 我们的
ApplicationUser
班需要公开public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser, string> manager)
- 这会强制
UserManager
的类型为 IApplicationUser 而不是应用程序用户,并导致发生大量级联依赖项。
这是我一直在使用的
container.RegisterType<IUserStore<IdentityUser>, UserStoreRepository>(new PerRequestLifetimeManager());
container.RegisterType<IRoleStore<IdentityRole, string>, RoleStoreRepository>(new PerRequestLifetimeManager());
container.RegisterType<ApplicationUserManager>(new PerRequestLifetimeManager());
container.RegisterType<ApplicationRoleManager>(new PerRequestLifetimeManager());
UserStoreRepository只是
public class UserStoreRepository : UserStore<IdentityUser>
{
public UserStoreRepository(AuthContext context)
: base(context)
{
}
}
同样地
public class RoleStoreRepository : RoleStore<IdentityRole>
{
public RoleStoreRepository(AuthContext context)
: base(context)
{
}
}
当然,您需要注册上下文
public class AuthContext: IdentityDbContext<IdentityUser>
{
public AuthContext()
: base("AuthContext")
{
}
}
对于其他事情:
public class ApplicationUserManager : UserManager<IdentityUser>
public class ApplicationRoleManager : RoleManager<IdentityRole>
我认为您的第一次尝试几乎是正确的,我会尝试将您的 UserStore 包装到包装您的应用程序用户的不同对象
> 基本上,http://tech.trailmax.info/2014/09/aspnet-identity-and-ioc-container-registration 中的示例提供了一段代码,该代码添加了不应该存在的依赖项。
解决方案是改变这一点:
Provider = new CookieAuthenticationProvider
{
// Enables the application to validate the security stamp when the user logs in.
// This is a security feature which is used when you change a password or add an external login to your account.
OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
validateInterval: TimeSpan.FromMinutes(30),
regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
}
对此:
Provider = new CookieAuthenticationProvider
{
// Enables the application to validate the security stamp when the user logs in.
// This is a security feature which is used when you change a password or add an external login to your account.
OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
validateInterval: TimeSpan.FromMinutes(30),
regenerateIdentity: (manager, user) => manager.CreateIdentityAsync(user, DefaultAuthenticationTypes.ApplicationCookie))
}
并从ApplicationUser
中删除GenerateUserIdentityAsync
方法。
这基本上将调用从user(usermanager)
翻转到usermanager(user)
,并且无需在 IApplication用户界面中引用应用程序用户!
然后,我能够在一个库中拥有ApplicationUser
类,将接口放在另一个库中,并且应用程序中只有与特定应用程序相关的类。