C#:Web Service异常处理
2024-07-21 02:20:04
供稿:网友
 
在.net中实现web服务时,在web服务接口中产生的任何用户异常(非soapexception之外的异常)都被包装为soapexception传递给客户端,这使得难以采用通常的方式处理web service的异常。本文讲述如何通过soapexceptionhelper实现一致的异常处理。
web service的异常处理问题
在.net中实现web服务时,web服务接口中产生的任何用户异常(非soapexception之外的异常)都被包装为soapexception传递给客户端 ,用户错误信息放置在soapexception的message属性中。
下面的例子演示了一个soapexception封装的用户异常信息。webmethod接口testexception代码抛出一个invalidoperationexception:
[webmethod]
public void testexception() {
 throw new invalidoperationexception("invalid operation.");
}
webmethod的客户端将捕获一个soapexception异常,message消息如下:
其中message消息包含一段“...-->[ 1 ]:[ 2 ] at ....”的信息,[1]为用户异常类,[2]为用户异常消息。而一个原始的soapexception(用new soapexception(...)的方式创建并抛出的异常)则没有这些信息,下面是一个原始的soapexception消息:
遗憾的是,目前的soapexception并没有提供更多直接的手段直接获取原来的异常信息,唯一包含的用户异常信息在message字符串中,对于使用web service作为分布式机制的应用系统来说是非常不方便的,调用者无法捕获原来的异常,难以获取用户友好的异常信息。同时,因为web service接口代理不再抛出原来的异常,应用的开发者需要考虑两套完全不同的异常处理机制,带来了程序结构的复杂性。
创建soapexception辅助类:soapexceptionhelper
soapexceptionhelper辅助类包含下列主要接口:
isuserexception:是否是一个userexception 
userexception:返回原始的userexception 
message:原始异常的错误消息。 
获得原始的用户异常类和异常消息
通过正则表达式类我们可以获得原始的用户异常类和异常消息:
/// <summary>
/// 读取userexception信息。
/// </summary>
private void readuserexceptioninfo() {
 //match user exception class
 system.text.regularexpressions.matchcollection mc = 
 regex.matches(soapexception.message, "---> ([^:]+):");
 if (mc.count >= 1) {
 userexceptionclass = mc[0].groups[1].value;
 //match user exception message
 mc = regex.matches(soapexception.message, "---> [^:]+:(.*)/n");
 if (mc.count > 0) userexceptionmessage = mc[0].groups[1].value;
 }
}
创建用户异常实例
userexception接口利用反射机制创建一个原来的exception类实例:
... ...
assembly callingassemply = assembly.getcallingassembly();
type exceptiontype = getexceptiontype(callingassemply); //获得用户异常类型定义
exception e = null;
try {
 try {
 e = activator.createinstance(exceptiontype, new object[]{userexceptionmessage}, null) as exception;
 }
 catch {}
 //if no exists constructor with message parameter, use no parameters constructor.
 if (e == null) e = activator.createinstance(exceptiontype) as exception;
}catch(exception ex) {
 throw new soapexceptionhelperexception(userexceptionclass, ex);
}
return e;
创建用户异常的问题
因为用户异常可能定义在不同的集成块中,soapexceptionhelper可能无法知道它的位置,无法正确的获取异常类型,如一个与soapexceptionhelper所在集成块和调用集成块(callingassembly)不再同一个引用范围内的异常类。soapexceptionhelper如果无法创建原始异常的实例,就创建一个system.exception对象实例。 
为了创建真正的原始异常类,调用者可以在外部获得实际的异常类型,并传递给soapexceptionhelper,因为调用者可以明确的引用异常定义 所在的集成块。示例如下:
// 项目引用中引入异常定义所在的集成块
 ...
soapexceptionhelper helper = new soapexceptionhelper(se);
type type = type.gettype(helper.userexceptionclass, "<异常类所在的集成块>");
exception e = helper.getuserexception(type);
如果外部没有传递异常类型定义,soapexceptionhelper尝试以以下顺序获取异常类型定义:
executing assembly 
calling assembly 
referenced assemblies (of calling assembly) 
system.exception 
使用soapexceptionhelper
返回用户友好的消息
使用soapexceptionhelper显示示例1中的错误消息:
try {
 ... ... // call web method
} catch (soapexception se){
 messagebox.show(new soapexceptionhelper(se).message) ; //show "invalid operation." string
}
 
屏蔽soapexception
web service客户端代理类可以在捕获soapexception后重新抛出原来的异常,使用这种机制,可以有效的屏蔽web service异常处理的差异,使应用程序采用一致的本地方式处理异常。下面的代码修改visual studio生成的web service client proxy class(reference.cs文件)实现了这种机制(加粗的部分为新增的代码):
[system.web.services.protocols.soapdocumentmethodattribute("http://tempuri.org/testexception", requestnamespace="http://tempuri.org/", responsenamespace="http://tempuri.org/", use=system.web.services.description.soapbindinguse.literal, parameterstyle=system.web.services.protocols.soapparameterstyle.wrapped)]
public void testexception() {
 try{
 this.invoke("testexception", new object[0]);
 }catch(soapexception se){
 soapexceptionhelper helper = new soapexceptionhelper(se);
 if (helper.isuserexception) throw helper.userexception; //rethrow user exception
 else throw;
 }
}