2010-07-30 45 views
55

Tôi đang cố gắng để lấy một danh sách các đối tượng từ Entity Framework qua WCF, nhưng tôi nhận được ngoại lệ sau đây:DataContractSerializer Lỗi sử dụng Entity Framework 4.0 với WCF 4,0

Có lỗi trong khi cố gắng để serialize tham số http://tempuri.org/:GetAllResult. Thông báo InnerException là 'Loại' Hệ thống.Data.Entity.DynamicProxies.TestObject_240F2B681A782799F3A0C3AFBE4A67A7E86083C3CC4A3939573C5410B408ECCE 'với tên hợp đồng dữ liệu' TestObject_240F2B681A782799F3A0C3AFBE4A67A7E86083C3CC4A3939573C5410B408ECCE: http://schemas.datacontract.org/2004/07/System.Data.Entity.DynamicProxies 'không được mong đợi. Hãy xem xét sử dụng một DataContractResolver hoặc thêm bất kỳ loại không được biết đến tĩnh vào danh sách các loại đã biết - ví dụ, bằng cách sử dụng thuộc tính KnownTypeAttribute hoặc bằng cách thêm chúng vào danh sách các kiểu đã biết được truyền cho DataContractSerializer. '. Vui lòng xem InnerException để biết thêm chi tiết.

Tôi đã sử dụng WCF trong quá khứ, nhưng không bao giờ có Khung thực thể. Tôi có tất cả các thực thể của mình được tạo thông qua Entity Framework và được chú thích với các thuộc tính [DataContract] và [DataMember]. Tôi không có Thuộc tính Điều hướng trên bất kỳ thực thể nào của tôi.

Các GetAll() phương pháp được gọi là trong một lớp dịch vụ trừu tượng:

[ServiceContract] 
public interface IService<T> 
{ 
    [OperationContract] 
    List<T> GetAll(); 
} 

Và tôi đang sử dụng ChannelFactory để gọi thực hiện của tôi:

Binding binding = new NetTcpBinding(); 
EndpointAddress endpointAddress = new EndpointAddress("net.tcp://localhost:8081/" + typeof(TestObjectService).Name); 
using (ChannelFactory<ITestObjectService> channel = new ChannelFactory<ITestObjectService>(binding, endpointAddress)) 
{ 
    ITestObjectService testObjectService = channel.CreateChannel(); 
    testObjects = testObjectService.GetAll(); 
    channel.Close(); 
} 

Tôi đang lưu trữ nó như vậy:

Type type = typeof(TestObjectService); 
ServiceHost host = new ServiceHost(type, 
      new Uri("http://localhost:8080/" + type.Name), 
      new Uri("net.tcp://localhost:8081/" + type.Name)); 
host.Open(); 

Khi sử dụng gỡ lỗi, nó tìm thấy các đối tượng từ cơ sở dữ liệu, tuy nhiên, nó là fai ling trả lại đồ vật.

Bất kỳ ý tưởng nào về nơi tôi có thể gặp sự cố?

Trả lời

88

Đây là một nỗi đau để tìm ra nhưng đó là bởi vì EntityFramework tạo ra một 'proxy' của lớp học của bạn. Lớp TestObject tôi đã có được thiết lập một cách chính xác, nhưng nó đã tạo ra một lớp được gọi là: TestObject_240F2B681A782799F3A0C3AFBE4A67A7E86083C3CC4A3939573C5410B408ECCE

Để thực hiện ChannelFactory + WCF + Entity Framework tất cả các công việc với nhau, bạn phải đi vào constructor Bối cảnh của bạn và thêm những điều sau đây:

ContextOptions.ProxyCreationEnabled = false; 

Tôi hy vọng điều này sẽ giúp người khác.

+1

Điều này đã giúp tôi rất nhiều. Nếu bạn gặp vấn đề được mô tả trong câu hỏi này, bạn cũng nên đọc http://stackoverflow.com/questions/4596371/what-are-the-downsides-to-turning-off-proxycreationenabled-for-ctp5-of-ef- code-f –

+0

Cảm ơn rất nhiều vì câu trả lời đó! – hupseb

+1

Tôi đã phải đúc DbContext của tôi đến một ObjectContext đầu tiên. Trong VB.NET, trông giống như 'DirectCast (Me, IObjectContextAdapter) .ObjectContext.ContextOptions.ProxyCreationEnabled = False' – BlueMonkMN

60

Khi sử dụng API DbContext Mã First (EF 4.3) tôi phải làm:

public class MyClass : DbContext 
{ 
    public MyClass() 
    { 
     base.Configuration.ProxyCreationEnabled = false; 
    } 
} 
+1

Tôi đã thêm điều này vào khuôn mẫu thực thể khung tt của tôi trong hàm tạo - giải pháp toàn cầu tuyệt vời. – JnJnBoo

18

Đối EntityFramework 6.0 Tôi đã phải thay đổi cấu hình cũng như:

public class MyContext : DbContext 
{ 
    public MyContext() : base("name=MyContext") 
    { 
     Configuration.ProxyCreationEnabled = false; 
    } 
} 
+1

Bạn đá !! 4 giờ gỡ lỗi r không bị lãng phí. thnx – Aki

4

Bạn có một vài khác các tùy chọn khác ngoài việc thêm không có proxy cho toàn bộ POCO của bạn:

1) Tạo trình bao bọc. Trong API, có khả năng bạn không muốn để lộ toàn bộ POCO cho người dùng của bạn ... để tạo đối tượng bao bọc chỉ hiển thị nội dung bạn muốn và điều này cũng giải quyết vấn đề proxy.

1.5) Khá giống như 1, nhưng thay vì tạo một wrapper, chỉ cần trả lại một anonymous type (với LINQ)

2) Nếu bạn không cần phải làm ứng dụng rộng rãi, nó có thể có ý nghĩa hơn để làm điều đó trong Controller nơi bạn cần mà serialization ... hoặc thậm chí nhiều địa phương đến một Method, bao gồm using, đây là một mỗi Controller thực hiện:

public class ThingController : ApiController 
{ 
    public ThingController() 
    { 
     db = new MyContext(); 
     db.Configuration.ProxyCreationEnabled = false; 
    } 

    private MyContext db; 

    // GET api/Thing 
    public IQueryable<Thing> GetThings() 
    { 
     return db.Things; 
    } 

    //... 

    protected override void Dispose(bool disposing) 
    { 
     if (disposing) 
      db.Dispose(); 

     base.Dispose(disposing); 
    } 
} 

3) một điều nữa là nếu bạn đang cần nó chỉ cho rằng cuộc gọi db , cách dễ nhất để thực hiện việc này là chuỗi AsNoTracking() vào cuộc gọi của bạn:

List<Thing> things; 
using (var db = new MyContext()) 
{ 
    things = db.Things.AsNoTracking().ToList(); 
} 
1

Thay vào đó, bạn có thể sử dụng DTO và trả lại điều đó. Không cần tắt thuộc tính Proxycreationenabled.

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