如何在动作过滤器中注入DbContext

问题描述 投票:0回答:1

我有一个动作过滤器,它将请求记录在数据库中。

我使用通常的施工注射器方法。

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

据我所知,问题是Filter的生命周期比上下文的生命周期长(设置为“Transient”)

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

那么我应该如何注入DbContext?

c# asp.net-core entity-framework-core
1个回答
1
投票

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

© www.soinside.com 2019 - 2024. All rights reserved.