将用户名注入dbContext(实体框架6)以自动更新列ModifiedBy / CreatedBy

时间:2016-01-29 10:01:44

标签: asp.net-mvc entity-framework asp.net-web-api asp.net-identity autofac

我正在建立一个MVC 5,WebApi 2,实体框架解决方案。我想在我的数据库中插入审计字段,而不是每次都编写样板代码来执行此操作。我的数据库实体位于他们自己的独立项目中,该项目引用了EntityFramework。

到目前为止,我有:

    public class MyDbContext : IdentityDbContext<ApplicationUser>
    {
        public MyDbContext(/*Autofac can inject stuff here*/)
        {
        }

        public override int SaveChanges()
        {
            // Updates ModifiedBy, CreatedBy, ModifiedOn, CreatedOn fields
            DbContextHelper.TrackSaveChanges(ChangeTracker, userName);

            return base.SaveChanges();
        }
    }
  

TrackSaveChanges()内的逻辑并不重要,这只是循环遍历所有已更改的实体并在字段上设置值。没什么太聪明的。

问题是在我的userName派生类中获得DbContext。我想最好的方法是在MyDbContext构造函数上注入它?

有关使用HttpContext.Current.User的建议,但我不想在我的数据项目中添加Web依赖项。此外,对HttpContext的直接引用也会影响单位可测试性。

  • 我在Autofac builder.Register<IPrincipal>(ip => HttpContext.Current.User);中尝试将IPrincipal注入dbcontext,但由于HttpContext.Current.User在创建时为null,因此会引发异常。
  • 如果必须,我宁愿使用HttpContextBase代替HttpContext

有干净的方法吗? 我正在使用Entity Framework 6,WebAPI 2,ASP NET Identity和Autofac。

1 个答案:

答案 0 :(得分:4)

您可以注入接口而不是string值本身:

interface IUserNameProvider
{
    string GetUserName();
}

具体实现将使用HttpContext.Current.User,但这种方法不会影响可测试性,因为界面很容易被模拟。

interface HttpContextUserNameProvider : IUserNameProvider
{
    public string GetUserName()
    {
        return HttpContext.Current.User;
    }
}

客户端代码示例:

public class MyDbContext : IdentityDbContext<ApplicationUser>
{
    internal IUserNameProvider _userNameProvider;

    public MyDbContext(IUserNameProvider userNameProvider)
    {
        _userNameProvider = userNameProvider;
    }

    public override int SaveChanges()
    {
        string userName = _userNameProvider.GetUserName();
        // ...
    }
}