2015-12-16 16 views
5

Tôi có một bộ điều khiển WebAPI có dịch vụ tiêm bằng AutoFac trong lớp OWIN StartupEF + AutoFac + async "trạng thái hiện tại của kết nối được kết nối"

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

Tôi cũng đã cố gắng

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

Trong một hành động điều khiển, tôi gọi một phương thức dịch vụ để tạo một bản ghi mới, chuyển id được tạo tới api bên ngoài thông qua HttpClient để lấy thêm dữ liệu, sau đó cập nhật bản ghi mới với một số dữ liệu trả về.

[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(); 
} 

mã dịch vụ

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(); 
    } 
} 

Nhưng tôi nhận được một InvalidOperationException trong UpdateNewThing var thing = await _context.Things.SingleOrDefaultAsync(o => o.Id == id);

System.InvalidOperationException: The connection was not closed. The connection's current state is connecting. 

Có vẻ như tôi phải từ bỏ một trong hai cách tiêm bối cảnh, async/chờ đợi hoặc sử dụng một cái gì đó như bối cảnh; trừ khi bất cứ ai có thể phát hiện ra điều gì đó đơn giản mà tôi đã bỏ lỡ, điều đó sẽ cho phép tôi tiếp tục với thiết kế này.

+0

Dòng nào ném ngoại lệ? Bạn có thể cho thấy cách bạn chèn '_context' vào vùng chứa không? Có nơi nào bạn vứt bỏ bối cảnh không? Bạn có gọi 'CreateNewThing' và' UpdateNewThing' từ cùng một phương thức không? Bạn có thể hiển thị mã hoàn chỉnh hơn không? –

+0

Đã thêm mã khác. Tôi tiêm bối cảnh trong constructor lớp dịch vụ. Tôi không vứt bỏ bất cứ đâu. CreateNewThing và UpdateNewThing đều ở trong cùng một hành động WebApi. Tôi cần Id mới để gửi đến api bên ngoài và sau đó phải cập nhật bản ghi với một số dữ liệu trả về; thông thường tôi sẽ không gọi dịch vụ của tôi như thế này. –

+1

Tôi không thể thấy sự cố trong mã của bạn. Điều gì sẽ xảy ra nếu bạn không thực hiện cuộc gọi dịch vụ web và thay vào đó kiểm tra bằng một số dữ liệu 'externalData' giả mạo? –

Trả lời

1

Mã của bạn trông đẹp trong ngữ cảnh một luồng. Tuy nhiên, DbContext không phải là chủ đề an toàn và tôi nghi ngờ điều đang xảy ra là bạn đang thực hiện CreateNewThing() trên một chuỗi và trình lên lịch nhiệm vụ trong trường hợp này thực hiện UpdateNewThing() trên một luồng khác.

Hoặc bằng cách nào, một ẩn dụ tốt hơn là sử dụng một nhà máy hoàn cảnh, mà bạn tiêm vào IMyService của bạn trong trường hợp này, và sau đó cho mọi phương pháp IMyService bạn tạo một MyEntities bối cảnh mới trong một khối using().

DbContext giá rẻ để tạo và đây là cách chúng được dự định sẽ được sử dụng; bối cảnh tồn tại lâu dài hầu như luôn là việc sử dụng không chính xác.

Chỉnh sửa 1 - ví dụ nhà máy sản xuất ngữ cảnh theo yêu cầu. Tôi có xu hướng triển khai một nhà máy chung có thể tạo nhiều bối cảnh, nhưng điều đó có thể di chuyển ra ngoài phạm vi của câu hỏi này.

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; 
    } 
} 
+0

Cảm ơn, đây là những gì tôi nghi ngờ nhưng tôi không muốn sử dụng async hơn là sử dụng nó với một nửa sự hiểu biết về những gì nó đang làm. Tôi đã thấy một vài ví dụ về bối cảnh; tất cả đều khác. Bạn có một ví dụ của một trong những bạn đã sử dụng trước khi –

+0

Có rất nhiều ví dụ bởi vì bạn có thể làm điều đó khá nhiều tuy nhiên bạn thích miễn là nó tạo ra một bối cảnh. Tôi đã thêm một ví dụ khá cơ bản cho câu trả lời. – sellotape

+0

ok, do đó, chỉ cần một nhà máy đơn giản - không có công cụ ưa thích của EF cho SaveChanges. Cảm ơn –

Các vấn đề liên quan