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】錯誤截圖:
運行程序,客戶端調用服務操作,拋出的異常截圖如下:
【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。它是一個抽象類,是 許多消息體處理類型的基類型。