POST調用WCF方法-項目實踐


做即時通信項目時,需要與OA系統對接接口,主要目標是實現在OA里進行一項事項,通過調用我們的接口,即時通知過來,並彈出消息框提示一下。我們的即時通信使用的WCF服務進行通信,在客戶端調用通信時,用的就是直接添加服務引用的方式,無可厚非,但是OA系統對接了太多項目,不能使用添加服務引用的方式,問題就來了,不得已只能更改我們的接口。
因為不熟悉這一塊,浪費了不少時間,總結一下過程,方便以后使用。
微軟官方文檔:https://msdn.microsoft.com/zh-cn/library/dd315413.aspx#id0070003

一、修改
首先,說一下用到的技術。REST編程模型,為了能夠讓OA這邊用他們通用的方法直接調用api,上網查找post調用wcf的方法,我見識淺薄,只知道使用REST編程的方式。

1.修改接口
主要是添加一個特性【WebInvoke】,該屬性指示服務操作在邏輯上就是調用操作,且可由wcf REST編程模型調用。
這里可以指定是GET調用或者POST調用,一般的格式如下:

GET:
[OperationContract]
[WebInvoke(Method = "GET", ResponseFormat = WebMessageFormat.Json, UriTemplate = "Say")]
string Say();
[OperationContract]
[WebInvoke(Method = "GET", ResponseFormat = WebMessageFormat.Json, UriTemplate = "SayHello/{value}/{a}")]
string SayHello(string value, string a);
POST:
[OperationContract]
[WebInvoke(BodyStyle = WebMessageBodyStyle.Wrapped, ResponseFormat = WebMessageFormat.Json, RequestFormat = WebMessageFormat.Json, Method = "POST")]
string PostDataTest(string value,string content);
[OperationContract]
[WebInvoke(BodyStyle = WebMessageBodyStyle.Wrapped,ResponseFormat = WebMessageFormat.Json, RequestFormat = WebMessageFormat.Json, Method = "POST")]
void WorkSend(string Title, string ReceiverId, string SenderId, string Content, string URL, string MsgType);
推薦一個網址,里面有REST的介紹與詳細的步驟:
http://www.cnblogs.com/wuhong/archive/2011/01/13/1934492.html(方法的參數是類對象,我這里用參數就可以實現)


2.修改服務端app.config/web.config
需要完全修改原來提供的接口配置。
首先在<bindings>標簽內添加webHttpBinding,簡單描述一下這種綁定協議:
WebHttpBinding允許開發人員通過 HTTP 請求(這些請求使用“Plain old XML”(POX) 樣式消息,而不是使用基於 SOAP 的消息)來公開 Web 服務,可以很便利的實現REST。
與其他綁定不同的是:必須使用WebHttpBehavior對服務的終結點進行配置。還要求使用WebGetAttribute或WebInvokeAttribute屬性將各個服務操作映射到 URI,同時定義調用和返回結果的消息格式。
下面是我的綁定:
<webHttpBinding>
<binding name="NewBinding3" maxReceivedMessageSize="2147483647" transferMode="Buffered">
<readerQuotas maxDepth="32" maxStringContentLength="2147483647" maxArrayLength="12000000" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" />
<security mode="None">
<transport clientCredentialType="None"></transport>
</security>
</binding>
</webHttpBinding>
然后行為的配置,必須使用WebHttpBehavior對服務的終結點進行配置。
如下:
<endpointBehaviors>
<behavior name="webHttp"> <!--必須設置-->
<webHttp helpEnabled="true" automaticFormatSelectionEnabled="true"/>
</behavior>
</endpointBehaviors>
因為我的wcf服務是寄宿在后台服務程序里的,會明確指定端口與ip,所以我還需要添加一個服務行為
<behavior name="RESTBehaviors">
<!-- 將下列元素添加到服務行為配置中。 -->
<serviceMetadata httpGetEnabled="true" httpGetUrl="http://192.168.1.192:8008/IMWCF/OpenAPI/"/>
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
最后就是添加<services>配置終結點了:
<service name="WCFService.OPenApi" behaviorConfiguration="RESTBehaviors">
<endpoint address="http://192.168.1.192:8008/IMWCF/OpenAPI/" binding="webHttpBinding" bindingConfiguration="NewBinding3" contract="WCFContract.IOPenApi" behaviorConfiguration="webHttp">
</endpoint>
</service>

3.修改客戶端調用方式
這里提供兩種方式,一種是常規的通過HttpWebRequest的方式,一種是直接通過WebClient的方式,個人感覺第二種更方便一些。(重要的是參數數據的傳遞)
另外提一下,上面推薦的網址中,提供了C#編程直接訪問HTTP的方式與使用jqueryGET和POST訪問的方式,消息的格式不一樣,一種是xml,一種是json格式,這里我沒做細的研究,都用的json格式。
常規方式
代碼如下:
public string PostHelper(string uri, string postData)
{
try
{
Encoding myEncode = Encoding.GetEncoding("UTF-8");
//轉換為字節數組
byte[] data = Encoding.UTF8.GetBytes(postData);

Uri uRI = new Uri(uri);
HttpWebRequest req = WebRequest.Create(uRI) as HttpWebRequest;
req.Method = "POST";
req.KeepAlive = true;
//req.ContentType = "application/json";
req.ContentType = "application/json;charset=utf-8";

req.ContentLength = data.Length; ////填充POST數據
req.AllowAutoRedirect = true;
//這個在Post的時候,一定要加上,如果服務器返回錯誤,他還會繼續再去請求,不會使用之前的錯誤數據,做返回數
req.ServicePoint.Expect100Continue = false;

Stream outStream = req.GetRequestStream();
outStream.Write(data, 0, data.Length);
outStream.Close();

//發送POST數據請求服務器
HttpWebResponse res = req.GetResponse() as HttpWebResponse;
//獲取服務器返回信息
Stream inStream = res.GetResponseStream();
//StreamReader sr = new StreamReader(inStream);
StreamReader sr = new StreamReader(inStream, myEncode);
string htmlResult = sr.ReadToEnd();

return htmlResult;
}
catch (Exception ex)
{
return "網絡錯誤:" + ex.Message.ToString();
}
}
調用:
string url = "http://192.168.1.192:8008/IMWCF/OpenAPI/WorkSend";
string postData = @"{'Title': '"+ title + "','ReceiverId': '" + recevier + "','SenderId': '" + sender + "','Content': '" + content + "','URL': '" + invokeurl + "','MsgType': '" + msgtype + "'}";
string mes = PostHelper(url, postData);

WebClient方式
WebClient client = new WebClient();
client.Headers.Add("Content-Type", "application/json");
try
{
var result = client.UploadString("http://192.168.1.192:8008/IMWCF/OpenAPI/PostDataTest", "POST", "{\"value\":\"ading\",\"content\":\"good\"}");
Console.WriteLine("返回值為{0}", result.ToString());
}

二、問題
在配置好服務端后,客戶端寫好調用方式后,遇到最多並且花費我大量時間的問題就是,400錯誤,
遠程服務器返回錯誤: (400) 錯誤的請求。

一到這里就報錯,上網查找好多400錯誤,都沒有解決,最后看到一條評論說這種問題就是,參數不匹配或者調用方式get、post搞錯的導致的。
通過第三方的Postman調用我的接口,發現能正常調用,排除問題出在服務端的可能,只能是自己的客戶端調用或者配置存在問題,因為json轉換這塊不是很熟,着重排查這里,一番修改,發現參數也沒什么問題。
實在沒辦法,在服務端添加測試接口,只傳遞一個參數的方法,調用后發現沒問題,然后對比兩個接口方法的鍥約,發現缺少了BodyStyle = WebMessageBodyStyle.Wrapped,添加后,發送可以調用了,查看描述,得知BodyStyle = WebMessageBodyStyle.Wrapped設定包裝參數。
添加屬性BodyStyle = WebMessageBodyStyle.WrappedRequest,
[WebInvoke(BodyStyle = WebMessageBodyStyle.Wrapped,ResponseFormat = WebMessageFormat.Json, RequestFormat = WebMessageFormat.Json, Method = "POST")]
並且需要保證后台傳遞數據中包含參數的傳遞
例如 string postData = @"{""value"": ""hello""}";,value及服務中方法的參數名。

 

三、總結

自工作以來,一直從事CS端方向項目,對於BS端得很多知識都靠得在學校學的基礎,BS端的網絡協議、json數據格式等都不熟,需要好好補充一下知識了。最后感謝網上其他同仁們的無私分享。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM