Ошибка DataContractSerializer при использовании Entity Framework 4.0 с WCF 4.0 - PullRequest
56 голосов
/ 30 июля 2010

Я пытаюсь получить список объектов из Entity Framework через WCF, но получаю следующее исключение:

Там была ошибка при попытке сериализовать параметр http://tempuri.org/:GetAllResult. Сообщение InnerException был «Type„System.Data.Entity.DynamicProxies.TestObject_240F2B681A782799F3A0C3AFBE4A67A7E86083C3CC4A3939573C5410B408ECCE“с именем контракта данных» TestObject_240F2B681A782799F3A0C3AFBE4A67A7E86083C3CC4A3939573C5410B408ECCE: http://schemas.datacontract.org/2004/07/System.Data.Entity.DynamicProxies' не ожидается. Попробуйте использовать DataContractResolver или добавить любые типы, которые не известны статически, в список известных типов - например, с помощью атрибута KnownTypeAttribute или путем добавления их в список известных типов, передаваемых в DataContractSerializer. Пожалуйста, смотрите InnerException для более подробной информации.

Я использовал WCF в прошлом, но никогда не использовал Entity Framework. У меня есть все мои сущности, созданные с помощью Entity Framework, и они отмечены атрибутами [DataContract] и [DataMember]. У меня нет навигационных свойств ни на одном из моих объектов.

Вызываемый метод GetAll () находится в абстрактном классе обслуживания:

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

И я использую ChannelFactory для вызова своей реализации:

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

Я размещаю его так:

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

При использовании отладки он находит объекты из базы данных, однако не может вернуть объекты.

Любые идеи относительно того, где я могу пойти не так?

Ответы [ 5 ]

90 голосов
/ 30 июля 2010

Это было трудно понять, но это потому, что EntityFramework создает «прокси» вашего класса.Класс TestObject, который у меня был, был правильно настроен, но он создавал класс с именем: TestObject_240F2B681A782799F3A0C3AFBE4A67A7E86083C3CC4A3939573C5410B408ECCE

Чтобы заставить ChannelFactory + WCF + Entity Framework работать вместе, вы должны все вместе добавить в контекстную среду, в которую вы хотите добавить конструкцию ChannelFactory + WCF +: Структура Entity Framework, а также объект Entity Framework должны работать вместе: все объекты и контекстный фреймворк должны работать вместе: в вашей структуре контекста и в вашей структуре:1003 *

ContextOptions.ProxyCreationEnabled = false;

Надеюсь, это поможет кому-то еще.

60 голосов
/ 27 февраля 2012

При использовании API DbContext для Code First (EF 4.3) мне пришлось сделать:

public class MyClass : DbContext
{
    public MyClass()
    {
        base.Configuration.ProxyCreationEnabled = false;
    }
}
19 голосов
/ 25 января 2015

Для EntityFramework 6.0 мне также пришлось изменить конфигурацию:

public class MyContext : DbContext
{
    public MyContext() : base("name=MyContext")
    {
        Configuration.ProxyCreationEnabled = false;
    }
}
4 голосов
/ 18 июня 2015

У вас есть несколько других вариантов, кроме добавления прокси-сервера ко всему POCO:

1) Создайте оболочку.В API, скорее всего, вы не хотите показывать весь POCO своим пользователям ... поэтому создайте объект-оболочку, который предоставляет только то, что вам нужно, и это также решает проблему с прокси.

1.5) Почти как 1, но вместо создания оболочки просто верните anonymous typeLINQ)

2) Если вам не нужно делать это широко, приложение может сделатьбольше смысла делать это в Controller, где вам нужна эта сериализация ... или еще более локализовано в Method, включая using, вот реализация для Controller:

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) Другое дело, что если вам это нужно только для этого вызова базы данных, самый простой способ сделать это - включить AsNoTracking() в ваш вызов:

List<Thing> things;
using (var db = new MyContext())
{
    things = db.Things.AsNoTracking().ToList();
}
1 голос
/ 03 декабря 2016

Вместо этого вы можете использовать DTO и вернуть его. Нет необходимости отключать свойство Proxycreationenabled.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...