开发者

C# WCF Server retrieves 'List<T>' with 1 entry, but client doesn't receive it

开发者 https://www.devze.com 2022-12-27 05:24 出处:网络
I am trying to retrieve a list of clients from the server (server using fluentNHibernate). The client object is as follows:

I am trying to retrieve a list of clients from the server (server using fluentNHibernate). The client object is as follows:

[DataContract]
//[KnownType(typeof(System.Collections.Generic.List<ContactPerson>))]
//[KnownType(typeof(System.Collections.Generic.List<Address>))]
//[KnownType(typeof(System.Collections.Generic.List<BatchRequest>))]
//[KnownType(typeof(System.Collections.Generic.List<Discount>))]
[KnownType(typeof(EClientType))]
[KnownType(typeof(EComType))]
public class Client
{
    #region Properties

[DataMember]
public virtual int ClientID { get; set; }

[DataMember]
public virtual EClientType ClientType { get; set; }

[DataMember]
public virtual string RegisterID {get; set;}

[DataMember]
public virtual string HerdCode { get; set; }

[DataMember]
开发者_JS百科public virtual string CompanyName { get; set; }

[DataMember]
public virtual bool InvoicePerBatch { get; set; }

[DataMember]
public virtual EComType ResultsComType { get; set; }

[DataMember]
public virtual EComType InvoiceComType { get; set; }



//[DataMember]
//public virtual IList<ContactPerson> Contacts { get; set; }

//[DataMember]
//public virtual IList<Address> Addresses { get; set; }

//[DataMember]
//public virtual IList<BatchRequest> Batches { get; set; }

//[DataMember]
//public virtual IList<Discount> Discounts { get; set; }

#endregion

#region Overrides

public override bool Equals(object obj)
{
    var other = obj as Client;
    if (other == null)
        return false;
    return other.GetHashCode() == this.GetHashCode();
}

public override int GetHashCode()
{
    return ClientID.GetHashCode() | ClientType.GetHashCode() | RegisterID.GetHashCode() |
            HerdCode.GetHashCode() | CompanyName.GetHashCode() | InvoicePerBatch.GetHashCode() |
            ResultsComType.GetHashCode() | InvoiceComType.GetHashCode();// | Contacts.GetHashCode() |
            //Addresses.GetHashCode() | Batches.GetHashCode() | Discounts.GetHashCode();
}

#endregion
}

I have already tried to remove the sub-lists, though even with this simplified version of the client I still run into the problem.

My fluent mapping is:

public class ClientMap : ClassMap<Client>
    {
        public ClientMap()
        {
            Table("Clients");
            Id(p => p.ClientID);

            Map(p => p.ClientType).CustomType<EClientType>(); ;
            Map(p => p.RegisterID);
            Map(p => p.HerdCode);
            Map(p => p.CompanyName);
            Map(p => p.InvoicePerBatch);
            Map(p => p.ResultsComType).CustomType<EComType>();
            Map(p => p.InvoiceComType).CustomType<EComType>();

            //HasMany<ContactPerson>(p => p.Contacts)
            //    .KeyColumns.Add("ContactPersonID")
            //    .Inverse()
            //    .Cascade.All();

            //HasMany<Address>(p => p.Addresses)
            //    .KeyColumns.Add("AddressID")
            //    .Inverse()
            //    .Cascade.All();

            //HasMany<BatchRequest>(p => p.Batches)
            //    .KeyColumns.Add("BatchID")
            //    .Inverse()
            //    .Cascade.All();

            //HasMany<Discount>(p => p.Discounts)
            //    .KeyColumns.Add("DiscountID")
            //    .Inverse()
            //    .Cascade.All();

        } 

The client method, seen below, connects to the server. The server retrieves the list, and everything looks right in the object, still, when it returns, the client doesn't receive anything (it receive a List object, but with nothing in it.

Herewith the calling method:

public List<s.Client> GetClientList()
        {
            try
            {
                s.DataServiceClient svcClient = new s.DataServiceClient();
                svcClient.Open();

                List<s.Client> clients = new List<s.Client>();

                clients = svcClient.GetClientList().ToList<s.Client>();

                svcClient.Close(); //when receiving focus from server, the clients object has a count of 0

                return clients;
            }
            catch (Exception e)
            {
                MessageBox.Show(e.Message);
            }
            return null;
        }

and the server method:

public IList<Client> GetClientList()
        {
            var clients = new List<Client>();

            try
            {
                using (var session = SessionHelper.OpenSession())
                {
                    clients = session.Linq<Client>().Where(p => p.ClientID > 0).ToList<Client>();
                }
            }
            catch (Exception e)
            {
                EventLog.WriteEntry("eCOWS.Data", e.Message);
            }

            return clients; //returns a list with 1 client in it
        }

The server method interface is:

 [UseNetDataContractSerializer]
        [OperationContract]
        IList<Client> GetClientList();

For final reference, here are my client app.config entries:

 <system.serviceModel>

        <bindings>
            <netTcpBinding>
                <binding name="NetTcpBinding_IDataService" listenBacklog="10" maxConnections="10"
                         transferMode="Buffered" transactionProtocol="OleTransactions"
                         maxReceivedMessageSize="2147483647" maxBufferSize="2147483647" 
                         receiveTimeout="00:10:00" sendTimeout="00:10:00">
                      <readerQuotas maxDepth="51200000" maxStringContentLength="51200000" 
                                    maxArrayLength="51200000" maxBytesPerRead="51200000" 
                                    maxNameTableCharCount="51200000" />
                  <security mode="Transport"/>
                </binding>
            </netTcpBinding>
        </bindings>

        <client>
            <endpoint address="net.tcp://localhost:9000/eCOWS/DataService"
                binding="netTcpBinding" bindingConfiguration="NetTcpBinding_IDataService"
                contract="eCowsDataService.IDataService" name="NetTcpBinding_IDataService"
                behaviorConfiguration="eCowsEndpointBehavior">
            </endpoint>

           <endpoint address="MEX"
                     binding="mexHttpBinding"
                     contract="IMetadataExchange" />

        </client>

        <behaviors>
          <endpointBehaviors>
            <behavior name="eCowsEndpointBehavior">
              <dataContractSerializer maxItemsInObjectGraph="2147483647"/>
            </behavior>
          </endpointBehaviors>
        </behaviors>

    </system.serviceModel>

and my server app.config:

    <system.serviceModel>

      <bindings>
        <netTcpBinding>
          <binding name="netTcpBinding"
                   maxConnections="10" listenBacklog="10"
                   transferMode="Buffered" transactionProtocol="OleTransactions" 
                   maxBufferSize="2147483647" maxReceivedMessageSize="2147483647"
                   sendTimeout="00:10:00" receiveTimeout="00:10:00">
            <readerQuotas maxDepth="51200000" maxStringContentLength="51200000" 
                          maxArrayLength="51200000" maxBytesPerRead="51200000" 
                          maxNameTableCharCount="51200000" />
            <security mode="Transport"/>
          </binding>
        </netTcpBinding>
      </bindings>

      <services>
      <service name="eCows.Data.Services.DataService" behaviorConfiguration="eCowsServiceBehavior">

        <host>
          <baseAddresses>
            <add baseAddress="http://localhost:9001/eCOWS/" />
            <add baseAddress="net.tcp://localhost:9000/eCOWS/" />
          </baseAddresses>
        </host>

        <endpoint address="DataService" 
                  binding="netTcpBinding" 
                  contract="eCows.Data.Services.IDataService"
                  behaviorConfiguration="eCowsEndpointBehaviour">
        </endpoint>

        <endpoint address="MEX"
                  binding="mexHttpBinding"
                  contract="IMetadataExchange" />
      </service>
    </services>

    <behaviors>
      <endpointBehaviors>
        <behavior name="eCowsEndpointBehaviour">
          <dataContractSerializer maxItemsInObjectGraph="2147483647" />
        </behavior>
      </endpointBehaviors>      
      <serviceBehaviors>
        <behavior name="eCowsServiceBehavior">
          <serviceMetadata httpGetEnabled="True"/>
          <serviceThrottling maxConcurrentCalls="10" maxConcurrentSessions="10"/>
          <serviceDebug includeExceptionDetailInFaults="False" />
        </behavior>
        <behavior name="MexBehaviour">
          <serviceMetadata />
        </behavior>
      </serviceBehaviors>
    </behaviors>

  </system.serviceModel>

I use to run into "socket closed / network or timeout" errors, and the trace showed clearly that on the callback it was looking for a listening endpoint, but couldn't find one. Anyway, after adding the UseNetSerializer that error went away, yet now I'm just not getting anything.

PS. If I add all the commented out List items, I still retrieve an entry from the DB, but also still not receive anything on the client.

If I remove the [UseNetDataContractSerializer] I get the following error(s) in the svclog:

WARNING: Description Faulted System.ServiceModel.Channels.ServerSessionPreambleConnectionReader+ServerFramingDuplexSessionChannel

WARNING: Description Faulted System.ServiceModel.Channels.ServiceChannel

ERROR: Initializing[eCows.Data.Models.Client#3]-failed to lazily initialize a collection of role: eCows.Data.Models.Client.Addresses, no session or session was closed

...

ERROR: Could not find default endpoint element that references contract 'ILogbookManager' in the ServiceModel client configuration section. This might be because no configuration file was found for your application, or because no endpoint element matching this contract could be found in the client element.

If I add a .Not.LazyLoad to the List mapping items, I'm back at not receiving errors, but also not receiving any client information.


With WCF you need to use concrete types not interfaces. Start off by using List<Client> instead of IList<Client>, or use simple arrays Client[]. (It is possible to use interfaces, but thats a lot more work.)

The actual problem here is that Linq returns an runtime type that you can't specify in your data contract.

Sample copy of your server method:

public Client[] GetClientList()
{
    try
    {
        using (var session = SessionHelper.OpenSession())
        {
            return session.Linq<Client>().Where(p => p.ClientID > 0).ToArray<Client>();
        }
    }
    catch (Exception e)
    {
        EventLog.WriteEntry("eCOWS.Data", e.Message);
        return null;
    }
}
0

精彩评论

暂无评论...
验证码 换一张
取 消