【问题标题】:How to inject DbContext in an Action Filter如何在动作过滤器中注入 DbContext
【发布时间】:2018-08-30 18:38:43
【问题描述】:

我有一个将请求记录在数据库中的操作过滤器。

我使用通常的构造注入器方法。

public ServerLogFilterAttribute(OrderEntryContext context)
{
  this.context = context;
}

public override void OnActionExecuting(ActionExecutingContext context)
{
    var descriptor = context.ActionDescriptor;
    if (descriptor != null && descriptor.RouteValues.Count > 0)
    {
        var actionName = descriptor.RouteValues["action"];
        var controllerName = descriptor.RouteValues["controller"];

        if (context.HttpContext.User != null && context.HttpContext.User.Identity != null)
        {
            var claimsIdentity = context.HttpContext.User.Identity as ClaimsIdentity;

            if (claimsIdentity != null && claimsIdentity.IsAuthenticated)
            {
                var username = claimsIdentity.FindFirst(ClaimTypes.NameIdentifier).Value;
                var userId = claimsIdentity.Claims.First(c => c.Type == "userId").Value;

                var serverLog = new ServerLog()
                {
                    AspNetUserId = userId,
                    Controller = controllerName,
                    Action = actionName,
                    TimeStamp = DateTime.Now
                };

                LoggerRepository loggerRepository = new LoggerRepository(this.context);
                Task.Run(() => loggerRepository.InsertServerCallLog(serverLog));
            }
        }
    }

    base.OnActionExecuting(context);

}

但这会在 SaveChanges() 期间引发异常:

System.ObjectDisposedException
  HResult=0x80131622
  Message=Cannot access a disposed object. A common cause of this error is disposing a context that was resolved from dependency injection and then later trying to use the same context instance elsewhere in your application. This may occur if you are calling Dispose() on the context, or wrapping the context in a using statement. If you are using dependency injection, you should let the dependency injection container take care of disposing context instances.
  Source=Microsoft.EntityFrameworkCore
  StackTrace:
   at Microsoft.EntityFrameworkCore.DbContext.CheckDisposed()
   at Microsoft.EntityFrameworkCore.DbContext.get_InternalServiceProvider()
   at Microsoft.EntityFrameworkCore.DbContext.get_DbContextDependencies()
   at Microsoft.EntityFrameworkCore.DbContext.<SaveChangesAsync>d__48.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at GGL.OrderEntry.Data.OrderEntryContext.<SaveChangesAsync>d__251.MoveNext() in C:\Dev\GGL\GGL.OrderEntry\GGL.OrderEntry.Data\Context\OrderEntryContext.Partial.cs:line 306

据我所知,问题在于过滤器的生命周期比上下文的生命周期长(设置为“瞬态”)

options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")), ServiceLifetime.Transient);

那么我应该如何注入 DbContext?

【问题讨论】:

  • @RyanWilson,谢谢你就是这样。我完全错过了。如果您想发布作为答案,我会接受。
  • 已将其移至答案,很高兴我能提供帮助。

标签: c# asp.net-core entity-framework-core


【解决方案1】:

您正在使用Task.Run(() =&gt; loggerRepository.InsertServerCallLog(serverLog));,它将上下文分配给变量loggerRepository,并告诉它在线程池上运行,从而让方法继续执行。该方法很可能在线程池完成执行并且对象已被释放之前退出,只需让对 InsertServerCallLog 的调用在主线程上运行,以便在完成该方法之前不会继续执行

【讨论】:

  • 没有必要说这是评论。此外,您应该从问题中删除您的 cmets,因为它是一个答案
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-07-06
  • 1970-01-01
  • 2023-03-16
  • 2017-01-08
相关资源
最近更新 更多