c# - EF + AutoFac + async "The connection' s 当前状态正在连接”

标签 c# async-await entity-framework-6 asp.net-web-api2 autofac

我有一个 WebApi Controller ,它具有由 AutoFac 在 OWIN 启动类中注入(inject)的服务

builder.Register(c => new MyEntities()).InstancePerRequest();

我也试过

builder.Register(c => new MyEntities()).InstancePerLifetimeScope();

在 Controller 操作中,我调用服务方法来创建新记录,通过 HttpClient 将创建的 ID 传递给外部 api 以获取更多数据,然后使用一些返回数据更新新记录。

[HttpPost, Route("")] 
public async Task<IHttpActionResult> MyControllerAction(MyModel model)
{
    var id = await _MyService.CreateNewThing(model.SomeId);
    var externalData = await CallExternalApiThroughHttpClient(id);
    await _MyService.UpdateNewThing(id, externalData);
    return Ok();
}

服务代码

public class MyService : IMyService 
{
    private MyEntities _context;

    public MyService(MyEntities context)
    {
        _context = context;
    }

    public async Task<int> CreateNewThing(int someId)
    {
        var thing = new Thing
        {
            SomeId = someId
        };

        _context.Things.Add(thing);

        await _context.SaveChangesAsync();

        return thing.Id;
    }

    public async Task UpdateNewThing(int id, string externalDataField)
    {
        var thing = await _context.Things.SingleOrDefaultAsync(o => o.Id == id);

            if (thing == null)
            {
                throw new ServiceNotFoundException("Thing " + transactionId + " not found");
            }

            thing.ExternalDataField= externalDataField;

            await _context.SaveChangesAsync();
    }
}

但是我在 UpdateNewThing var thing = await _context.Things.SingleOrDefaultAsync(o => o.Id == id);

中得到一个 InvalidOperationException
System.InvalidOperationException: The connection was not closed. The connection's current state is connecting.

看来我不得不放弃注入(inject)上下文、async/await 或使用上下文工厂之类的东西;除非有人能发现我遗漏的一些简单的东西,否则我会继续这个设计。

最佳答案

您的代码在单线程上下文中看起来不错。但是,DbContext 不是线程安全的,我怀疑发生的事情是您在一个线程上执行 CreateNewThing(),而任务调度程序在这种情况下执行 UpdateNewThing() 在不同的线程上。

无论哪种方式,一个更好的比喻是使用上下文工厂,在本例中将其注入(inject)到 IMyService 中,然后为每个 IMyService 方法创建一个新的MyEntities 上下文在 using() block 中。

DbContext 的创建成本很低,这就是它们的用途;长期存在的上下文几乎总是不正确的用法。

编辑 1 - 根据要求示例上下文工厂。我倾向于实现一个可以创建多个上下文的通用工厂,但这可能超出了这个问题的范围。

public interface IMyEntitiesFactory
{
    MyEntities Create();
}

public class MyEntitiesFactory : IMyEntitiesFactory
{
    MyEntities IMyEntitiesFactory.Create()
    {
        return new MyEntities();
    }
}

// For use with unit tests; e.g. pass a mock object to the constructor.
public class TestMyEntitiesFactory : IMyEntitiesFactory
{
    private readonly MyEntities _value;

    public TestMyEntitiesFactory(MyEntities value)
    {
        _value = value;
    }

    MyEntities IMyEntitiesFactory.Create()
    {
        return _value;
    }
}

关于c# - EF + AutoFac + async "The connection' s 当前状态正在连接”,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34308008/

相关文章:

node.js - 使用 Mongoose 异步保存多个文档

c# - ASP Identity 用户和其他表之间的 Entity Framework 映射 - 更改 Id 列

c# - 如何忽略特定派生类的基类中的 'shared' NUnit 测试

c# - 通过 SSL 使用 HttpWebRequest 发送请求时出现错误 502(错误的网关)

javascript - 在 for 循环 VueJS 中同步 API 调用

c# - Entity Framework .First() 缓存查询数据

c# - 将只读属性分配给 Entity Framework 中的新对象

c# - 方法 'Skip' 仅支持 LINQ to Entities 中的排序输入

c# - 从第三个项目中的两个 C# 项目调用表单

python asyncio 在 key 可用时通过 key 从字典中异步获取数据