因此,在花了大约一天左右的时间阅读和阅读之后,我最终构建了自己的 Identity 实现。首先我所做的是获取我现有的Employee 对象并将其扩展为从IUser<int> 继承。 IUser<int> 是一个接口,它是 Identity 2.0(当前处于 alpha 版本)的一部分,它允许将主键类型配置为 string 以外的其他内容,这是 1.0 中的默认设置。由于我存储数据的方式,我的实现非常具体。例如,Employee 可以有多个与之相关的 Email 对象,对于我的应用程序,我想使用电子邮件作为用户名。所以,我简单地设置UserName属性返回Employee的工作邮箱:
public string UserName {
get {
if (this.WorkEmail != null) {
return this.WorkEmail.Address;
}
return null;
}
set {
/// This property is non-settable.
}
}
旁注,由于我不打算使用该属性的 setter,除了简单地将其留空之外,是否有更清洁的方法来废弃它?
继续,我还添加了PasswordHash 属性。我添加了我自己的Role 对象,继承自IRole<int>。最后,Employee 和Role 对象都有一个ICollection<T> 相互链接。另一个方面说明,Identity 的实体框架实现手动创建映射表UserRoles,而不是利用它自己的配置功能,我似乎无法理解其背后的原因。它创建的UserRole 确实会传递到它实现的*Stores 中,但除了充当链接之外,它并没有真正做任何特别的事情。在我的实现中,我只是使用了已经建立的链接,它当然会在数据库中创建一个映射表,但不会毫无意义地暴露在应用程序中。我只是觉得很好奇。
继续前进,使用我配置的对象,我继续实施我自己的 IUserStore 和 IRoleStore 类,创造性地称为 EmployeeStore 和 RoleStore:
public class EmployeeStore : IQueryableUserStore<Employee, int>, IUserStore<Employee, int>, IUserPasswordStore<Employee, int>, IUserRoleStore<Employee, int>, IDisposable {
private bool Disposed;
private IDatabaseRepository<Role> RolesRepository { get; set; }
private IDatabaseRepository<Employee> EmployeesRepository { get; set; }
public EmployeeStore(
IDatabaseRepository<Role> rolesRepository,
IDatabaseRepository<Employee> employeesRepository) {
this.RolesRepository = rolesRepository;
this.EmployeesRepository = employeesRepository;
}
#region IQueryableUserStore Members
public IQueryable<Employee> Users {
get {
return this.EmployeesRepository.Set;
}
}
#endregion
#region IUserStore Members
public async Task CreateAsync(
Employee employee) {
this.ThrowIfDisposed();
if (employee == null) {
throw new ArgumentNullException("employee");
}
await this.EmployeesRepository.AddAndCommitAsync(employee);
}
public async Task DeleteAsync(
Employee employee) {
this.ThrowIfDisposed();
if (employee == null) {
throw new ArgumentNullException("employee");
}
await this.EmployeesRepository.RemoveAndCommitAsync(employee);
}
public Task<Employee> FindByIdAsync(
int employeeId) {
this.ThrowIfDisposed();
return Task.FromResult<Employee>(this.EmployeesRepository.FindSingleOrDefault(
u =>
(u.Id == employeeId)));
}
public Task<Employee> FindByNameAsync(
string userName) {
this.ThrowIfDisposed();
return Task.FromResult<Employee>(this.EmployeesRepository.FindSingleOrDefault(
e =>
(e.UserName == userName)));
}
public async Task UpdateAsync(
Employee employee) {
this.ThrowIfDisposed();
if (employee == null) {
throw new ArgumentNullException("employee");
}
await this.EmployeesRepository.CommitAsync();
}
#endregion
#region IDisposable Members
public void Dispose() {
this.Dispose(true);
GC.SuppressFinalize(this);
}
protected void Dispose(
bool disposing) {
this.Disposed = true;
}
private void ThrowIfDisposed() {
if (this.Disposed) {
throw new ObjectDisposedException(base.GetType().Name);
}
}
#endregion
#region IUserPasswordStore Members
public Task<string> GetPasswordHashAsync(
Employee employee) {
this.ThrowIfDisposed();
if (employee == null) {
throw new ArgumentNullException("employee");
}
return Task.FromResult<string>(employee.PasswordHash);
}
public Task<bool> HasPasswordAsync(
Employee employee) {
return Task.FromResult<bool>(!String.IsNullOrEmpty(employee.PasswordHash));
}
public Task SetPasswordHashAsync(
Employee employee,
string passwordHash) {
this.ThrowIfDisposed();
if (employee == null) {
throw new ArgumentNullException("employee");
}
employee.PasswordHash = passwordHash;
return Task.FromResult<int>(0);
}
#endregion
#region IUserRoleStore Members
public Task AddToRoleAsync(
Employee employee,
string roleName) {
this.ThrowIfDisposed();
if (employee == null) {
throw new ArgumentNullException("employee");
}
if (String.IsNullOrEmpty(roleName)) {
throw new ArgumentNullException("roleName");
}
Role role = this.RolesRepository.FindSingleOrDefault(
r =>
(r.Name == roleName));
if (role == null) {
throw new InvalidOperationException("Role not found");
}
employee.Roles.Add(role);
return Task.FromResult<int>(0);
}
public Task<IList<string>> GetRolesAsync(
Employee employee) {
this.ThrowIfDisposed();
if (employee == null) {
throw new ArgumentNullException("employee");
}
return Task.FromResult<IList<string>>(employee.Roles.Select(
r =>
r.Name).ToList());
}
public Task<bool> IsInRoleAsync(
Employee employee,
string roleName) {
this.ThrowIfDisposed();
if (employee == null) {
throw new ArgumentNullException("employee");
}
if (String.IsNullOrEmpty(roleName)) {
throw new ArgumentNullException("roleName");
}
return Task.FromResult<bool>(employee.Roles.Any(
r =>
(r.Name == roleName)));
}
public Task RemoveFromRoleAsync(
Employee employee,
string roleName) {
this.ThrowIfDisposed();
if (employee == null) {
throw new ArgumentNullException("employee");
}
if (String.IsNullOrEmpty(roleName)) {
throw new ArgumentNullException("roleName");
}
Role role = this.RolesRepository.FindSingleOrDefault(
r =>
(r.Name == roleName));
if (role == null) {
throw new InvalidOperationException("Role is null");
}
employee.Roles.Remove(role);
return Task.FromResult<int>(0);
}
#endregion
}
RoleStore:
public class RoleStore : IQueryableRoleStore<Role, int>, IRoleStore<Role, int>, IDisposable {
private bool Disposed;
private IDatabaseRepository<Role> RolesRepository { get; set; }
public RoleStore(
IDatabaseRepository<Role> rolesRepository) {
this.RolesRepository = rolesRepository;
}
#region IQueryableRoleStore Members
public IQueryable<Role> Roles {
get {
return this.RolesRepository.Set;
}
}
#endregion
#region IRoleStore Members
public async Task CreateAsync(
Role role) {
this.ThrowIfDisposed();
if (role == null) {
throw new ArgumentNullException("role");
}
await this.RolesRepository.AddAndCommitAsync(role);
}
public async Task DeleteAsync(
Role role) {
this.ThrowIfDisposed();
if (role == null) {
throw new ArgumentNullException("role");
}
await this.RolesRepository.RemoveAndCommitAsync(role);
}
public Task<Role> FindByIdAsync(
int roleId) {
this.ThrowIfDisposed();
return Task.FromResult<Role>(this.RolesRepository.FindSingleOrDefault(
r =>
(r.Id == roleId)));
}
public Task<Role> FindByNameAsync(
string roleName) {
this.ThrowIfDisposed();
return Task.FromResult<Role>(this.RolesRepository.FindSingleOrDefault(
r =>
(r.Name == roleName)));
}
public async Task UpdateAsync(
Role role) {
this.ThrowIfDisposed();
if (role == null) {
throw new ArgumentNullException("role");
}
await this.RolesRepository.CommitAsync();
}
#endregion
#region IDisposable Members
public void Dispose() {
this.Dispose(true);
GC.SuppressFinalize(this);
}
protected void Dispose(
bool disposing) {
this.Disposed = true;
}
private void ThrowIfDisposed() {
if (this.Disposed) {
throw new ObjectDisposedException(base.GetType().Name);
}
}
#endregion
}
现在,我注意到实体框架实现正在创建一个看起来像迷你存储库的东西。由于我的项目已经在使用我自己的 Repository 实现,我决定改用它。我们会看看结果如何......
现在,所有这些都有效,而且令人惊讶的是根本没有崩溃,或者至少现在还没有。话虽如此,我拥有所有这些美妙的身份实现,但我似乎无法弄清楚如何在我的 MVC 应用程序中利用它们。由于这超出了这个问题的范围,我将继续打开一个新的来解决这个问题。
我将此作为问题的答案,以防其他人将来遇到此问题。当然,如果有人在我发布的代码中发现错误,请告诉我。