- r - 以节省内存的方式增长 data.frame
- ruby-on-rails - ruby/ruby on rails 内存泄漏检测
- android - 无法解析导入android.support.v7.app
- UNIX 域套接字与共享内存(映射文件)
我正在使用 Entity Framework 6 学习 ASP.NET MVC 5 应用程序中的存储库和工作单元模式。
我已经看了很多教程和文章,但几乎所有的都是自相矛盾的。一些人说存储库和工作单元模式很好,其他人说 DbContext 已经是一个存储库和工作单元,其他人说类似的话,但提供了一种完全不同的方法。我尝试了所有这些不同的方法(好吧,也许不是所有的方法),但仍在纠结于哪种方法是最正确的。
我目前拥有的是:
不确定我是否需要为它粘贴代码,我认为它非常通用,问题实际上不在于 Repository/UnitOfWork 本身。我遇到的问题是将 ASP.NET 标识类与我的存储库和工作单元结合使用。我为成员(member)和所有其他数据共享同一个数据库——我认为这是一种常见的情况。我找不到好的解决方案,如何使用我的存储库实例化 ASP.NET Identity 类。
UserStore<ApplicationUser> store = new UserStore<ApplicationUser>(_DBCONTEXT_);
this.UserManager = new UserManager<ApplicationUser>(store);
我应该用什么代替 DBCONTEXT,以便它与我的 UnitOfWork 共享同一个 DbContext?或者如何以其他方式使 ASP.NET Identity 与 UnitOfWork 一起工作?
我尝试将 DbContext 公开为 UnitOfWork 类的公共(public)属性,例如:
UserStore<ApplicationUser> store = new UserStore<ApplicationUser>(this.unitOfWork.MyDbContext);
但我认为它不对 - 它不适用于自定义 IDbContext 接口(interface),并且使代码不利于单元测试。
我还尝试实现 CustomUserStore 和 CustomRoleStore - 总的来说它是有效的,但是当我测试它时,它需要实现越来越多的方法。这个解决方案看起来太复杂了 - 我真的希望有更简单的方法。
最佳答案
我发现使用 ASP.Net Identity 2.0 和 EF6 有点挑战。最大的缺点是缺少文档或文档冲突。
我正在使用 WebApi 2.0、EF6 和 ASP.Net Identity 2.0。起初很难开始,但一旦开始工作,就很好了。
我创建了自己的身份类。目前我不关心扩展身份类我只想生成表并登录到系统。
自定义角色
public class CustomRole : IdentityRole<int, CustomUserRole>
{
/// <summary>
/// Initializes a new instance of the <see cref="CustomRole"/> class.
/// </summary>
public CustomRole() { }
/// <summary>
/// Initializes a new instance of the <see cref="CustomRole"/> class.
/// </summary>
/// <param name="name">The name.</param>
public CustomRole(string name) { Name = name; }
}
自定义用户声明
public class CustomUserClaim : IdentityUserClaim<int> { }
自定义用户登录
public class CustomUserLogin : IdentityUserLogin<int> { }
自定义用户角色
public class CustomUserRole : IdentityUserRole<int> {}
用户
public class User : IdentityUser<int, CustomUserLogin, CustomUserRole, CustomUserClaim>
{
/// <summary>
/// Gets or sets the first name.
/// </summary>
/// <value>The first name.</value>
public string FirstName { get; set; }
/// <summary>
/// Gets or sets the last name.
/// </summary>
/// <value>The last name.</value>
public string LastName { get; set; }
/// <summary>
/// Gets or sets a value indicating whether this <see cref="User"/> is active.
/// </summary>
/// <value><c>true</c> if active; otherwise, <c>false</c>.</value>
public bool Active { get; set; }
}
我不喜欢 Identity 表的命名,所以我更改了名称。
数据上下文
public class DataContext : IdentityDbContext<User, CustomRole, int, CustomUserLogin, CustomUserRole, CustomUserClaim>
{
public DataContext() : base("DefaultConnection"){}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<CustomUserRole>().ToTable("UserRoles", "Security");
modelBuilder.Entity<CustomUserLogin>().ToTable("UserLogins", "Security");
modelBuilder.Entity<CustomUserClaim>().ToTable("UserClaims", "Security");
modelBuilder.Entity<CustomRole>().ToTable("Roles", "Security");
modelBuilder.Entity<User>().ToTable("Users", "Security");
}
}
我发现获取 UserManager 有点麻烦。
我创建了一个静态类来处理它。 UserStore 确实处理 DataContext 的生命周期,但您必须调用 dispose 才能发生这种情况。如果您在别处使用此 DataContext 引用,这可能会导致问题。我最终会将它连接到我的 DI 容器中,但现在这就是我所拥有的:
public class Identity
{
/// <summary>
/// Gets the user manager.
/// </summary>
/// <returns>UserManager<User, System.Int32>.</returns>
public static UserManager<User, int> GetUserManager()
{
var store = new UserStore<User, CustomRole, int, CustomUserLogin, CustomUserRole, CustomUserClaim>(new DataContext());
var userManager = new UserManager<User, int>(store);
return userManager;
}
}
我的大部分数据访问都使用工作单元模式。它运作良好。在某些情况下,我的数据需要比我公开 DataContext 的工作单元公开的数据更多的控制权。如果这对我仍然不起作用,我将回退到使用存储库。
public class UnitOfWork : IUnitOfWork
{
private readonly IContainer _container;
public UnitOfWork(IContainer container) :this()
{
_container = container;
}
//private readonly List<CommitInterception> _postInterceptions = new List<CommitInterception>();
public DataContext Context { get; set; }
/// <summary>
/// Initializes a new instance of the <see cref="UnitOfWork"/> class.
/// </summary>
public UnitOfWork()
{
Context = new DataContext();
}
/// <summary>
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
/// </summary>
/// <exception cref="System.NotImplementedException"></exception>
public void Dispose()
{
//Chuck was here
try
{
Commit();
}
finally
{
Context.Dispose();
}
}
/// <summary>
/// Begins the transaction.
/// </summary>
/// <returns>IUnitOfWorkTransaction.</returns>
public IUnitOfWorkTransaction BeginTransaction()
{
return new UnitOfWorkTransaction(this);
}
/// <summary>
/// Commits this instance.
/// </summary>
public void Commit()
{
Commit(null);
}
/// <summary>
/// Commits transaction.
/// </summary>
public void Commit(DbContextTransaction transaction)
{
//Lee was here.
try
{
Context.SaveChanges();
if (transaction != null)
{
transaction.Commit();
}
//foreach (var interception in _postInterceptions)
//{
// interception.PostCommit(interception.Instance, this);
//}
}
catch (DbEntityValidationException ex)
{
var errors = FormatError(ex);
throw new Exception(errors, ex);
}
catch
{
if (transaction != null)
{
transaction.Rollback();
}
throw;
}
finally
{
// _postInterceptions.Clear();
}
}
/// <summary>
/// Formats the error.
/// </summary>
/// <param name="ex">The ex.</param>
/// <returns>System.String.</returns>
private static string FormatError(DbEntityValidationException ex)
{
var build = new StringBuilder();
foreach (var error in ex.EntityValidationErrors)
{
var errorBuilder = new StringBuilder();
foreach (var validationError in error.ValidationErrors)
{
errorBuilder.AppendLine(string.Format("Property '{0}' errored:{1}", validationError.PropertyName, validationError.ErrorMessage));
}
build.AppendLine(errorBuilder.ToString());
}
return build.ToString();
}
/// <summary>
/// Inserts the specified entity.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="entity">The entity.</param>
/// <returns>``0.</returns>
public T Insert<T>(T entity) where T: class
{
var instance = _container.TryGetInstance<IUnitOfWorkInterception<T>>();
if (instance != null)
{
instance.Intercept(entity, this);
// _postInterceptions.Add(new CommitInterception() { Instance = entity, PostCommit = (d,f) => instance.PostCommit(d as T, f) });
}
var set = Context.Set<T>();
var item = set.Add(entity);
return item;
}
public T Update<T>(T entity) where T : class
{
var set = Context.Set<T>();
set.Attach(entity);
Context.Entry(entity).State = EntityState.Modified;
return entity;
}
/// <summary>
/// Deletes the specified entity.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="entity">The entity.</param>
public void Delete<T>(T entity) where T : class
{
var set = Context.Set<T>();
set.Remove(entity);
}
/// <summary>
/// Finds the specified predicate.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="predicate">The predicate.</param>
/// <returns>IQueryable{``0}.</returns>
public IQueryable<T> Find<T>(Expression<Func<T, bool>> predicate) where T : class
{
var set = Context.Set<T>();
return set.Where(predicate);
}
/// <summary>
/// Gets all.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns>IQueryable{``0}.</returns>
public IQueryable<T> GetAll<T>() where T : class
{
return Context.Set<T>();
}
/// <summary>
/// Gets the by identifier.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="id">The identifier.</param>
/// <returns>``0.</returns>
public T GetById<T>(int id) where T : class
{
var set = Context.Set<T>();
return set.Find(id);
}
/// <summary>
/// Executes the query command.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="sql">The SQL.</param>
/// <returns>DbSqlQuery{``0}.</returns>
public DbSqlQuery<T> ExecuteQueryCommand<T>(string sql) where T : class
{
var set = Context.Set<T>();
return set.SqlQuery(sql);
}
private class CommitInterception
{
public object Instance { get; set; }
public Action<object, IUnitOfWork> PostCommit { get; set; }
}
}
public class UnitOfWorkTransaction : IUnitOfWorkTransaction
{
private readonly UnitOfWork _unitOfWork;
private readonly DbContextTransaction _transaction;
/// <summary>
/// Initializes a new instance of the <see cref="UnitOfWorkTransaction"/> class.
/// </summary>
/// <param name="unitOfWork">The unit of work.</param>
public UnitOfWorkTransaction(UnitOfWork unitOfWork)
{
_unitOfWork = unitOfWork;
_transaction = _unitOfWork.Context.Database.BeginTransaction();
Context = unitOfWork.Context;
}
/// <summary>
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
/// </summary>
public void Dispose()
{
_unitOfWork.Commit(_transaction);
}
public DataContext Context { get; set; }
/// <summary>
/// Commits this instance.
/// </summary>
public void Commit()
{
_unitOfWork.Commit();
}
/// <summary>
/// Rollbacks this instance.
/// </summary>
public void Rollback()
{
_transaction.Rollback();
}
/// <summary>
/// Inserts the specified entity.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="entity">The entity.</param>
/// <returns>T.</returns>
public T Insert<T>(T entity) where T : class
{
return _unitOfWork.Insert(entity);
}
/// <summary>
/// Updates the specified entity.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="entity">The entity.</param>
/// <returns>T.</returns>
public T Update<T>(T entity) where T : class
{
return _unitOfWork.Update(entity);
}
/// <summary>
/// Deletes the specified entity.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="entity">The entity.</param>
public void Delete<T>(T entity) where T : class
{
_unitOfWork.Delete(entity);
}
/// <summary>
/// Finds the specified predicate.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="predicate">The predicate.</param>
/// <returns>IQueryable<T>.</returns>
public IQueryable<T> Find<T>(Expression<Func<T, bool>> predicate) where T : class
{
return _unitOfWork.Find(predicate);
}
/// <summary>
/// Gets all.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns>IQueryable<T>.</returns>
public IQueryable<T> GetAll<T>() where T : class
{
return _unitOfWork.GetAll<T>();
}
/// <summary>
/// Gets the by identifier.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="id">The identifier.</param>
/// <returns>T.</returns>
public T GetById<T>(int id) where T : class
{
return _unitOfWork.GetById<T>(id);
}
/// <summary>
/// Executes the query command.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="sql">The SQL.</param>
/// <returns>DbSqlQuery<T>.</returns>
public DbSqlQuery<T> ExecuteQueryCommand<T>(string sql) where T : class
{
return _unitOfWork.ExecuteQueryCommand<T>(sql);
}
}
以下是它的一些实际应用示例。我有 nHibernate 背景,喜欢在 using
范围内定义一个事务,所以我在我的工作单元中实现了。
using (var trans = _unitOfWork.BeginTransaction())
{
var newAgency = trans.Insert(new Database.Schema.Agency() { Name = agency.Name, TaxId = agency.TaxId });
}
另一个使用“查找”关闭工作单元的示例:
var users = _unitOfWork.Find<Database.Schema.User>(s => s.Active && s.Agency_Id == agencyId)
.Select(u=> new {Label = u.FirstName + " " + u.LastName, Value = u.Id})
.ToList();
用户创建和用户登录
我使用 ASP.NET Identity 进行登录和用户创建,并使用我的工作单元进行其他所有操作。
测试
我不会尝试测试 ASP.NET Identity。首先,我确信微软在测试它方面做得很好。我相信他们比你或我做得更好。如果您真的想围绕 ASP.NET Identity 代码进行测试,请将其放在接口(interface)后面并模拟接口(interface)。
关于c# - 具有存储库和工作单元的 ASP.NET 标识,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23226140/
#include using namespace std; class C{ private: int value; public: C(){ value = 0;
这个问题已经有答案了: What is the difference between char a[] = ?string?; and char *p = ?string?;? (8 个回答) 已关闭
关闭。此题需要details or clarity 。目前不接受答案。 想要改进这个问题吗?通过 editing this post 添加详细信息并澄清问题. 已关闭 7 年前。 此帖子已于 8 个月
除了调试之外,是否有任何针对 c、c++ 或 c# 的测试工具,其工作原理类似于将独立函数复制粘贴到某个文本框,然后在其他文本框中输入参数? 最佳答案 也许您会考虑单元测试。我推荐你谷歌测试和谷歌模拟
我想在第二台显示器中移动一个窗口 (HWND)。问题是我尝试了很多方法,例如将分辨率加倍或输入负值,但它永远无法将窗口放在我的第二台显示器上。 关于如何在 C/C++/c# 中执行此操作的任何线索 最
我正在寻找 C/C++/C## 中不同类型 DES 的现有实现。我的运行平台是Windows XP/Vista/7。 我正在尝试编写一个 C# 程序,它将使用 DES 算法进行加密和解密。我需要一些实
很难说出这里要问什么。这个问题模棱两可、含糊不清、不完整、过于宽泛或夸夸其谈,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开,visit the help center . 关闭 1
有没有办法强制将另一个 窗口置于顶部? 不是应用程序的窗口,而是另一个已经在系统上运行的窗口。 (Windows, C/C++/C#) 最佳答案 SetWindowPos(that_window_ha
假设您可以在 C/C++ 或 Csharp 之间做出选择,并且您打算在 Windows 和 Linux 服务器上运行同一服务器的多个实例,那么构建套接字服务器应用程序的最明智选择是什么? 最佳答案 如
你们能告诉我它们之间的区别吗? 顺便问一下,有什么叫C++库或C库的吗? 最佳答案 C++ 标准库 和 C 标准库 是 C++ 和 C 标准定义的库,提供给 C++ 和 C 程序使用。那是那些词的共同
下面的测试代码,我将输出信息放在注释中。我使用的是 gcc 4.8.5 和 Centos 7.2。 #include #include class C { public:
很难说出这里问的是什么。这个问题是含糊的、模糊的、不完整的、过于宽泛的或修辞性的,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开它,visit the help center 。 已关
我的客户将使用名为 annoucement 的结构/类与客户通信。我想我会用 C++ 编写服务器。会有很多不同的类继承annoucement。我的问题是通过网络将这些类发送给客户端 我想也许我应该使用
我在 C# 中有以下函数: public Matrix ConcatDescriptors(IList> descriptors) { int cols = descriptors[0].Co
我有一个项目要编写一个函数来对某些数据执行某些操作。我可以用 C/C++ 编写代码,但我不想与雇主共享该函数的代码。相反,我只想让他有权在他自己的代码中调用该函数。是否可以?我想到了这两种方法 - 在
我使用的是编写糟糕的第 3 方 (C/C++) Api。我从托管代码(C++/CLI)中使用它。有时会出现“访问冲突错误”。这使整个应用程序崩溃。我知道我无法处理这些错误[如果指针访问非法内存位置等,
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 我们不允许提问寻求书籍、工具、软件库等的推荐。您可以编辑问题,以便用事实和引用来回答。 关闭 7 年前。
已关闭。此问题不符合Stack Overflow guidelines 。目前不接受答案。 要求我们推荐或查找工具、库或最喜欢的场外资源的问题对于 Stack Overflow 来说是偏离主题的,因为
我有一些 C 代码,将使用 P/Invoke 从 C# 调用。我正在尝试为这个 C 函数定义一个 C# 等效项。 SomeData* DoSomething(); struct SomeData {
这个问题已经有答案了: Why are these constructs using pre and post-increment undefined behavior? (14 个回答) 已关闭 6
我是一名优秀的程序员,十分优秀!