2013-02-19 3 views
1

[EDIT] Теперь я редактировал конструктор D и код вызова в методах клиента и OnDeserializing() и OnDeserialized().Передача объекта с использованием DataContract в WCF

У меня есть служба WCF (поверх именованной трубы) и клиент. Мне нужно передать объект (и предпочтительно ссылку на этот объект) в качестве аргумента моего OperationContract.

[DataContract] 
public class D 
{ 
    [DataMember] 
    public int Id; 

    [DataMember] 
    public string StrId; 

    //... 


    public D(int id, string strid) 
    { 
     Id = id; 
     StrId = strid; 
     //... 
    } 

    [OnDeserialized] 
    void OnDeserialized(StreamingContext strmCtx) 
    { 
    } // breakpoint here (1) 

    [OnDeserializing] 
    void OnDeserializing(StreamingContext strmCtx) 
    { 
    } // breakpoint here (2) 

} 

и это контракт на обслуживание:

[ServiceContract] 
public interface ICalc 
{ 
    [OperationContract] 
    int Calculate(string date, int count); 

    // d is input of this method, and count and array are outputs. 
    [OperationContract] 
    int getArray(ref int count, ref int[] array, D d); 
} 

Это мой код клиента, где GetArray вызывается:

proxy.getArray(ref myCount, ref myIntArray, new D(source)) 

Я также попытался это:

D d = new D(source) 
proxy.getArray(ref myCount, ref myIntArray, d) 

Очевидно, что это не изменить что-либо, в обоих случаях, когда я получаю d в служебном коде (код метода getArray), все его поля равны нулю. Почему это? Есть что-то, чего я не хватает?

Я знаю, что (используя разрешающие трассы и просматривая сообщения на транспортном уровне) на уровне транспортного уровня поля правильно переносятся на провод. Я также добавил методы OnDeserialized() и OnDeserializing() к объекту, чтобы я мог разместить там точку останова, в точках останова (1) и (2) все поля равны нулю! !! на самом деле объектные сеттеры вообще не называются !!

Я бегу из идей здесь ....

+1

Вы уверены, что ваша настоящая реализация 'D', как показано? Может быть, проблема с инициализацией полей в ctor или что-то еще? – UserControl

+0

Спасибо, да, у меня есть конструктор, я отредактировал свое сообщение, чтобы это отразить. есть ли что-то явно неправильное? – jambodev

+1

Я бы постарался добавить default 'ctor' (' protected', поскольку вы, вероятно, не хотите, чтобы это было 'public'). Возможно, это вызывает проблему десериализации. – UserControl

ответ

4

WCF являются данные ориентированные (сериализованная XML), а не объектно-ориентированный язык. Это не сработает!

Ваша работа службы:

[OperationContract] 
int getArray(ref int count, ref int[] array, D d); 

возвращает значение данных междунар. Если вы хотите получить значение int и значение массива, я бы рекомендовал вам создать для него [DataContract], содержащий оба значения. Таким образом, они будут передаваться клиенту как данные.

Вызов операции обслуживания с помощью (ref int []) не изменит ситуацию.

Обновление с помощью некоторого кода: Извините, но я не могу определить вашу ошибку. Вот небольшой пример (который работает), с которым можно сравнить. Если вы все еще не можете исправить ошибку, я предлагаю вам опубликовать весь код и конфигурацию.

using System.Runtime.Serialization; 
using System.ServiceModel; 

namespace WcfService2 
{ 
    [ServiceContract] 
    public interface IService1 
    { 
     [OperationContract] 
     string GetData(InputData value); 
    } 

    [DataContract] 
    public class InputData 
    { 
     [DataMember] 
     public int[] Array { get; set; } 
     [DataMember] 
     public D SomeStuff { get; set; } 
    } 

    [DataContract] 
    public class D 
    { 
     [DataMember] 
     public int Id { get; set; } 
    } 
} 

using System; 

namespace WcfService2 
{ 
    public class Service1 : IService1 
    { 
     public string GetData(InputData data) 
     { 
      if (data.Array == null || data.SomeStuff == null) 
       throw new NullReferenceException(); 
      return "OK!"; 
     } 
    } 
} 

using ConsoleApplication9.ServiceReference; 
using System; 

namespace ConsoleApplication9 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      var proxy = new Service1Client(); 
      var request = new InputData 
       { 
        Array = new int[] {1, 2, 3}, 
        SomeStuff = new D {Id = 42} 
       }; 
      Console.WriteLine(proxy.GetData(request)); 
      Console.ReadKey(); 
     } 
    } 
} 
+0

Вы говорите, что WCF не может сериализовать мой объект на стороне клиента и отправить его, а на сервере создать новый экземпляр объекта и назначить значения полей, десериализуя переданный объект? – jambodev

+0

Что вы говорите, не будет работать? Вы, конечно же, можете передавать объекты, WCF будет просто обрабатывать его по-разному. – Sam

+0

@ это не объект, который проходит, его данные, и они становятся сериализованными на стороне клиента и сервера. Это была моя точка зрения. – Jocke

1

У вас есть конструктор по умолчанию, поскольку WCF не поймет его, если это не так.

Также - ref int[] array - массивы передаются как ссылочные типы в любом случае.

+0

У меня есть общедоступный конструктор по умолчанию, но значения полей на стороне службы все еще нулевые, это сводит меня с ума. как я могу включить трассировку, чтобы я мог видеть, что сериализуется на стороне клиента, я предполагаю, что могу использовать SvcTraceViewer.exe для отслеживания? – jambodev

0

Спасибо за все ваши ответы и ответы. Наконец, я решил это. Как только я положил D, в своей собственной сборке и ссылался на нее как со службы, так и с клиентом, все это начало работать.

0

У меня была такая же проблема после группировки некоторых параметров в класс DataContract.

У меня на самом деле было два клиента, один из которых с помощью общей сборки интерфейса с сервером работал нормально. Другой клиент, использующий копию кода ServiceContract и DataContract, не работал, и все члены моей серверной части параметра DataContract равны 0 или null, как описано выше.

Проблема возникает из-за пространства имен, в которое я поместил свой DataContract в свой клиент. Я позаботился о том, чтобы поместить мой DataContract в то же пространство имен, что и в сборке основных клиентов, и это устранило мою проблему. Фактически я помещаю все свои контрактные классы в одно и то же пространство имен, кроме Callback one. Так что, возможно, это была не просто проблема с DataContract. Хотя он отлично работает, когда не использует DataContract, поэтому я думаю, что это единственное, что вызывало проблему.

Надеюсь, что это имеет смысл.