WCF分布式开发常见错误(30):Start element 'Binary' expected(期望的初始元素是'Binary' )

       WCF分布式开发常见错误(30):Start element 'Binary' expected(期望的初始元素是'Binary' ). Found 'SayHello'.
调试WCF4.0代码遇到的错误,目前网络上参考的资料很少,我把这个异常的信息给收集起来,包括解决办法,整理为一篇文章,供大家参考。这个问题目前没什么参考资料。使用Google也搜索不到相关的英文帮资料。分享出来,应该对大家有点参考价值。
【1】错误描述:
  这个问题是在调试今天我在调试WCF自定义绑定实现字节流编码ByteStreamMessageEncoding程序例子代码的时候遇到这个错误。客户端抛出的异常是:Start element 'Binary' expected(期望的初始元素是'Binary' ). Found 'SayHello'.
  绑定的定义如下:
  // 创建自定义绑定
            ByteStreamMessageEncodingBindingElement byteStream  =   new  ByteStreamMessageEncodingBindingElement();
            
// TcpTransportBindingElement transport = new TcpTransportBindingElement();

            HttpTransportBindingElement transport 
=   new  HttpTransportBindingElement();
            transport.AuthenticationScheme 
=  System.Net.AuthenticationSchemes.Anonymous;
            transport.HostNameComparisonMode 
=  HostNameComparisonMode.StrongWildcard;

            CustomBinding binding 
=   new  CustomBinding(byteStream, transport);
   操作的定义如下:
  // 2.服务类,继承接口。实现服务契约定义的操作
     public   class  WCFService : IWCFService
    {
        
// 实现接口定义的方法
         public   void  SayHello( byte [] b)
        {
            Console.WriteLine(
" Hello! {0},Calling at {1} ... " , b,DateTime.Now.ToLongTimeString());
            
// return b;
        }
    }
 【2】错误截图:
      运行程序,客户端调用服务操作,抛出的异常截图如下:
WCF分布式开发常见错误(30):Start element 'Binary' expected(期望的初始元素是'Binary' )_第1张图片
【3】问题分析:
      这个问题应该是由于消息的根节点元素不正确导致的。这里的SOAP消息的Body默认根节点应该是<SayHello>。
 SOAP消息不符合Schema导致的。WCF里提供了能够控制消息序列化的机制就是使用Message类型来控制序列化。
【4】解决办法:
  首先我们要重新定义一下操作,这里服务契约不能定义为普通的契约,而要使用消息契约来代替数据契约。
声明如下:
     // 1.服务契约
    [ServiceContract]
    
public   interface  IWCFService
    {
        
// 操作契约
        [OperationContract(Action  =   " * " , ReplyAction  =   " * " )]
        Message UpLoad(Message request);
    }
 
     其次控制Message对象,这是客户端的请求消息Body,第一个根节点必须为Binary节点。
这里比较复杂的一点是要了解WCF的消息序列化机制。在《WCF技术内幕》有过介绍。我们在实例化Message对象的时候,要提供一个BodyWriter的之类对象,它可以负责Message对象的消息体部分的处理工作。我们可以控制节点的添加。
    BodyWriter为抽象类,我们要定义一个类型继承实现它的抽象方法。定义如下:
  class  ByteStreamBodyWriter : BodyWriter
    {
        
string  testFileName;

        
public  ByteStreamBodyWriter( string  testFileName)
            : 
base ( false )
        {
            
this .testFileName  =  testFileName;
        }
        
protected   override   void  OnWriteBodyContents(XmlDictionaryWriter writer)
        {
            writer.WriteStartElement(
" Binary " );
            
// 写数据
            writer.WriteEndElement();
            fs.Close();
        }
    }
 
    OnWriteBodyContents(XmlDictionaryWriter writer)方法里提供了一个消息体元素"Binary"的定义,我们把数据放到这个节点下面,就可以解决问题。这个时候请求消息里就会包含需要的节点。在此启动程序基本正常。
【5】总结:
    (1)这里比较值得注意的问题是,根据提示我曾经尝试把方法名字修改为"Binary"。
这个做法基于的出发点就是WCF会把方法名默认作为消息的根节点名。但是后来尝试失败。应该是SOAP消息里包含了新的后缀,我很难控制消息体的根节点元素名称。
  (2)另外就是ByteStreamMessageEncodingBindingElement的使用只能是基于自定义绑定,而且对方要求把数据放到消息里的"Binary"节点里:
< Binary >字节流 数据 </ Binary >
 
    这里唯一的办法就是使用Message契约来实现,WCF提供的可以控制消息体的方法也就是通过控制SOAP消息的序列化过程。这里我们使用的一个重要类型BodyWriter。它是一个抽象类,是许多消息体处理类型的基类型。
 
参考资料:
1. BodyWriter Class
2.《WCF技术内幕》绑定

你可能感兴趣的:(职场,binary,休闲,初始元素)