多数时候我们通过 "添加 Web 引用..." 创建客户端代理类的方式调用WebService,但在某些情况下我们可能需要在程序运行期间动态调用一个未知的服务。在 .NET Framework 的 System.Web.Services.Description 命名空间中有我们需要的东西。
具体步骤:
1. 从目标 URL 下载 WSDL 数据。
2. 使用 ServiceDescription 创建和格式化 WSDL 文档文件。
3. 使用 ServiceDescriptionImporter 创建客户端代理类。
4. 使用 CodeDom 动态创建客户端代理类程序集。
5. 利用反射调用相关 WebService 方法。
OK,看看具体的例子。
我们要调用的目标 WebService,其 URL 是 http://localhost:60436/Learn.WEB/WebService.asmx

HelloWorld.asmx [WebService(Namespace
=
"
http://www.rainsts.net/
"
, Description
=
我的Web服务
)]

[WebServiceBinding(ConformsTo
WsiProfiles.BasicProfile1_1)]

public
class
WebService : System.Web.Services.WebService
{


public WebService () {

}


[WebMethod]

string HelloWorld()

{

return "Hello Wolrd!";

}

}


1
. 动态调用 WebService


客户端动态调用代码

using
System.IO;

System.Net;

System.Reflection;

System.CodeDom;

System.CodeDom.Compiler;

System.Web.Services;

System.Web.Services.Description;

System.Web.Services.Protocols;

System.Xml.Serialization;


//
1. 使用 WebClient 下载 WSDL 信息。

WebClient web
new
WebClient();

Stream stream
web.OpenRead(
http://localhost:60436/Learn.WEB/WebService.asmx?WSDL
);


2. 创建和格式化 WSDL 文档。
ServiceDescription description
ServiceDescription.Read(stream);


3. 创建客户端代理代理类。
ServiceDescriptionImporter importer
ServiceDescriptionImporter();


importer.ProtocolName
Soap
;
指定访问协议。
importer.Style
ServiceDescriptionImportStyle.Client;
生成客户端代理。
importer.CodeGenerationoptions
CodeGenerationoptions.GenerateProperties
|
CodeGenerationoptions.GenerateNewAsync;


importer.AddServiceDescription(description,
null
);
添加 WSDL 文档。


4. 使用 CodeDom 编译客户端代理类。
CodeNamespace nmspace
CodeNamespace();
为代理类添加命名空间,缺省为全局空间。
CodeCompileUnit unit
CodeCompileUnit();

unit.Namespaces.Add(nmspace);


ServiceDescriptionImportWarnings warning
importer.Import(nmspace, unit);

CodeDomProvider provider
CodeDomProvider.CreateProvider(
CSharp
);


CompilerParameters parameter
CompilerParameters();

parameter.GenerateExecutable
false
;

parameter.GenerateInMemory
true
;

parameter.ReferencedAssemblies.Add(
System.dll
);

parameter.ReferencedAssemblies.Add(
System.XML.dll
System.Web.Services.dll
System.Data.dll
);


CompilerResults result
provider.CompileAssemblyFromDom(parameter, unit);


5. 使用 Reflection 调用 WebService。
if
(
!
result.Errors.HasErrors)

{

Assembly asm = result.CompiledAssembly;

Type t asm.GetType(WebService); // 如果在前面为代理类添加了命名空间,此处需要将命名空间添加到类型前面。


object o Activator.CreateInstance(t);

MethodInfo method t.getmethod(HelloWorld);

Console.WriteLine(method.Invoke(o, null));

}

2. 生成客户端代理程序集文件
上面的代码通过在内存中创建动态程序集的方式完成了动态调用过程。如果我们希望将客户端代理类生成程序集文件保存到硬盘,则可以进行如下修改。生成程序集文件后,我们可以通过 Assembly.LoadFrom() 载入并进行反射调用。对于需要多次调用的系统,要比每次生成动态程序集效率高出很多。
;

p
arameter.OutputAssembly
test.dll
可以指定你所需的任何文件名。
parameter.ReferencedAssemblies.Add(
ottom:0px; margin-left:0px; padding-top:0px; padding-right:0px; padding-bottom:0px; padding-left:0px; font-family:'Courier New'; font-size:12px; line-height:1.5; color:rgb(128, unit);

(result.Errors.HasErrors)

{

显示编译错误信息

}


调用程序集文件演示

Assembly asm
Assembly.LoadFrom(
);

Type t
asm.GetType(
WebService
);


object
o
Activator.CreateInstance(t);

MethodInfo method
t.getmethod(
HelloWorld
);

Console.WriteLine(method.Invoke(o,0)">));

3. 获取客户端代理类源代码
还有一种情形,就是我们需要获得客户端代理类的 C# 源代码。
5. 保存源
代码到
文件。当然,你也可以直接保存到内存字符串中。
TextWriter writer
File.CreateText(
test.cs
指定你所需的源代码文件名。
provider.GenerateCodeFromCompileUnit(unit, writer,0)">);

writer.Flush();

writer.Close();


如果你调用时触发 "WebException: 请求因 HTTP 状态 415 失败: Unsupported Media Type。" 这样的异常,那么恭喜你和我一样郁闷,赶紧把服务器端的 WSE 关掉吧。在必须使用 WSE 的情况下,需要对客户端进行调整.
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。