user1307149 user1307149 - 2 months ago 16
C# Question

POCO class not returned from WCF

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)

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.

Comments