C# DbContext在使用异步任务方法时被释放

C# DbContext在使用异步任务方法时被释放,c#,angularjs,asp.net-web-api,async-await,C#,Angularjs,Asp.net Web Api,Async Await,我目前正在使用异步任务方法来实现IAAuthenticationFilter接口。成功登录后,我将尝试访问具有此属性的API,它将正常工作。但是,一旦我返回并再次访问API,就会抛出异常 public async Task AuthenticateAsync(HttpAuthenticationContext context, CancellationToken cancellationToken) { var token = context.Request.Headers.Author

我目前正在使用异步任务方法来实现IAAuthenticationFilter接口。成功登录后,我将尝试访问具有此属性的API,它将正常工作。但是,一旦我返回并再次访问API,就会抛出异常

public async Task AuthenticateAsync(HttpAuthenticationContext context, CancellationToken cancellationToken)
{
    var token = context.Request.Headers.Authorization.Parameter;
    var principal = await AuthenticateToken(token)
    // Other code here ... 
}

protected Task<IPrincipal> AuthenticateToken(string token)
{
    var secretKey = _authenticationBusiness.GetSecretKey(); // error triggers here.

    if (principal == null)
        context.ErrorResult = new AuthenticationFailureResult("Invalid token", request);
    else
        context.Principal = principal;
}

//AuthenticationBusiness.cs
public string GetSecretKey()
{
    using (_unitOfWork)
    {
        var token = _unitOfWork.Tokens.GetToken();

        return token.SecretKey ?? string.Empty;
    }
}

//Dependency Injection using Unity
    container.RegisterType<IUnitOfWork, UnitOfWork>(new HierarchicalLifetimeManager());
    container.RegisterType<IContext, Context>(new HierarchicalLifetimeManager());

//UnitOfWork.cs
private readonly IContext _context;

public UnitOfWork(IContext context, IJWTRepository tokens)
{
    _context = context;
    Tokens = tokens;
}

public IJWTRepository Tokens { get; private set; }

public void Dispose()
{
    _context.Dispose();
}


//Context.cs
public class Context : DbContext, IContext
{
    public new void SaveChanges()
    {
        base.SaveChanges();
    }

    public new void Dispose()
    {
        base.Dispose();
    }
}

//JWTRepository.cs
public class JWTRepository : Repository<JsonWebToken>, IJWTRepository
{
    public JWTRepository(Context context) : base(context) { }

    public JsonWebToken GetToken()
    {
        return Context.Tokens
            .OrderBy(jwt => jwt.Id)
            .Take(1)
            .SingleOrDefault();
    }

    private Context Context => _context as Context;
}
public异步任务authenticateSync(HttpAuthenticationContext,CancellationToken CancellationToken)
{
var token=context.Request.Headers.Authorization.Parameter;
var principal=Wait AuthenticateToken(令牌)
//其他代码在这里。。。
}
受保护的任务AuthenticateToken(字符串令牌)
{
var secretKey=\u authenticationBusiness.GetSecretKey();//此处会触发错误。
if(principal==null)
context.ErrorResult=新身份验证失败结果(“无效令牌”,请求);
其他的
context.Principal=Principal;
}
//AuthenticationBusiness.cs
公共字符串GetSecretKey()
{
使用(_unitOfWork)
{
var token=_unitOfWork.Tokens.GetToken();
return token.SecretKey??string.Empty;
}
}
//使用Unity的依赖注入
RegisterType(新的层次结构CallifetimeManager());
RegisterType(新的层次结构CallifetimeManager());
//UnitOfWork.cs
私有只读IContext\u上下文;
公共UnitOfWork(IContext上下文、IJWTRepository令牌)
{
_上下文=上下文;
代币=代币;
}
公共存储库令牌{get;private set;}
公共空间处置()
{
_context.Dispose();
}
//Context.cs
公共类上下文:DbContext、IContext
{
public new void SaveChanges()
{
base.SaveChanges();
}
公开新的无效处置()
{
base.Dispose();
}
}
//JWTRepository.cs
公共类JWTRepository:Repository,IJWTRepository
{
公共JWTRepository(上下文):基(上下文){}
公共JsonWebToken GetToken()
{
返回Context.Tokens
.OrderBy(jwt=>jwt.Id)
.采取(1)
.SingleOrDefault();
}
私有上下文=>\u上下文作为上下文;
}
如果我尝试删除该属性并多次访问API,则不会发生任何错误,因此我假设这与该属性具有异步方法这一事实有关

当IDisposable对象的生存期限制为单个 方法,您应该在using语句中声明并实例化它。 using语句调用中对象的Dispose方法 正确的方式,并且(当您如前所示使用它时),它也会导致 对象本身在调用Dispose后立即超出范围。在内部 使用块时,对象为只读,无法修改或删除 重新分配

在代码中,问题是您正在将
GetSecretkey()
包装到
using()
中,这将处理
\u unitOfWork
,当您再次尝试访问它时,它将显示一个错误

希望这段代码对你有用

//AuthenticationBusiness.cs

public string GetSecretKey()
{
    var token = _unitOfWork.Tokens.GetToken();

    return token.SecretKey ?? string.Empty;
}

函数中的问题
AuthenticateToken
。使用async await时,如果任务处理项目,请确保在返回前等待每个任务。看见第一个答案集中在一次性物品上

我假设您省略了方法
AuthenticateToken
的部分,因为我没有说返回值

解决方案:将方法声明为异步,并在返回之前等待任务

async Task<IPrincipal> AuthenticateToken(string token)
{
    var secretKey = _authenticationBusiness.GetSecretKey(); 
    ...
    // Somewhere there is a Task involved, 
    Task<IPrincipal> myTask = ...

    // instead of return myTask:
    return await myTask;
}
异步任务AuthenticateToken(字符串令牌)
{
var secretKey=_authenticationBusiness.GetSecretKey();
...
//某个地方有一项任务,
任务myTask=。。。
//而不是返回myTask:
返回等待我的任务;
}

这是因为您正在处理它。您的
GetSecretKey()
被包装在
using()
中,它将处理
\u unitOfWork
using()基本上会在项目超出范围时处理它。如果您正在执行任何其他异步操作(如果您返回一个任务等,我假设情况就是如此),那么您可能还希望将CancellationToken传递到AuthenticateToken()方法中。@JohanP:如果处理是问题所在,那么当我删除此属性时,它如何工作正常?这意味着,如果我尝试在没有IAAuthenticationFilter的情况下多次访问API,一切正常。@GlennWatson:AuthenticateToken方法中没有异步方法。我更新了该方法。当您多次访问该方法时,您将获得一个新的上下文,DI将为每个请求注入一个新的上下文,当您拥有筛选器时,请求中的上下文仍然相同,您在一个请求中多次访问unitOfWork。它就像一个符咒。但是,如果抛出异常,比如在
\u unitOfWork.Tokens.GetToken()处,我将如何正确地处理_unitOfWork?@JoshMonreal您的DI将为您处理它,经验法则是创建对象的东西负责处理它。