Web API - 在DbContext类中访问HttpContext

时间:2018-03-29 13:33:17

标签: c# asp.net-web-api

在我的C#Web API应用程序中,我在所有表中添加了CreatedDateCreatedBy列。现在,我想在任何表中添加新记录时填充这些列。

为此,我在DbContext类中重写了SaveChangesSaveChangesAsync函数,如下所示:

public class AuthDbContext : IdentityDbContext<ApplicationUser, CustomRole, int, CustomUserLogin, CustomUserRole, CustomUserClaim>
{
    public override int SaveChanges()
    {
        AddTimestamps();
        return base.SaveChanges();
    }

    public override async Task<int> SaveChangesAsync()
    {
        AddTimestamps();
        return await base.SaveChangesAsync();
    }

    private void AddTimestamps()
    {        
        var entities = ChangeTracker.Entries().Where(x => (x.State == EntityState.Added));

        var currentUsername = !string.IsNullOrEmpty(HttpContext.Current?.User?.Identity?.Name)
            ? HttpContext.Current.User.Identity.Name
            : "SYSTEM";

        foreach (var entity in entities)
        {
            foreach (var propName in entity.CurrentValues.PropertyNames)
            {
                if (propName == "CreatedBy" && entity.State == EntityState.Added)
                {
                    entity.CurrentValues[propName] = currentUsername;
                }
                else if (propName == "CreatedDate" && entity.State == EntityState.Added)
                {
                    entity.CurrentValues[propName] = DateTime.Now;
                }                
            }
        }
    }
}

现在,当我从控制器的任何位置拨打SaveChangesSaveChangesAsync时,HttpContext.Current已分配,我可以使用ttpContext.Current.User.Identity.Name从中获取用户名。但是当我使用UserManager.UpdateAsync函数(在我们的DbContext类中内部调用SaveChangesAsync函数)来更改底层用户表时,HttpContext.Current被设置为null。

如何在此特定情况下访问HttpContext以获取用户名?

1 个答案:

答案 0 :(得分:4)

问题是使用SaveChangesAsync您不知道您是否有权访问HttpContext.Current,因为您可能没有在请求被提供的线程上执行。

解决这个问题的最佳方法是使用DI。您可以创建一个接口和匹配类,其中实现依赖于HttpContextBase。配置DI框架以将IUserContext实例注入DbContext并为每个请求创建UserContext的新实例。

至于使用哪个DI框架,我偏向于Autofac,但有很多可供选择,并且大部分具有相似的功能。

public interface IUserContext {
   bool IsAuthenticated {get;}
   // additional properties like user id / name / etc
}

public class UserContext : IUserContext
{
  public UserContext(HttpContextBase httpContext) {
    this.IsAuthenticated = httpContext.User.Identity.IsAuthenticated;
    // any other properties that you want to use later
  }
}