首页 文章

客户端WCF DataContract具有来自服务的空/空值

提问于
浏览
9

我有一个简单的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客户端上,返回对象的所有成员都是null,空白或默认的vaule . 如您所见,服务器返回当前日期和时间 . 但是在silverlight中,我对象上的Time属性设置为1/1/0001 12:00 AM(默认值) .

Sooo认为DataContracts在服务器和silverlight客户端之间不匹配 . 这是服务器的DataContract

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

非常简单 . 这是我的silverlight客户端上的datacontract .

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

字面上唯一的区别是应用程序中的命名空间 . 但是返回的值仍然是null,空或.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

2 回答

  • 0

    因为您没有在DataContractAttribute上设置the Namespace property,所以将从.NET类/命名空间中合并名称空间 . 您可以在发布的SOAP消息示例中看到这一点:

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

    为了使 Contract 被认为是相等的,您必须将DataContract上的Namespace属性设置为两侧的相同值 . 这可能看起来像这样:

    [DataContract(Namespace="urn:my-test-namespace")]
    
  • 19

    扩展Drew Marsh的正确答案(1-thx)我有一个生成的服务引用,但是当我尝试使用Wcf客户端工厂实现正确的接口(但命名空间不同)时,我遇到了描述的问题 .

    我没有简单的方法来确定“正确的”命名空间应该是什么,只是简单地将以下属性从服务引用的DataContract实体复制到Wcf Client Factory实现中的那个解决了问题;

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

相关问题