WCF Rest:不使用UriTemplate使用post方式傳參解決HTTP400問題以及參數映射問題


  由於實驗室項目組正在開發ERP系統,客戶端有PC CS、BS、Android等多種展現方式。前期為了快速開發出產品雛形,PC端使用.NET開發,Android使用JavaEE做為服務后台。本人參與了.NET后台開發以及JavaEE后台開發。擔任技術攻關角色。

  隨着系統的完善逐漸成熟,早期的系統架構已經不能滿足現在的需求,問題在於:由於平台的限制,不同平台的客戶端需要不同平台的后台提供服務,也就是說相同的業務需要開發多套后台服務出來。這種架構必定存在問題。

  而要做到平台的無關性,就要制定標准的通訊協議和數據契約。由於.NET平台比較成熟,經過考慮,本人決定使用WCF作為APPServer,沒有使用JavaEE。使用HTTP+JSON作為通信協議與數據契約,提供統一的服務接口,為不同的客戶端平台提供后台服務。

  在使用此解決方案前,需要做一些WCF的技術攻關以及性能調優,以避免后期系統完全使用此方案造成大規模的故障。在研究WCF REST編程模型時,遇到了以下問題及解決方案:

  問題描述一、

    在使用POST方式向服務提交數據時,出現HTTP400異常,以下代碼描述:

    服務接口定義:

    [OperationContract]
    [WebInvoke(ResponseFormat = WebMessageFormat.Json, RequestFormat = WebMessageFormat.Json, Method = "POST", BodyStyle =             WebMessageBodyStyle.Bare)]
    Stream HelloData(MyData data);

    [OperationContract]
[WebInvoke(Method = "POST", BodyStyle = WebMessageBodyStyle.Bare)]
Stream HelloDataStr(String data);

    實現只是簡單的把傳入的數據打印出來,略

    客戶端調用:

    方法一、 

    private static void HelloDataClient()
    {

      WebClient client = new WebClient();
      client.Headers["Content-Type"] = "application/json";
      string data = "{\"ID\":1,\"Name\":\"ss\"}";
      string str = client.UploadString("http://localhost:1122/HelloData", "POST", data);
      Console.WriteLine(str);
    }

    方法二

    private static void HelloDataStrClient()
    {
      WebClient client = new WebClient();
      string str = client.UploadString("http://localhost:1122/HelloDataStr", "POST", "ss");
      Console.WriteLine(str);
    }

    以上兩個方法對用調用兩個不同的服務,問題在於使用Mydata數據契約的方法一OK,方法二出現HTTP400錯誤。為什么自定義類型的可以,而基本數據類型的不可以?起初認為自定義數據類型自己已經做了序列化,而string不是自己做的可能跟序列化有關。那沒有用UriTemplate是不是參數映射出了問題?因為方法一已經成功,說明WCF會將HTTP請求參數默認映射到僅有的一個服務接口的參數上。排除此猜測。

    方法后來做了以下迭代測試:

    將方法二改為:

    private static void HelloDataStrClient()
    {
      WebClient client = new WebClient();
      string str = client.UploadString("http://localhost:1122/HelloDataStr", "POST", String.Empty);
      Console.WriteLine(str);
    }

    發現調用成功,說明數據有問題。數據有問題就是數據的格式有問題,但是服務契約二沒有聲明Request的格式為JSON。那么他默認為什么呢?把方法二再改如下:

    private static void HelloDataStrClient()
    {
      WebClient client = new WebClient();
      client.Headers["Content-Type"] = "application/json";
      string str = client.UploadString("http://localhost:1122/HelloDataStr", "POST", "\"ss\"");
      Console.WriteLine(str);

    }

    調用成功。

      注意:JSON格式默認為“”引起,所以 "\"ss\""不能寫為“ss”,否則還是HTTP400錯誤。因為未識別數據,將數據拼接到其他字節了吧。

    問題描述二、

      沒有使用UriTemplate做參數的映射,那多個參數是怎么映射的?將方法二改為:

    服務契約二:

    [OperationContract]
    [WebInvoke(Method = "POST", BodyStyle = WebMessageBodyStyle.Wrapped)]
    Stream HelloDataStr(String data1,string data2);

 

    客戶端:

    private static void HelloDataStrClient()
    {
      WebClient client = new WebClient();
      client.Headers["Content-Type"] = "application/json";
      string str = client.UploadString("http://localhost:1122/HelloDataStr", "POST", "{\"data1\":\"hh\",\"data2\":\"ss\"}");
      Console.WriteLine(str);

    }

    調用成功,並且成功打印了兩個參數。注意服務契約的接口定義屬性WebMessageBodyStyle.Wrapped,此屬性將兩個參數進行了包裝,否則無法映射。

 

 

    附:JAVA調用代碼:

    

public static void main(String[] args) {
// TODO Auto-generated method stub
  HelloClient();

  HelloDataClient();

  HelloDataStrClient();

}
private static void HelloClient(){
  URLClient client = new URLClient();
  String resultStr = client.getDocumentAt("http://localhost:1122/Hello");
  MyData data = assembleModel(resultStr);
  System.out.print("Hello Response content: " +resultStr);
  System.out.println("MyData Name: " +data.getName());
}

private static void HelloDataClient(){
  try {

String postUrl = "http://localhost:1122/HelloData";
String postData = "{\"data1\":1,\"data2\":\"ss\"}";
HttpClient hClient = new DefaultHttpClient();
HttpPost post = new HttpPost(postUrl);
StringEntity s = new StringEntity(postData);
s.setContentEncoding("UTF-8");
s.setContentType("application/json");
post.setEntity(s);
HttpResponse response = hClient.execute(post);
HttpEntity responseEntity = response.getEntity();

String resultStr = inputStream2String(responseEntity.getContent());
MyData data = assembleModel(resultStr);
System.out.println("HelloDataStr Response content: "
+ resultStr);
System.out.println("MyData Name: " +data.getName());

} catch (Exception e) {

  // TODO: handle exception

  }

}

private static void HelloDataStrClient(){
  try {

String postUrl = "http://localhost:1122/HelloDataStr";
String postData = "{\"data1\":1,\"data2\":\"ss\"}";
HttpClient hClient = new DefaultHttpClient();
HttpPost post = new HttpPost(postUrl);
StringEntity s = new StringEntity(postData);
s.setContentEncoding("UTF-8");
s.setContentType("application/json");
post.setEntity(s);
HttpResponse response = hClient.execute(post);
HttpEntity responseEntity = response.getEntity();

String resultStr = inputStream2String(responseEntity.getContent());
System.out.println("HelloDataStr Response content: "
+ resultStr);

  } catch (Exception e) {
// TODO: handle exception
    }
}

public static String inputStream2String(InputStream is) throws IOException {
  ByteArrayOutputStream baos = new ByteArrayOutputStream();
  int i = -1;
  while ((i = is.read()) != -1) {
    baos.write(i);
  }
  return baos.toString();
}
private static MyData assembleModel(String jsonStr) {
  MyData model = null;
  try {
      JsonConvertor jsonConvertor = new JsonConvertor();
      MyData[] stus = (MyData[]) jsonConvertor
    .convertToObj(jsonStr,MyData.class);
      model = stus[0];
    } catch (Exception e) {
      e.printStackTrace();
  }
  return model;
}

    原創:轉載請標明出處:http://www.cnblogs.com/sh91/p/3273072.html


免責聲明!

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



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