POCO class not returned from WCF

c# entity-framework entity-framework-6 poco wcf

Question

I have 3 projects:

  1. DAL class library where I am using EF 6.1
  2. WCF service library
  3. WPF client app

The WPF app has a service reference to the WCF project. The problem I was having is when I was trying something like this:

public List<DbTable> GetItems()
{
    try
    {
        IQueryable<DbTable> items;
        using (var dbContext = new MyEntities())
        {                                        
            items = dbContext.Items.Select(a => a);
            return items.ToList();  
        }
    }
    catch (Exception ex)
    {
        Debug.WriteLine(ex);
        return null;
    }
}

The WCF Service was not returning any results and I was getting the generic HTTP not set correctly error message.

So after reading some I decided to create POCO classes in the WCF service and this worked.

using (var dbContext = new MyEntities())
{
   var items = dbContext.Items.Select(a =>
       new MyPocoClass
       {
           ItemId = a.ItemId,
           Name = a.Name
       });
   return items.ToList();
}

My question is can I not just return the entity framework object with out creating POCO classes to ferry the data back and forth? If I can am I missing a step or something?

Here is the message when I try returning any EF object

like return dbContext.Items.ToList();

The only way I can get it to work is by using a POCO class.

enter image description here

Update:

Here is my service config file:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <system.serviceModel>
    <services>
      <service name="MyProject.WebService.MyWebService">
        <endpoint address="" binding="basicHttpBinding" contract="MyProject.WebService.IMyWebService">
          <identity>
            <dns value="localhost" />
          </identity>
        </endpoint>
        <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
        <host>
          <baseAddresses>
            <add baseAddress="http://localhost:8733/Design_Time_Addresses/MyProject.WebService/MyWebService/" />
          </baseAddresses>
        </host>
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior>
          <serviceMetadata httpGetEnabled="True" httpsGetEnabled="True" />
          <serviceDebug includeExceptionDetailInFaults="True" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
  </system.serviceModel>
</configuration>

And my client:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <system.serviceModel>
    <bindings>
      <basicHttpBinding>
        <binding name="BasicHttpBinding_IMyWebService" maxBufferSize="2147483647" maxReceivedMessageSize="2147483647"/>
      </basicHttpBinding>
    </bindings>
    <client>
      <endpoint address="http://localhost:8733/Design_Time_Addresses/MyProject.WebService/MyWebService/" binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IMyWebService" contract="ServiceReference.IMyWebService" name="BasicHttpBinding_IMyWebService" />
    </client>
  </system.serviceModel>
</configuration>

Re-Update-

Inner Exception:
Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host.
   at System.Net.Sockets.NetworkStream.Read(Byte[] buffer, Int32 offset, Int32 size)
   at System.Net.PooledStream.Read(Byte[] buffer, Int32 offset, Int32 size)
1
2
3/23/2014 5:43:24 AM

Accepted Answer

This trouble occurs because the Entity Framework returns dynamic proxy objects with types that are derived from your original types and are created at runtime. To solve this, you should create a ProxyDataContractResolver attribute:

public class ApplyProxyDataContractResolverAttribute : Attribute, IOperationBehavior
{
    public void AddBindingParameters(
                  OperationDescription description,
                  BindingParameterCollection parameters)
    {
    }

    public void ApplyClientBehavior(
                  OperationDescription description,
                  ClientOperation proxy)
    {

        var dataContractSerializerOperationBehavior =
            description.Behaviors.Find<DataContractSerializerOperationBehavior>();
        dataContractSerializerOperationBehavior.DataContractResolver = new ProxyDataContractResolver();
    }

    public void ApplyDispatchBehavior(
                   OperationDescription description,
                   DispatchOperation dispatch)
    {
        var dataContractSerializerOperationBehavior =
            description.Behaviors.Find<DataContractSerializerOperationBehavior>();
        dataContractSerializerOperationBehavior.DataContractResolver =
            new ProxyDataContractResolver();
    }

    public void Validate(OperationDescription description)
    {
    }
}

Then apply this attribute to your service method, for example:

[ApplyProxyDataContractResolver]
public List<DbTable> GetItems()
{
// query to database with EF here
}

However, my advice is to use DTO conception. Using DTOs you may split your fat models into some small and transfer only information that your clients need. This makes your architecture more manageable and reduces amount of data transferring across the network.

2
9/29/2016 6:44:23 AM

Popular Answer

I think you should keep the DTO layer (POCOs) because as your model gets more complex, Lazy Loading causes all sorts of problems if you try to return the entities directly (depending on your data structure). For example, if you have a fairly standard relationship setup like:

  • One Client has many Contacts
  • One Contact has many Orders
  • One Order has many Line Items
  • One Line Item has many Store Inventory Level records
  • One Line Item has many Photographs
  • etc.

    public class Client
    {
      public int ClientId { get; set; }
      public string ClientName { get; set; }
      public IList<Contact> Contacts { get; set; }
    }
    
    public class Contacts
    {
      public int ContactId { get; set; }
      public string ContactName { get; set; }
      public IList<Order> Order { get; set; }
    }
    

When you try and pass a Client object over the WCF boundary, the serializer will touch each property in the Entity and load up related entities (Contacts, Orders, Line Items, Store Inventories, Photograhs).

This can cause a huge cascade of data loading, or fail due to circular references.

If you disable Lazy Loading, then your object is full of nulls, but there are plenty of other reasons not to pass entities around, such as not requiring a rebuild of client applications if you change your database structure etc.

If you find making the DTO -> Entity -> DTO mapping time consuming, take a look at AutoMapper, which can do this.

I find it helpful to write a unit test for this mapping with AutoFixture and DeepEqual.



Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow