С# WCF Server извлекает «List‹T›» с 1 записью, но клиент не получает его

Я пытаюсь получить список клиентов с сервера (сервер, использующий fluentNHibernate). Объект клиента выглядит следующим образом:

[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]
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
}

Я уже пытался удалить подсписки, хотя даже с этой упрощенной версией клиента я все еще сталкиваюсь с проблемой.

Мое свободное отображение:

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

        } 

Клиентский метод, показанный ниже, подключается к серверу. Сервер получает список, и в объекте все выглядит правильно, тем не менее, когда он возвращается, клиент ничего не получает (он получает объект List, но в нем ничего нет.

При этом метод вызова:

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

и метод сервера:

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
        }

Интерфейс метода сервера:

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

Для окончательной справки, вот мои клиентские записи app.config:

 <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>

и мой сервер 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>

Я использую, чтобы столкнуться с ошибками «сокет закрыт / сеть или тайм-аут», и трассировка ясно показала, что при обратном вызове он искал конечную точку прослушивания, но не смог ее найти. Во всяком случае, после добавления UseNetSerializer эта ошибка исчезла, но теперь я просто ничего не получаю.

PS. Если я добавлю все закомментированные элементы списка, я все равно извлеку запись из БД, но также ничего не получу на клиенте.

Если я удалю [UseNetDataContractSerializer], я получу следующие ошибки в svclog:

ПРЕДУПРЕЖДЕНИЕ. Описание Faulted System.ServiceModel.Channels.ServerSessionPreambleConnectionReader+ServerFramingDuplexSessionChannel

ВНИМАНИЕ: Описание Faulted System.ServiceModel.Channels.ServiceChannel

ОШИБКА: Initializing[eCows.Data.Models.Client#3] — не удалось лениво инициализировать набор ролей: eCows.Data.Models.Client.Addresses, сеанс или сеанс не был закрыт

...

ОШИБКА: не удалось найти элемент конечной точки по умолчанию, который ссылается на контракт «ILogbookManager» в разделе конфигурации клиента ServiceModel. Это может быть связано с тем, что для вашего приложения не найден файл конфигурации или с тем, что в клиентском элементе не удалось найти элемент конечной точки, соответствующий этому контракту.

Если я добавлю .Not.LazyLoad к элементам сопоставления списка, я вернусь к тому, что не буду получать ошибки, но также не буду получать информацию о клиенте.


person Neville    schedule 13.04.2010    source источник
comment
Вы говорите, что вызов svcClient.GetClientList() на стороне клиента не возвращает никаких элементов? Или вы говорите, что переменная client после client = svcClient.GetClientList().ToList‹s.Client›(); в строке нет элементов?   -  person DaveB    schedule 13.04.2010


Ответы (1)


С WCF вам нужно использовать конкретные типы, а не интерфейсы. Начните с использования List<Client> вместо IList<Client> или используйте простые массивы Client[]. (Можно использовать интерфейсы, но это намного больше работы.)

Фактическая проблема здесь заключается в том, что Linq возвращает тип времени выполнения, который вы не можете указать в своем контракте данных.

Пример копии вашего серверного метода:

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;
    }
}
person chilltemp    schedule 15.04.2010
comment
HI Chilltemp, спасибо за ваш ответ, я думаю, что это сработало, хотя не совсем уверен, так как теперь я получаю сообщение об ошибке, связанное с конечной точкой для iLogbookManager (возможно, связано с ServiceModelEx.dll?) Я пытаюсь найти решение для эта проблема с конечной точкой, после чего я смогу узнать, устранило ли ваше решение мою проблему, поскольку на данный момент я каждый раз получаю разрыв соединения. - person Neville; 19.04.2010
comment
При удаче? В предоставленном вами образце конфигурации отсутствует ILogbookManager. В файле конфигурации службы должен быть указан список всех конечных точек, реализованных классом узла, который вы создаете в качестве службы WCF. - person chilltemp; 19.04.2010
comment
Ну, какая большая задержка с возвращением к вам по этому поводу! Наверное, таков процесс переезда за границу :) Помню, ваш комментарий мне очень помог, и действительно поправил определенный раздел моего общения. Спасибо за помощь и извините за поздний ответ. - person Neville; 21.02.2011