zoukankan      html  css  js  c++  java
  • .net 调用 Java编写的WebService

    经常使用.net访问第三方系统接口,特别是访问Java编写的WebService经常碰到各种各样的问题,例如:

      1.添加Web引用出错,使用wsdl生成代理类过程出错(这个问题困扰我很久,可能是wsdl格式解释的问题吧,具体未找到原因)

      2.不能添加Web引用(对方给的接口地址,根本得不到WSDL),使用对方提供的wsdl生成的代理类执行出错。微软生成的代理类产生的Soap是以"soap"标记,而对方只认"soapenv"标记(在网上看到有人说可以通用,但对方接口就是不认)

      因此我们可能要变通的访问,下面是在网上找到的比较好的方法

      ================================================================

      如果.NET调用WebService,最简单的办法当然是直接添加WEB引用,然后自动产生代理类,但是在调用JAVA的WebService时并没有这么简单,特别是对于SoapHeader的处理。
      先说说的思路:
      1、先用soapUI进行测试,这个工具会自动生成调用某个方法的XML。
      2、把soapUI生成的XML作为模版,自己也生成一个一模一样的XML并为参数节点赋好值。
      3、将这个XML通过http直接发送给WebService。
      4、接收返回的XML进行处理。
      这样做最大的好处就是可以自己很轻松的控制XML格式,最开始的时候我是通过添加引用的方式去调用某个方法一直失败,但是用soapUI去测试这个方法又是可以成功调用的,折腾了半天,最后通过抓包的方式对发送的数据进行对比,发现两者发送的XML相差甚远,好了废话不说了,就拿一个小实例来演示这个过程吧。

      首先,通过soapUI工具测试调用WebService里一个名为getPopCheckedInfo的方法,生成的XML如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ws="http://ws.pop.wsif.cogent.com/">
      <soapenv:Header>
        <wsse:Security soapenv:mustUnderstand="1" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
          <wsse:UsernameToken wsu:Id="UsernameToken-2" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
            <wsse:Username>用户名</wsse:Username>
            <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">密码</wsse:Password>
            <wsse:Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">qTW5ajMAEp4o9BiSvcczNA==</wsse:Nonce>
            <wsu:Created>2010-05-24T07:02:10.531Z</wsu:Created>
          </wsse:UsernameToken>
        </wsse:Security>
      </soapenv:Header>
      <soapenv:Body>
        <ws:getPopCheckedInfo>
          <arg0>参数</arg0>
        </ws:getPopCheckedInfo>
      </soapenv:Body>
    </soapenv:Envelope>

      上面三个用汉字标示的地方就是我们要修改赋值的地方,大家看到了吧,如果用添加引用自动生成代理类的方式,要产生这样格式的XML有多难控制了吧,但是如果全部用代码来生成也不是一件容易的事,个人用了一个比较巧妙的办法:
    在项目中添加一个名为“getPopCheckedInfo”的xml文件,将上面的XML粘贴上去,然后再将这个XML文件作为内嵌资源(在这个的文件属性里面的‘生产操作’选择‘嵌入的资源’),使用的时候直接加载这个XML文件,然后修改那3个节点的值就可以了(用户名和密码一般都预先确定的,也可以直接写在XML文件里,调用的时候就只要对那一个参数赋值了)。使用内嵌资源是为了不让外面看到我们的那个XML文件,以防被修改了什么的。

      下面看看调用的代码实现吧:(为了理解方便清晰,我们用跟WebService上一模一样的方法名和参数)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
       /// <summary>
       /// 根据居民id获取该居民信息
    /// </summary>
       /// <param name="id">居民id</param>
       public static People getPopCheckedInfo(string id)
       {
           String ServerUrl = Config.GetWebServerURL();//得到WebServer地址
           Hashtable pars = new Hashtable();//用来存放参数
           pars["arg0"] = id;
           XmlDocument xml = WebSvcCaller.QuerySoapWebService(ServerUrl, "getPopCheckedInfo", pars);
           //这个是对返回的XML文件处理,我删掉了,处理完后返回一个居民的实体对象
           return myPeople;
       }

    WebSvcCaller.QuerySoapWebService方法代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    /// <summary>
    /// 通用WebService调用(Soap),参数Pars为String类型的参数名、参数值
    /// </summary>
    public static XmlDocument QuerySoapWebService(String URL, String MethodName, Hashtable Pars)
    {
        HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(URL);
        request.Method = "POST";
        request.Accept = @"gzip,deflate";
        request.ContentType = @"text/xml;charset=utf-8";
        request.UserAgent = @"Jakarta Commons-HttpClient/3.1";
        request.Credentials = CredentialCache.DefaultCredentials;
        request.Timeout = 10000;
        byte[] data = EncodeParsToSoap(Pars, MethodName);
        WriteRequestData(request, data);//将处理成字节组的XML写到流中发送到服务端
        XmlDocument doc = new XmlDocument();
        doc = ReadXmlResponse(request.GetResponse());//读取服务端返回的结果
        return doc;
     }

     EncodeParsToSoap(Pars, MethodName),处理XML文件方法的代码:(以下仅供参考,大家根据自己的实际情况变动)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    /// <summary>
    /// 处理要发送的XML文档
    /// </summary>
    /// <param name="Pars">参数</param>
    /// <param name="MethodName">方法名</param>
    private static byte[] EncodeParsToSoap(Hashtable Pars, String MethodName)
    {
        XmlDocument xml = null;
        if (hshtableXML.ContainsKey(MethodName))
        {//如果已经加载过,则从缓存中读取
            xml = (XmlDocument)hshtableXML[MethodName];
        }
        else
        {//如果还未加载则进行加载,并放入缓存
     
            //从资源文件得到文件流
            Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("你的项目的名称.XML文件存放的文件夹."   MethodName   ".xml");
            xml = new XmlDocument();
            xml.Load(stream);
            hshtableXML.Add(MethodName, xml);
        }
     
        //修改参数的值
        foreach (DictionaryEntry de in Pars)
        {
            XmlNamespaceManager nsmgr = new XmlNamespaceManager(xml.NameTable);
            nsmgr.AddNamespace("soapenv", "http://schemas.xmlsoap.org/soap/envelope/");
            nsmgr.AddNamespace("ws", "http://ws.pop.wsif.cogent.com/");
            Hashtable subpars = de.Value as Hashtable;
            if (subpars == null)
            {
                string subNode = "soapenv:Envelope/soapenv:Body/ws:"   MethodName   "/"   de.Key.ToString();
                XmlNode node = xml.SelectSingleNode(subNode, nsmgr);
                node.InnerText = de.Value.ToString();
            }
            else
            {
                foreach (DictionaryEntry subde in subpars)
                {
                    string subNode = "soapenv:Envelope/soapenv:Body/ws:"   MethodName   "/"   de.Key.ToString()   "/"   subde.Key.ToString();
                    XmlNode node = xml.SelectSingleNode(subNode, nsmgr);
                    node.InnerText = subde.Value.ToString();
                }
            }
            
        }
     
        //将修改后的XML文件保存到流中
          //这样做还可以保证发送的XML文件也是格式化的那种形式,而不是一整行
          //如通过OuterXml获取的就是一整行,这样也可能会导致服务端解析失败,个人这次就碰到这种情况了
        MemoryStream outStream = new MemoryStream();
        xml.Save(outStream);
     
        byte[] buffer = new byte[outStream.Length];
        byte[] temp = outStream.GetBuffer();
        for (int i = 0; i < buffer.Length; i  )
        {
            buffer[i] = temp[i];
        }
        outStream.Close();
     
        return buffer;
    }

    最后还有WriteRequestData、ReadXmlResponse两个方法的代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    /// <summary>
    /// 写到流中,发送给服务端
    /// </summary>
    /// <param name="request">HttpWebRequest连接对象</param>
    /// <param name="data">要写入连接流发给服务端的内容</param>
    private static void WriteRequestData(HttpWebRequest request, byte[] data)
    {
        request.ContentLength = data.Length;
        Stream writer = request.GetRequestStream();
        writer.Write(data, 0, data.Length);
        writer.Close();
    }
     
    /// <summary>
    /// 读取服务端返回的结果
    /// </summary>
    private static XmlDocument ReadXmlResponse(WebResponse response)
    {
        StreamReader sr = new StreamReader(response.GetResponseStream(), Encoding.UTF8);
        String retXml = sr.ReadToEnd();
        sr.Close();
        XmlDocument doc = new XmlDocument();
        doc.LoadXml(retXml);
        return doc;
    }
  • 相关阅读:
    paip.注册java程序为LINUX系统服务的总结。
    paip.Log4j配置不起作用的解决
    paip.获取地理位置根据Ip
    paip.抓取网页内容--java php python
    paip.java 开发中web server的选择jboss resin tomcat比较..
    paip.c++ 转换 java 解决方案
    paip.java c# .net php python调用c++ c dll so windows api 总结
    SVN的405错误
    怎样开启SQL数据库服务
    C#中读取二维数组每位的长度
  • 原文地址:https://www.cnblogs.com/ldsweely/p/13517507.html
Copyright © 2011-2022 走看看