关于.NET中动态调用Web Service服务的方法心得

介绍.NET中动态调用Web Service的相关技术文章。

在.NET中调用Web Service服务(WSDL)有两种可行的方法:
1、通过Web 服务引用,在本地生成所要调用服务的类;(静态方法)
2、通过给定的WSDL服务地址,动态生成Web Service服务类进行服务调用;(动态方法)

由于1中的方法大部分人都会经常用到,因此暂不讨论。

对于2,实现上较为复杂,主要的过程为:
(1)读取WSDL内容到内存中;
(2)根据WSDL内容,动态生成Web Service服务代码;
(3)使用动态编译技术将生成的Web Service服务代码编译为DLL;
(4)通过反射机制实现动态调用。
_________________________________________________________

有关这类技术请参考如下网站:
1、《动态调用 WebService》
地址:http://www.rainsts.net/article.asp?id=304
2、《DynWsLib》
地址:http://www.thinktecture.com/Resources/Software/DynWsLib/default.html
说明:
欧洲一家名位Thinktecture公司发布的开源项目,实现了比较完整的动态调用Web Service的方法,最新版本为1.6,支持.NET 2.0。最可贵的是这是一个完全开源的项目,我们可以下载下来根据实际情况进行一些修改,以适应不同的需求。
3、WSE
地址:http://msdn2.microsoft.com/en-us/webservices/aa740663.aspx
说明:
微软发布的支持Web Service的工具包。目前最新版本为3.0。
_________________________________________________________
Java 与 .NET的互调用
这是本文重点要讨论的话题。
由于项目需要,我们必须为客户提供一个.NET的动态调用Web Service包,以实现对Oracle的BPEL服务器上发布的Web Service进行动态调用。

在使用动态DynWSLib生成的对象进行调用的时候,发现只能够发送一次SOAP,当第二次发送之后,.NET程序会抛出链接已被断开的异常。

这样的错误十分诡异,在网上搜索了之后,发现问题在于BPEL服务器与Microsoft的IIS之间是有区别的,看来微软还是很喜欢搞垄断。

下面说说个人分析的结论,共大家参考:
问题的出现可能和微软的地层支持有关,本人猜测,微软生成的Web Service对象在发送SOAP请求时,建立的HTTP链接在请求发送完成之后,会长时间保持链接状态(即链接没有立即断开),而对于Oracle的Web服务器,当相应SOAP请求之后,会主动断开HTTP链接,这也许就是为什么用微软的东西发送SOAP消息给Oracle服务器,第一次能够成功,第二次就会报链接已断开,发送失败的错误。后面的解决方案中也部分支持了我的这个观点。
________________________________________________________
解决方案:
WSE + HTTP
1、使用WSE构造SOAP请求消息;
2、使用HTTP发送SOAP消息。

下面给出部分参考代码:

using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Net;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;

namespace My.Web.WebService
{
    internal class SoapHttpClient
    {
        private string url = null;

        public SoapHttpClient(string url)
        {
            this.url = url;
        }

        public string RequestResponse(string methodName, string envelope)
        {
            // 用于支持SSL
            ServicePointManager.ServerCertificateValidationCallback += new RemoteCertificateValidationCallback(OnCheckRemoteCallback);

            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
            request.Credentials = CredentialCache.DefaultCredentials;

            // 必须设置该值为flase,否则出错
            request.KeepAlive = false;

            request.Method = "POST";
            request.ContentType = "text/xml";
            request.Headers.Add("SOAPAction", methodName);

            UTF8Encoding encoding = new UTF8Encoding();
            byte[] bodyBytes = encoding.GetBytes(envelope);
            request.ContentLength = bodyBytes.Length;
            using (Stream serviceRequestBodyStream = request.GetRequestStream())
            {
                serviceRequestBodyStream.Write(bodyBytes, 0, bodyBytes.Length);
                serviceRequestBodyStream.Close();

                using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
                {
                    using (StreamReader reader = new StreamReader(response.GetResponseStream(), System.Text.Encoding.UTF8))
                    {
                        string result = reader.ReadToEnd();
                        return result;
                    }
                }
            }
        }

        /// <summary>
        /// Using untrusted SSL certificates
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="certificate"></param>
        /// <param name="chain"></param>
        /// <param name="sslPolicyErrors"></param>
        /// <returns></returns>
        private static bool OnCheckRemoteCallback(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
        {
            return true;
        }
    }
}

_________________________________________________________
[b]最后讨论一下有关DynWSLib动态调用的问题。[/b]
使用DynWSLib在调用Web Service服务的时候,需要对传入的参数进行适当的处理。

 

private void bnCalc_Click(object sender, System.EventArgs e)
  {
            DynamicWebServiceProxy ws = new DynamicWebServiceProxy();

            ws.EnableMessageAccess = true;
            ws.Wsdl = "http://localhost:3092/CatalogueDataPublishTest.asmx?WSDL";
            //ws.Url = new Uri("http://localhost:3092/CatalogueDataPublishTest.asmx");
            ws.TypeName = "CatalogueDataPublishTest";
            ws.MethodName = "HelloWorld";
           
            //ws.AddParameter(XmlHelper.Object2Xml(new DCMCatalogueWork()));
            //ws.AddParameter(new DCMCatalogueWork());

            AddParameter(ws, "dcw", new Sobey.MAM.Common.InterfaceDataType.DCM2.Catalogue.SystemDefineType());

            object result = ws.InvokeCall();

            MessageBox.Show(result.ToString());
  }

        /// <summary>
        /// 添加WebService类型体系中的参数值
        /// </summary>
        /// <param name="ws">代理</param>
        /// <param name="name">参数名字(WebService中的参数名字,这里也可以是参数位置索引)</param>
        /// <param name="value">参数取值</param>
        public void AddParameter(DynamicWebServiceProxy ws,string name, object value)
        {
            //找到该参数的类型
            Type objType = GetParameterType(ws,name);

            //由于2个对象只是命名空间不同,不能强制转换,就采用序列化与反序列化的方式进行深度拷贝。
            ws.AddParameter(XmlHelper.Xml2Object(XmlHelper.Object2Xml(value), objType));
        }

        /// <summary>
        /// 获取WebService方法指定参数的类型
        /// </summary>
        /// <param name="ws">服务代理</param>
        /// <param name="parameterName">参数名称</param>
        /// <returns></returns>
        private Type GetParameterType(DynamicWebServiceProxy ws,string parameterName)
        {
            Type t = ws.Instance.GetType();
            MethodInfo methodInfo = t.GetMethod(ws.MethodName);

            // 获得方法的参数类型
            ParameterInfo[] param = methodInfo.GetParameters();

            if (param.Length < 1)
            {
                return null;
            }

            foreach (ParameterInfo pi in param)
            {
                if (pi.Name == parameterName)
                {
                    return pi.ParameterType;
                }
            }

            return null;
        }

posted @ 2009-06-03 15:08  遥望星空  阅读(1626)  评论(2编辑  收藏  举报