Client WCF DataContract имеет пустые/нулевые значения из службы
-
22-09-2019 - |
Вопрос
У меня есть простая служба WCF, которая возвращает время с сервера. Я подтвердил, что данные отправляются путем проверки с Fiddler. Вот объект результата XML, который отправляет моя служба.
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<GetTimeResponse xmlns="http://tempuri.org/">
<GetTimeResult xmlns:a="http://schemas.datacontract.org/2004/07/TestService.DataObjects" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<a:theTime>2010-03-26T09:14:38.066372-06:00</a:theTime>
</GetTimeResult>
</GetTimeResponse>
</s:Body>
</s:Envelope>
Итак, насколько я могу судить, в конце сервера нет ничего плохого. Это получает запросы и возвращающиеся результаты.
Но на моем клиенте Silverlight все участники возвращаемого объекта либо нулевые, пустые или далеку по умолчанию. Как видите, сервер возвращает текущую дату и время. Но в Silverlight свойство на моем объекте установлено на 1/1/10001 12:00 (значение по умолчанию).
Ооочень меняется, что обработка данных не совпадает между сервером и клиентом Silverlight. Вот образный данных для сервера
[DataContract]
public class Time
{
[DataMember]
public DateTime theTime { get; set; }
}
Невероятно просто. А вот и обработка данных на моем клиенте Silverlight.
[DataContract]
public class Time
{
[DataMember]
public DateTime theTime { get; set; }
}
Буквально единственное отличие - это пространства имен в приложении. Но все же возвращаемые значения являются нулевыми, пустыми или .NET по умолчанию.
Спасибо за помощь!
ОБНОВИТЬ
Вот клиентская база, через которую проходят все мои услуги. Я читаю Отличная статья здесь чтобы построить его.
public class ClientBase<T> where T :class
{
private T Channel { get; set; }
private Type ContractType { get; set; }
private ClientBase()
{
ContractType = typeof( T );
}
public ClientBase(string endPointConfiguration) :this()
{
Channel = new ChannelFactory<T>( endPointConfiguration ).CreateChannel();
}
public ClientBase( EndpointAddress address, Binding binding ):this()
{
Channel = new ChannelFactory<T>( binding, address ).CreateChannel();
}
public void Begin(string methodName, object state, params object[] parameterArray)
{
Begin( methodName, null, state, parameterArray );
}
public void Begin(string methodName, EventHandler<ClientEventArgs> callBack, object state, params object[] parameterArray)
{
if(parameterArray != null)
{
Array.Resize(ref parameterArray, parameterArray.Length + 2);
}
else
{
parameterArray = new object[2];
}
parameterArray[ parameterArray.Length - 1 ] = new ObjectClientState {CallBack = callBack, MethodName = methodName, UserState = state};
parameterArray[ parameterArray.Length - 2 ] = new AsyncCallback( OnCallBack );
ContractType.InvokeMember( "Begin" + methodName,
System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.InvokeMethod |
System.Reflection.BindingFlags.Public, null, Channel, parameterArray );
}
private void OnCallBack(IAsyncResult result)
{
ObjectClientState state = result.AsyncState as ObjectClientState;
if(state == null)
return;
Object obj = ContractType.InvokeMember( "End" + state.MethodName,
System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.InvokeMethod |
System.Reflection.BindingFlags.Public, null, Channel, new object[] {result} );
if(state.CallBack != null)
{
state.CallBack( this, new ClientEventArgs {Object = obj, UserState = state.UserState} );
}
}
public class ClientEventArgs : EventArgs
{
public object Object { get; set; }
public object UserState { get; set; }
public T LoadResult<T>()
{
if( Object is T )
return ( T ) Object;
return default( T );
}
}
private class ObjectClientState
{
public EventHandler<ClientEventArgs> CallBack { get; set; }
public string MethodName { get; set; }
public object UserState { get; set; }
}
}
Вот мой интерфейс
[ServiceContract]
public interface ITestService
{
[OperationContract( AsyncPattern = true )]
IAsyncResult BeginGetTime( AsyncCallback callback, object state );
Time EndGetTime( IAsyncResult result );
}
Теперь у меня есть мой класс услуг, который делает звонки через мой класс BaseRervice, используя этот интерфейс.
public class TestSiteService : ClientBase<ITestService>
{
public TestSiteService (string endPointConfiguration):base(endPointConfiguration) { }
public TestSiteService ( EndpointAddress address, Binding binding ) : base( address, binding ) { }
public void GetTime( EventHandler<ClientEventArgs> callBack )
{
Begin( "GetTime", callBack, null, null );
}
}
Наконец, вот код, который на самом деле называет все и делает работу.
TestSiteService client = new TestSiteService ( new EndpointAddress( "http://localhost:3483/wcf/Service.svc" ), new BasicHttpBinding() );
client.GetTime( delegate( object res, ClientBase<ITestService>.ClientEventArgs e )
{
Dispatcher.BeginInvoke( () => lblDisplay.Text = "Welcome " + e.LoadResult<Time>().theTime );
} );
Вот ... Я надеюсь, что никто не потерян из всего этого кода, который я опубликовал: P
Решение
Потому что ты не устанавливаешь Свойство пространства имен На вашем DataContractattribute пространство имен будет отстранено из пространства класса/имен .NET. Вы можете увидеть это в примере сообщения SOAP, который вы опубликовали:
http://schemas.datacontract.org/2004/07/Testservice.dataobjects
Чтобы договоры считались равными, вы должны установить свойство пространства имен на обратном данных на одно и то же значение с обеих сторон. Это может выглядеть немного подобным:
[DataContract(Namespace="urn:my-test-namespace")]
Другие советы
Расширение правильного ответа Дрю Марша (+1 - thx) У меня была сгенерированная ссылка на обслуживание, которая работала, но когда я попытался использовать клиентскую фабрику WCF, реализуя правильный интерфейс (но пространство имен было другим), тогда я испытывал проблему описанный
У меня не было простого способа выяснить, каким должно быть «правильное» пространство имен, но просто копировать следующие атрибуты из объекта DataContract DataContract службы в тот, который в реализации клиентской фабрики WCF решила проблему;
[System.Runtime.Serialization.DataContractAttribute(Name = "BOSPrice", Namespace = "http://schemas.datacontract.org/2004/07/BOSDataService")]
[System.SerializableAttribute()]