C# Web API-在DbContext类中访问HttpContext

C# Web API-在DbContext类中访问HttpContext,c#,asp.net-web-api,C#,Asp.net Web Api,在我的C#Web API应用程序中,我在所有表中添加了CreatedDate和CreatedBy列。现在我想在任何表中添加新记录时填充这些列 为此,我在DbContext类中重写了SaveChanges和savechangesync函数,如下所示: public class AuthDbContext : IdentityDbContext<ApplicationUser, CustomRole, int, CustomUserLogin, CustomUserRole, CustomUs

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

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

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;
                }                
            }
        }
    }
}
公共类AuthDbContext:IdentityDbContext
{
公共覆盖int SaveChanges()
{
AddTimestamps();
返回base.SaveChanges();
}
公共重写异步任务SaveChangesAsync()
{
AddTimestamps();
return wait base.SaveChangesAsync();
}
私有void AddTimestamps()
{        
var entities=ChangeTracker.Entries(),其中(x=>(x.State==EntityState.Added));
var currentUsername=!string.IsNullOrEmpty(HttpContext.Current?.User?.Identity?.Name)
?HttpContext.Current.User.Identity.Name
:“系统”;
foreach(实体中的var实体)
{
foreach(entity.CurrentValues.PropertyNames中的变量propName)
{
if(propName==“CreatedBy”&&entity.State==EntityState.Added)
{
entity.CurrentValues[propName]=currentUsername;
}
else if(propName==“CreatedDate”&&entity.State==EntityState.Added)
{
entity.CurrentValues[propName]=DateTime.Now;
}                
}
}
}
}
现在,当我在控制器中的任何位置调用
SaveChanges
savechangesync
时,
HttpContext.Current
被分配,我可以使用
ttpContext.Current.User.Identity.name
从中获取用户名。但是,当我使用
UserManager.UpdateAsync
函数(在DbContext类中内部调用
savechangesync
函数)对底层用户表进行更改时,
HttpContext.Current
设置为null


在这种特殊情况下,我如何访问HttpContext来获取用户名?

问题是,使用
savechangesync
时,您不知道是否可以访问
HttpContext.Current
,因为您可能没有在处理请求的线程上执行

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

至于使用哪种DI框架,我是偏爱的,但有很多可供选择,而且大部分都有类似的功能

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
  }
}

你怎么称呼UpdateAsync?你能展示一下吗?作为旁注,我强烈建议你定义一个接口,比如说
IAuditable
,它声明有问题的属性,而不是乱搞字符串。同时使用
DateTime.Now
几乎肯定会对你造成伤害。@AluanHaddad,你对使用DateTime.Now的评论是什么意思,你的意思是他应该使用DateTime.UtcNow吗?@Mart10是的,如果这足够的话,可以使用
DateTime.UtcNow
(也就是说,你永远不需要在当地时间显示它们)否则,您需要使用
DateTimeOffset
,并保留一个时区。@AluanHaddad完全同意您的意见。感谢您的指导+1感谢Igor。这与您在另一个问题的评论中所建议的类似。asp.net web api不支持现成的DI吗?还是仅仅是aspnetcore?@Mart10-core是一个内置DI框架的内核。Asp.net(web api/mvc)没有内置框架,但添加第三方di框架非常容易。