客户端 WCF DataContract 具有来自服务的空/空值
Posted
技术标签:
【中文标题】客户端 WCF DataContract 具有来自服务的空/空值【英文标题】:Client WCF DataContract has empty/null values from service 【发布时间】:2011-02-01 05:43:51 【问题描述】:我有一个从服务器返回时间的简单 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 中,我的对象的 Time 属性设置为 1/1/0001 12:00 AM(默认值)。
我认为服务器和 silverlight 客户端之间的 DataContract 不匹配。这是服务器的 DataContract
[DataContract]
public class Time
[DataMember]
public DateTime theTime get; set;
非常简单。这是我的 silverlight 客户端上的数据合同。
[DataContract]
public class Time
[DataMember]
public DateTime theTime get; set;
从字面上看,唯一的区别是应用程序中的命名空间。但返回的值仍然是 null、空或 .NET 默认值。
感谢您的帮助!
更新
这是我的所有服务都通过的 ClientBase。我阅读了excellent article here 来构建它。
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 );
现在我的服务类使用此接口通过我的 BaseService 类进行调用。
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
【问题讨论】:
您可以发布服务方法的代码以及您正在使用的客户端代码吗?此外,您需要在问题中正确格式化代码。编辑问题,突出显示代码,然后按 Ctrl+K。 哎呀!不知道那是怎么发生的。都修好了。稍后我会发布我的服务客户端 【参考方案1】:因为您没有在 DataContractAttribute 上设置 the Namespace property,所以命名空间将从 .NET 类/命名空间合成。您可以在您发布的 SOAP 消息示例中看到这一点:
http://schemas.datacontract.org/2004/07/TestService.DataObjects
为了使合同被视为相等,您必须将 DataContract 上的 Namespace 属性设置为双方的相同值。这可能看起来有点像这样:
[DataContract(Namespace="urn:my-test-namespace")]
【讨论】:
这些似乎非常非常非常合理,这就是问题所在。我将在下一个空闲时间尝试一下。谢谢。 很有趣,而且因为每个应用程序都有不同的命名空间,DataContracts 不起作用。我添加了一些命名空间,现在一切正常!谢谢!! 感谢您的回答。我不敢相信我用谷歌搜索了一个术语,它导致堆栈溢出,而第一个回复正是我所需要的。太棒了。 这里与@CJohnson 相同。感谢您的提示。 非常感谢!我看到了很多不同的解决方案来解决这个问题,但这确实是我的问题。【参考方案2】:扩展 Drew Marsh 的正确答案 (+1 - thx) 我生成了一个正在运行的服务参考,但是当我尝试使用 Wcf 客户端工厂实现正确的接口(但命名空间不同)时,我是遇到所描述的问题。
我没有简单的方法来确定“正确”的命名空间应该是什么,只需将以下属性从服务引用的 DataContract 实体复制到 Wcf 客户端工厂实现中的实体即可解决问题;
[System.Runtime.Serialization.DataContractAttribute(Name = "BOSPrice", Namespace = "http://schemas.datacontract.org/2004/07/BOSDataService")]
[System.SerializableAttribute()]
【讨论】:
以上是关于客户端 WCF DataContract 具有来自服务的空/空值的主要内容,如果未能解决你的问题,请参考以下文章
将 DataMember 添加到 WCF 中的现有 DataContract
如何拥有一个带有 json 动态成员的 WCF DataContract