很少用C#动态的去调用Web Service,一般都是通过添加引用的方式,这样的话是自动成了代理,那么动态代理调用就是我们通过代码去调用这个WSDL,然后自己去生成客户端代理。更多的内容可以看下面的两个地址:http://blog.csdn.net/limlimlim/article/details/8651043 http://www.cnblogs.com/VisualStudio/archive/2008/10/29/1322228.html 1.动态调用的url后面注意一定要加上?WSDL 例如:string _url = "http://服务器IP:端口/CITI_TRANS_WH/wsTransData_InWH.asmx?WSDL"; --------------------------------------------------------------------------------------------------- 2.WebService中传递List泛型对象 [WebMethod] public List<TestModel> TestTransDataByClass(int _max) 注意TestModel必须是可以序列化的类 //必须可序列化 [Serializable] public class TestModel { public int No { get; set; } public string Des { get; set; } } --------------------------------------------------------------------------------------------------- 3.WebService中不能直接传递输出dictionary<string,object>这样的泛型对象,必须自定义一个类来输出,这个类同样也是可以序列化的 [Serializable] public class MyDictionary { public List<TestModel> Table1 { get; set; } public List<TestModel2> Table2 { get; set; } } --------------------------------------------------------------------------------------------------- 4.动态调用WebService的类封装 public static class InvokeWebServiceDynamic { /// <summary> /// 动态调用WebService /// </summary> /// <param name="_url">web服务url地址</param> /// <param name="_methodName">web服务中的方法</param> /// <param name="_params">传递给方法的参数</param> /// <returns></returns> public static object InvokeWebMethod(string _url ,string _methodName, params object[] _params) { WebClient client = new WebClient(); //String url = "http://localhost:3182/Service1.asmx?WSDL";//这个地址可以写在Config文件里面 Stream stream = client.OpenRead(_url); ServiceDescription description = ServiceDescription.Read(stream); ServiceDescriptionImporter importer = new ServiceDescriptionImporter();//创建客户端代理代理类。 importer.ProtocolName = "Soap"; //指定访问协议。 importer.Style = ServiceDescriptionImportStyle.Client; //生成客户端代理。 importer.CodeGenerationOptions = CodeGenerationOptions.GenerateProperties | CodeGenerationOptions.GenerateNewAsync; importer.AddServiceDescription(description, null, null); //添加WSDL文档。 CodeNamespace nmspace = new CodeNamespace(); //命名空间 nmspace.Name = "TestWebService"; //这个命名空间可以自己取 CodeCompileUnit unit = new CodeCompileUnit(); unit.Namespaces.Add(nmspace); ServiceDescriptionImportWarnings warning = importer.Import(nmspace, unit); CodeDomProvider provider = CodeDomProvider.CreateProvider("CSharp"); CompilerParameters parameter = new CompilerParameters(); parameter.GenerateExecutable = false; parameter.OutputAssembly = "MyTest.dll";//输出程序集的名称 parameter.ReferencedAssemblies.Add("System.dll"); parameter.ReferencedAssemblies.Add("System.XML.dll"); parameter.ReferencedAssemblies.Add("System.Web.Services.dll"); parameter.ReferencedAssemblies.Add("System.Data.dll"); CompilerResults result = provider.CompileAssemblyFromDom(parameter, unit); if (result.Errors.HasErrors) { // 显示编译错误信息 } Assembly asm = Assembly.LoadFrom("MyTest.dll");//加载前面生成的程序集 Type t = asm.GetType("TestWebService.wsTransData_InWH"); //前面的命名空间.类名,类必须是webservice中定义的 object o = Activator.CreateInstance(t); MethodInfo method = t.GetMethod(_methodName);//GetPersons是服务端的方法名称,你想调用服务端的什么方法都可以在这里改,最好封装一下 object item = method.Invoke(o, _params); //注:method.Invoke(o, null)返回的是一个Object,如果你服务端返回的是DataSet,这里也是用(DataSet)method.Invoke(o, null)转一下就行了 //foreach (string str in item) // Console.WriteLine(str); //上面是根据WebService地址,模似生成一个代理类,如果你想看看生成的代码文件是什么样子,可以用以下代码保存下来,默认是保存在bin目录下面 //TextWriter writer = File.CreateText("MyTest.cs"); //provider.GenerateCodeFromCompileUnit(unit, writer, null); //writer.Flush(); //writer.Close(); return item; } } --------------------------------------------------------------------------------------------------- 5.通过反射提取web方法返回的自定义类数据 说明: <1>.WebService方法TestTransDataByDic返回自定义的MyDictionary对象 <2>.它包含两个属性table1,table2 <3>.类定义代码如下 [Serializable] public class MyDictionary { public List<TestModel> Table1 { get; set; } public List<TestModel2> Table2 { get; set; } } <4>.客户端调用代码 private void InvokeDic_Click(object sender, EventArgs e) { //要注意加?WSDL //string _url = "http://localhost:58764/wsTransData_InWH.asmx?WSDL"; int _count = int.Parse(txtCount.Text); object o = InvokeWebServiceDynamic.InvokeWebMethod(_url, "TestTransDataByDic", new object[] { _count }); PropertyInfo _propertyTable1 = o.GetType().GetProperty("Table1"); PropertyInfo _propertyTable2 = o.GetType().GetProperty("Table2"); //读取Table1属性中的数据 object[] _table1Items = (object[])_propertyTable1.GetValue(o, null); if(_table1Items.Length>0) { lstData1.Visible = false; lstData1.Items.Clear(); //反射出对象TestModel的属性 PropertyInfo _propertyNo = _table1Items[0].GetType().GetProperty("No"); PropertyInfo _propertyDes = _table1Items[0].GetType().GetProperty("Des"); for (int i = 0; i < _table1Items.Length; i++) { //根据属性取值 string _no = _propertyNo.GetValue(_table1Items[i], null).ToString(); string _des = _propertyDes.GetValue(_table1Items[i], null).ToString(); string _format = string.Format("第{0}条:{1}", _no, _des); lstData1.Items.Add(_format); } lstData1.Visible = true; } //读取Table2属性中的数据 object[] _table2Items = (object[])_propertyTable2.GetValue(o, null); if (_table2Items.Length > 0) { lstData2.Visible = false; lstData2.Items.Clear(); //反射出对象TestModel2的属性 PropertyInfo _propertyMyFNo = _table2Items[0].GetType().GetProperty("MyFNo"); PropertyInfo _propertyMyFDes = _table2Items[0].GetType().GetProperty("MyFDes"); for (int i = 0; i < _table1Items.Length; i++) { //根据属性取值 string _no = _propertyMyFNo.GetValue(_table2Items[i], null).ToString(); string _des = _propertyMyFDes.GetValue(_table2Items[i], null).ToString(); string _format = string.Format("第{0}条:{1}", _no, _des); lstData2.Items.Add(_format); } lstData2.Visible = true; } MessageBox.Show("OK"); } --------------------------------------------------------------------------------------------------- 6.客户端传递序列化对象给webserice方法 /// <summary> /// /// </summary> /// <param name="_dicGet">是一个客户端传过来的序列化的对象</param> /// <returns></returns> [WebMethod] public string TestInsertData(byte[] _dicGet) { //反序列化对象 object _dicGetOK = SqlHelper.DeserializeObject(_dicGet); return "ok"; } 注意: <1>.创建一个.NET类库,把要传输的对象做成一个结构或类放在类库(假设为ClassLib.dll)中。如: <2>.然后在客户端程序和webservice项目中都引用ClassLib.dll <3>.上面两步的目的是让客户端序列化的对象,在webservice服务端能正常反序列化,不会出现反序列化时找不到命名空间的问题 --------------------------------------------------------------------------------------------------- 7.修改webserivce最大传输的长度 <?xml version="1.0" encoding="utf-8"?> <!-- 有关如何配置 ASP.NET 应用程序的详细消息,请访问 http://go.microsoft.com/fwlink/?LinkId=169433 --> <configuration> <connectionStrings> <add name="ConStr" connectionString="$(ReplacableToken_ConStr-Web.config Connection String_0)"/> </connectionStrings> <system.web> <compilation debug="true" targetFramework="4.0" /> <httpRuntime maxRequestLength="2147483647" /> </system.web> </configuration> 8.修改webservice的超时时间 <?xml version="1.0" encoding="utf-8"?> <!-- 有关如何配置 ASP.NET 应用程序的详细消息,请访问 executionTimeout="120" 超时时间120秒 maxRequestLength="2147483647" 最大请求长度 http://go.microsoft.com/fwlink/?LinkId=169433 --> <configuration> <connectionStrings> <add name="ConStr" connectionString="Data Source=192.128.58.248;Initial catalog=Citibank_test;Uid=sa;pwd=kicpassword"/> </connectionStrings> <system.web> <compilation debug="true" targetFramework="4.0" /> <httpRuntime maxRequestLength="2147483647" executionTimeout="240" /> </system.web> </configuration> 9.序列化,反序列化方法 public static byte[] SerializeObject(object pObj) { if (pObj == null) return null; System.IO.MemoryStream memoryStream = new System.IO.MemoryStream(); BinaryFormatter formatter = new BinaryFormatter(); formatter.Serialize(memoryStream, pObj); memoryStream.Position = 0; byte[] read = new byte[memoryStream.Length]; memoryStream.Read(read, 0, read.Length); memoryStream.Close(); return read; } public static object DeserializeObject(byte[] pBytes) { object newOjb = null; if (pBytes == null) { return newOjb; } System.IO.MemoryStream memoryStream = new System.IO.MemoryStream(pBytes); memoryStream.Position = 0; BinaryFormatter formatter = new BinaryFormatter(); newOjb = formatter.Deserialize(memoryStream); memoryStream.Close(); return newOjb; }
时间: 2024-10-17 11:19:22