zoukankan      html  css  js  c++  java
  • 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数据格式等都不熟,需要好好补充一下知识了。最后感谢网上其他同仁们的无私分享。

  • 相关阅读:
    《C++ Primer》读书笔记之第15章:面向对象编程
    Color Space: HSI
    Color Space: Lab
    C# 特殊关键字
    WPF 打开文件、文件夹
    EmguCV+Win7+Visual C# 2012 配置
    C# 常用结构
    C#抽象类、抽象方法、虚方法
    C# Image 、 byte[] 、Bitmap之间的转化
    java反射机制基础
  • 原文地址:https://www.cnblogs.com/adingfirstlove/p/9835724.html
Copyright © 2011-2022 走看看