资源描述
整理,内容来源于网络及本人实践】
前面整理了一篇关于VS2008实现简单的WebService的文章,但里面的调用是静态的,当服务地址更改后,需要重新编译程序,对于很多应用来说是不现实的。本文介绍一下C#动态调用WebService的方法。
1.实现
写个叫WebServiceHelper的类
[csharp] view plaincopyprint?
1. namespace webhelp
2. {
3. using System;
4. using System.Net;
5. using System.IO;
6. using System.CodeDom;
7. using Microsoft.CSharp;
8. using System.CodeDom.Compiler;
9. using System.Web.Services.Description;
10. using System.Web.Services.Protocols;
11. public class WebServiceHelper
12. {
13. #region InvokeWebService
14.
15. public static object InvokeAndCallWebService(string url, string methodname, object[] args)
16. {
17. return WebServiceHelper.InvokeAndCallWebService(url, null, methodname, args);
18. }
19. public static object InvokeAndCallWebService(string url,/* string @namespace, */string classname, string methodname, object[] args)
20. {
21. string @namespace = "EnterpriseServerBase.WebService.DynamicWebCalling";
22. if ((classname == null) || (classname == ""))
23. {
24. classname = WebServiceHelper.GetWsClassName(url);
25. }
26.
27. try
28. {
29. //获取WSDL
30. WebClient webClient = new WebClient();
31. Stream stream = webClient.OpenRead(url + "?WSDL");
32. ServiceDescription description = ServiceDescription.Read(stream);
33. ServiceDescriptionImporter descriptionImporter = new ServiceDescriptionImporter();
34. descriptionImporter.AddServiceDescription(description, "", "");
35. CodeNamespace codeNamespace = new CodeNamespace(@namespace);
36.
37. //生成客户端代理类代码
38. CodeCompileUnit codeCompileUnit = new CodeCompileUnit();
39. codeCompileUnit.Namespaces.Add(codeNamespace);
40. descriptionImporter.Import(codeNamespace, codeCompileUnit);
41. CSharpCodeProvider codeProvider = new CSharpCodeProvider();
42.
43. //设定编译参数
44. CompilerParameters compilerParameters = new CompilerParameters();
45. compilerParameters.GenerateExecutable = false;
46. compilerParameters.GenerateInMemory = true;
47. compilerParameters.ReferencedAssemblies.Add("System.dll");
48. compilerParameters.ReferencedAssemblies.Add("System.XML.dll");
49. compilerParameters.ReferencedAssemblies.Add("System.Web.Services.dll");
50. compilerParameters.ReferencedAssemblies.Add("System.Data.dll");
51.
52. //编译代理类
53. CompilerResults codeResult = codeProvider.CompileAssemblyFromDom(compilerParameters, codeCompileUnit);
54. if (true == codeResult.Errors.HasErrors)
55. {
56. System.Text.StringBuilder stringBuilder = new System.Text.StringBuilder();
57. foreach (System.CodeDom.Compiler.CompilerError compileError in codeResult.Errors)
58. {
59. stringBuilder.Append(compileError.ToString());
60. stringBuilder.Append(System.Environment.NewLine);
61. }
62. throw new Exception(stringBuilder.ToString());
63. }
64.
65. //生成代理实例,并调用方法
66. System.Reflection.Assembly assembly = codeResult.CompiledAssembly;
67. Type @class = assembly.GetType(@namespace + "." + classname, true, true);
68. object instance = Activator.CreateInstance(@class);
69. System.Reflection.MethodInfo methorInfo = @class.GetMethod(methodname);
70.
71. return methorInfo.Invoke(instance, args);
72.
73. }
74. catch (Exception ex)
75. {
76. throw new Exception(ex.InnerException.Message, new Exception(ex.InnerException.StackTrace));
77. }
78. }
79.
80. private static string GetWsClassName(string wsUrl)
81. {
82. string[] parts = wsUrl.Split('/');
83. string[] pps = parts[parts.Length - 1].Split('.');
84.
85. return pps[0];
86. }
87. #endregion
88. }
89. }
namespace webhelp
{
using System;
using System.Net;
using System.IO;
using System.CodeDom;
using Microsoft.CSharp;
using System.CodeDom.Compiler;
using System.Web.Services.Description;
using System.Web.Services.Protocols;
public class WebServiceHelper
{
#region InvokeWebService
public static object InvokeAndCallWebService(string url, string methodname, object[] args)
{
return WebServiceHelper.InvokeAndCallWebService(url, null, methodname, args);
}
public static object InvokeAndCallWebService(string url,/* string @namespace, */string classname, string methodname, object[] args)
{
string @namespace = "EnterpriseServerBase.WebService.DynamicWebCalling";
if ((classname == null) || (classname == ""))
{
classname = WebServiceHelper.GetWsClassName(url);
}
try
{
//获取WSDL
WebClient webClient = new WebClient();
Stream stream = webClient.OpenRead(url + "?WSDL");
ServiceDescription description = ServiceDescription.Read(stream);
ServiceDescriptionImporter descriptionImporter = new ServiceDescriptionImporter();
descriptionImporter.AddServiceDescription(description, "", "");
CodeNamespace codeNamespace = new CodeNamespace(@namespace);
//生成客户端代理类代码
CodeCompileUnit codeCompileUnit = new CodeCompileUnit();
codeCompileUnit.Namespaces.Add(codeNamespace);
descriptionImporter.Import(codeNamespace, codeCompileUnit);
CSharpCodeProvider codeProvider = new CSharpCodeProvider();
//设定编译参数
CompilerParameters compilerParameters = new CompilerParameters();
compilerParameters.GenerateExecutable = false;
compilerParameters.GenerateInMemory = true;
compilerParameters.ReferencedAssemblies.Add("System.dll");
compilerParameters.ReferencedAssemblies.Add("System.XML.dll");
compilerParameters.ReferencedAssemblies.Add("System.Web.Services.dll");
compilerParameters.ReferencedAssemblies.Add("System.Data.dll");
//编译代理类
CompilerResults codeResult = codeProvider.CompileAssemblyFromDom(compilerParameters, codeCompileUnit);
if (true == codeResult.Errors.HasErrors)
{
System.Text.StringBuilder stringBuilder = new System.Text.StringBuilder();
foreach (System.CodeDom.Compiler.CompilerError compileError in codeResult.Errors)
{
stringBuilder.Append(compileError.ToString());
stringBuilder.Append(System.Environment.NewLine);
}
throw new Exception(stringBuilder.ToString());
}
//生成代理实例,并调用方法
System.Reflection.Assembly assembly = codeResult.CompiledAssembly;
Type @class = assembly.GetType(@namespace + "." + classname, true, true);
object instance = Activator.CreateInstance(@class);
System.Reflection.MethodInfo methorInfo = @class.GetMethod(methodname);
return methorInfo.Invoke(instance, args);
}
catch (Exception ex)
{
throw new Exception(ex.InnerException.Message, new Exception(ex.InnerException.StackTrace));
}
}
private static string GetWsClassName(string wsUrl)
{
string[] parts = wsUrl.Split('/');
string[] pps = parts[parts.Length - 1].Split('.');
return pps[0];
}
#endregion
}
}
2.注意
1.)若编译提示“命名空间“System.Web”中不存在类型或命名空间名称“Services”(是缺少程序集引用吗?)”,只需在解决方案资源管理器中添加对System.Web.Services的程序集引用即可。
2.)不建议调用
[csharp] view plaincopyprint?
1. public static object InvokeAndCallWebService(string url, string methodname, object[] args)
public static object InvokeAndCallWebService(string url, string methodname, object[] args)
即不指定类名,让程序由URL中分析出类名,因为不是所有服务的类名都放在URL的最后一个‘/’和‘.’中间的。
3.)@namespace不一定要取"EnterpriseServerBase.WebService.DynamicWebCalling",从我的实验中,取任意@namespace,甚至@namespace是空串都能够正常运行。
4.)网上有人说用这种方法调用Java写的Webservice时有问题,说是异常提示报的是无法获得相应空间里的类,有人说跟Java不要命名空间有关。我特意请同学帮我做一个java 的webservice(因为我不会java),实验证明这种方法并没有什么问题,我猜测报异常可能是因为没有指定类名,而是代码根据url分析类名,或者有可能是服务返回类型是一些复杂类型的值,建议返回类型最好是string或int之类的。
5.)在这种方法中url、命名空间、类名、函数名都是字符串,可以根据需要进行赋值。
3.调用
注意到上面实现的InvokeAndCallWebService是个静态函数,所以想利用WebServiceHelper调用Webservice方法如下。
[csharp] view plaincopyprint?
1. string url = "http://192.168.0.113/NM2SMARTB/INM2SmartSoap11Binding.asmx";
2. string[] args = new string[1];
3. args[0] = "hello";
4. object result = webhelp.WebServiceHelper.InvokeAndCallWebService(url, "Nm2Smart", "getDevices", args);
string url = "http://192.168.0.113/NM2SMARTB/INM2SmartSoap11Binding.asmx";
string[] args = new string[1];
args[0] = "hello";
object result = webhelp.WebServiceHelper.InvokeAndCallWebService(url, "Nm2Smart", "getDevices", args);
4.变化
上面的WebServiceHelper利用静态方法实现动态调用WebService,但是仍存在一个问题,就是每次函数InvokeAndCallWebService都要重新获取服务、生成代理等一系列过程,这样子的效率很低。所以可以对WebServiceHelper稍作修改,在服务没更改的的时候,只生成一次代理,可以多次调用其中的函数。大部分代码仍和上面一样。只是将服务实例化代码和调用分开,将InvokeAndCallWebService中的局部变量instance和@class变为类成员变量。如此只要声明一个WebServiceHelper对象,就可以只生成一次代理,多次调用函数,直到必要的时候再重新生成代理实例。当然此时函数已不是静态函数。
[csharp] view plaincopyprint?
1. namespace webhelp
2. {
3. using System;
4. using System.Net;
5. using System.IO;
6. using System.CodeDom;
7. using Microsoft.CSharp;
8. using System.CodeDom.Compiler;
9. using System.Web.Services.Description;
10. using System.Web.Services.Protocols;
11. public class WebServiceHelper
12. {
13. #region InvokeWebService
14. object instance;//将原来函数内的局部变量变为类成员
15. Type @class;//将原来函数内的局部变量变为类成员
16.
17. public void InvokeWebService(string url,/* string @namespace,*/ string classname)
18. {
19. string @namespace = "EnterpriseServerBase.WebService.DynamicWebCalling";
20. if ((classname == null) || (classname == ""))
21. {
22. classname = WebServiceHelper.GetWsClassName(url);
23. }
24.
25. try
26. {
27. //获取WSDL
28. WebClient webClient = new WebClient();
29. Stream stream = webClient.OpenRead(url + "?WSDL");
30. ServiceDescription description = ServiceDescription.Read(stream);
31. ServiceDescriptionImporter descriptionImporter = new ServiceDescriptionImporter();
32. descriptionImporter.AddServiceDescription(description, "", "");
33. CodeNamespace codeNamespace = new CodeNamespace(@namespace);
34.
35. //生成客户端代理类代码
36. CodeCompileUnit codeCompileUnit = new CodeCompileUnit();
37. codeCompileUnit.Namespaces.Add(codeNamespace);
38. descriptionImporter.Import(codeNamespace, codeCompileUnit);
39. CSharpCodeProvider codeProvider = new CSharpCodeProvider();
40.
41. //设定编译参数
42. CompilerParameters compilerParameters = new CompilerParameters();
43. compilerParameters.GenerateExecutable = false;
44. compilerParameters.GenerateInMemory = true;
45. compilerParameters.ReferencedAssemblies.Add("System.dll");
46. compilerParameters.ReferencedAssemblies.Add("System.XML.dll");
47. compilerParameters.ReferencedAssemblies.Add("System.Web.Services.dll");
48. compilerParameters.ReferencedAssemblies.Add("System.Data.dll");
49.
50. //编译代理类
51. CompilerResults codeResult = codeProvider.CompileAssemblyFromDom(compilerParameters, codeCompileUnit);
52. if (true == codeResult.Errors.HasErrors)
53. {
54. System.Text.StringBuilder stringBuilder = new System.Text.StringBuilder();
55. foreach (System.CodeDom.Compiler.CompilerError compileError in codeResult.Errors)
56. {
57. stringBuilder.Append(compileError.ToString());
58. stringBuilder.Append(System.Environment.NewLine);
59. }
60. throw new Exception(stringBuilder.ToString());
61. }
62.
63. //生成代理实例
64. System.Reflection.Assembly assembly = codeResult.CompiledAssembly;
65. @class = assembly.GetType(@namespace + "." + classname, true, true);
66. instance = Activator.CreateInstance(@class);
67. // return instance;
68. }
69. catch (Exception ex)
70. {
71. throw new Exception(ex.InnerException.Message, new Exception(ex.InnerException.StackTrace));
72. }
73. }
74. public object CallService(string methodname, object[] args)//调用方法与生成代理实例分开
75. {
76. try
77. {
78. System.Reflection.MethodInfo methorInfo = @class.GetMethod(methodname);
79. return methorInfo.Invoke(instance, args);
80. }
81. catch (System.Exception ex)
82. {
83. throw ex;
84. }
85. }
86.
87. #endregion
88. }
89. }
namespace webhelp
{
using System;
using System.Net;
using System.IO;
using System.CodeDom;
using Microsoft.CSharp;
using System.CodeDom.Compiler;
using System.Web.Services.Description;
using System.Web.Services.Protocols;
public class WebServiceHelper
{
#region InvokeWebService
object instance;//将原来函数内的局部变量变为类成员
Type @class;//将原来函数内的局部变量变为类成员
public void InvokeWebService(string url,/* string @namespace,*/ string classname)
{
string @namespace = "EnterpriseServerBase.WebService.DynamicWebCalling";
if ((classname == null) || (classname == ""))
{
classname = WebServiceHelper.GetWsClassName(url);
}
try
{
//获取WSDL
WebClient webClient = new WebClient();
Stream stream = webClient.OpenRead(url + "?WSDL");
ServiceDescription description = ServiceDescription.Read(stream);
ServiceDescriptionImporter descriptionImporter = new ServiceDescriptionImporter();
descriptionImporter.AddServiceDescription(description, "", "");
CodeNamespace codeNamespace = new CodeNamespace(@namespace);
//生成客户端代理类代码
CodeCompileUnit codeCompileUnit = new CodeCompileUnit();
codeCompileUnit.Namespaces.Add(codeNamespace);
descriptionImporter.Import(codeNamespace, codeCompileUnit);
CSharpCodeProvider codeProvider = new CSharpCodeProvider();
//设定编译参数
CompilerParameters compilerParameters = new CompilerParameters();
compilerParameters.GenerateExecutable = false;
compilerParameters.GenerateInMemory = true;
compilerParameters.ReferencedAssemblies.Add("System.dll");
compilerParameters.ReferencedAssemblies.Add("System.XML.dll");
compilerParameters.ReferencedAssemblies.Add("System.Web.Services.dll");
compilerParameters.ReferencedAssemblies.Add("System.Data.dll");
//编译代理类
CompilerResults codeResult = codeProvider.CompileAssemblyFromDom(compilerParameters, codeCompileUnit);
if (true == codeResult.Errors.HasErrors)
{
System.Text.StringBuilder stringBuilder = ne
展开阅读全文