2010-03-26 45 views
9

我有一个简单的WCF服务,它从服务器返回时间。我已经确认数据是通过与Fiddler进行检查来发送的。这是我的服务发送的结果对象xml。客户端WCF DataContract具有来自服务的空/空值

<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客户端中,返回对象的所有成员都是null,空白或缺省值。正如你所看到的,服务器返回当前的日期和时间。但在silverlight中,我的对象的Time属性设置为1/1/0001 12:00 AM(默认值)。

Sooo认为DataContracts在服务器和Silverlight客户端之间不匹配。下面是服务器

[DataContract] 
public class Time 
{ 
    [DataMember] 
    public DateTime theTime { get; set; } 
} 

令人难以置信的是简单的DataContract。这里是我的Silverlight客户端的数据合同。

[DataContract] 
public class Time 
{ 
    [DataMember] 
    public DateTime theTime { get; set; } 
} 

字面上唯一的区别是应用程序内的命名空间。但仍然返回的值为空,空或.NET缺省值。

感谢您的帮助!

UPDATE

这里是我的所有服务运行通过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

+0

您可以发布服务方法的代码以及您使用的客户端代码吗?另外,你需要在你的问题中正确地格式化你的代码。编辑问题,突出显示代码,然后按Ctrl + K。 – 2010-03-26 15:37:00

+0

eek!不知道这是怎么发生的。所有固定。我将发布我的服务客户端 – Matt 2010-03-26 15:40:51

回答

19

因为你没有设置the Namespace property您DataContractAttribute,命名空间将被从.NET sythesized类/命名空间。您可以在您发布的SOAP消息例子中看到这一点:

http://schemas.datacontract.org/2004/07/TestService.DataObjects

为了有合同被认为是平等的,你必须在DataContract设置Namespace属性相同的双方的价值。这可能看起来有点像这样:

[DataContract(Namespace="urn:my-test-namespace")] 
+0

这似乎是非常非常非常合理的问题。我会在下一次的自由时刻尝试它。谢谢。 – Matt 2010-03-26 19:57:10

+1

有趣,而且因为我为每个应用程序有不同的命名空间,DataContracts不起作用。我在一些命名空间中添加了它,现在一切都完美了!谢谢!! – Matt 2010-03-26 20:41:16

+0

没错。很高兴我能帮上忙! – 2010-03-26 20:51:06

0

在德鲁Marsh的正确答案扩展(+1 - THX)我正在工作生成服务引用,但是当我尝试使用WCF客户端厂一个实施正确的界面(但名称空间不同),那么我遇到了所述的问题。

我没有简单的方法来找出什么是“正确”的命名空间本来应该只是简单复制从服务引用的DataContract实体到一个在WCF客户端工厂实现以下属性来解决这个问题;

[System.Runtime.Serialization.DataContractAttribute(Name = "BOSPrice", Namespace = "http://schemas.datacontract.org/2004/07/BOSDataService")] 
    [System.SerializableAttribute()] 
相关问题