【问题标题】:Web API - Accessing HttpContext inside DbContext classWeb API - 在 DbContext 类中访问 HttpContext
【发布时间】:2018-04-09 09:57:14
【问题描述】:

在我的 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 以获取用户名?

【问题讨论】:

  • 如何调用UpdateAsync?可以展示一下吗?
  • 附带说明,我强烈建议您定义一个接口,例如IAuditable,它声明相关属性,而不是乱用字符串。同样使用DateTime.Now 几乎肯定会咬你。
  • @AluanHaddad 你对使用 datetime.now 的评论,你的意思是他应该改用 DateTime.UtcNow 吗?
  • @Mart10 是的,如果足够的话,使用DateTime.UtcNow(即您不需要在本地时间显示它们)否则您需要使用DateTimeOffset 并保留一个时区.
  • @AluanHaddad 完全同意你的看法。感谢指导

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


【解决方案1】:

问题在于,对于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
  }
}

【讨论】:

  • +1 谢谢伊戈尔。这类似于您在另一个问题stackoverflow.com/questions/41267255/… 的 cmets 中已经提出的建议
  • asp.net web-api 是否支持开箱即用的 DI?还是只是 aspnetcore?
  • @Mart10 - 核心是具有内置 DI 框架的核心。 Asp.net (web-api/mvc) 没有内置框架,但很容易添加 3rd 方 di 框架。
猜你喜欢
  • 1970-01-01
  • 2011-08-23
  • 1970-01-01
  • 2019-11-17
  • 2010-12-10
  • 1970-01-01
  • 2015-03-29
  • 1970-01-01
  • 2021-04-27
相关资源
最近更新 更多