两种方式:
一、返回错误信息和错误码,这样客户端可以把错误信息直接显示给用户,省去了解析错误码的烦恼。
服务器端实现:
下面的类解析错误码定义文件,并且把错误信息加入hastTable
异常抛出方式:
客户端如果检测到是MeetingBaseException就可以直接把错误信息显示给客户,而不用解析错误码。
缺点:虽然省去了错误码的解析,但是如果有多语言化问题,错误信息直接显示就不行了。
如果客户端想只显示某些错误信息给客户,这种方式也不方便。
二、只返回错误码,客户端去解析错误码,这样提供了,最大的灵活性。
实现:服务器省去了错误码的解析。
异常抛出方式:
下面是用到资源文件的例子,如果只有一种资源,就可以用ErrProcedure处理。
因为全局资源被编译为资源类,而错误码是数字,不能做标志符,因此把他做简单处理,正数前加“R”,负数加“R_”,修改后类似(简体资源):
此处用反射简化了很多,见 http://www.cnblogs.com/bluewater/archive/2006/09/08/498660.html
我认为第二种方式在大多数情况下都比较好,如果是很小的项目,第一种方式会简单些。
webservice异常处理:
在webservice中抛出异常,让客户端去解析是很困难的,因为客户端可能是js,php等,对ws的封装很差。因此我认为好一些的异常处理应该这样:
返回结果分两种类型,一种是只包含简单的错误码:
先定义返回值类型如,HistoryFeeResult
实现方式和第一种一样,只是如果有自定义异常,则调用HistoryFeeResult的只有错误码的构造函数。
如果调用成功会返回(Post方式):
一、返回错误信息和错误码,这样客户端可以把错误信息直接显示给用户,省去了解析错误码的烦恼。
服务器端实现:
下面的类解析错误码定义文件,并且把错误信息加入hastTable
using
System;
using System.Collections.Generic;
using System.Text;
using System.Xml.Serialization;
using System.IO;
using System.Xml;
using System.Web;
using System.Web.Caching;
using System.Collections;
namespace MeetingProxy.MeetingException
{
/**//// <summary>
/// 错误码的描述
/// </summary>
public class ErrProcedure
{
private static Hashtable errMessages = new Hashtable();
public static Hashtable GetErrMessages()
{
if (CommonCache.Get("ErrMessage") as Hashtable == null)
{
string path = null;
HttpContext context = HttpContext.Current;
if (context != null)
path = context.Server.MapPath("~ErrMessage.xml");
else
path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "ErrMessage.xml");
XmlDocument xdoc = new XmlDocument();
xdoc.Load(path);
foreach (XmlNode child in xdoc.LastChild)
{
errMessages.Add(int.Parse(child.LastChild.InnerText), child.FirstChild.InnerText);
}
CacheDependency cd = new CacheDependency(path);
CommonCache.Max("ErrMessage", errMessages,cd);
return errMessages;
}
else
{
return CommonCache.Get("ErrMessage") as Hashtable;
}
}
}
}
错误码文件:
using System.Collections.Generic;
using System.Text;
using System.Xml.Serialization;
using System.IO;
using System.Xml;
using System.Web;
using System.Web.Caching;
using System.Collections;
namespace MeetingProxy.MeetingException
{
/**//// <summary>
/// 错误码的描述
/// </summary>
public class ErrProcedure
{
private static Hashtable errMessages = new Hashtable();
public static Hashtable GetErrMessages()
{
if (CommonCache.Get("ErrMessage") as Hashtable == null)
{
string path = null;
HttpContext context = HttpContext.Current;
if (context != null)
path = context.Server.MapPath("~ErrMessage.xml");
else
path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "ErrMessage.xml");
XmlDocument xdoc = new XmlDocument();
xdoc.Load(path);
foreach (XmlNode child in xdoc.LastChild)
{
errMessages.Add(int.Parse(child.LastChild.InnerText), child.FirstChild.InnerText);
}
CacheDependency cd = new CacheDependency(path);
CommonCache.Max("ErrMessage", errMessages,cd);
return errMessages;
}
else
{
return CommonCache.Get("ErrMessage") as Hashtable;
}
}
}
}
<?
xml version
=
"
1.0
"
encoding
=
"
UTF-8
"
?>
< ErrMessage >
< Err >
< Description > 登录会议室错误 </ Description >
< ErrCode > 100 </ ErrCode >
</ Err >
< Err >
< Description > 您申请的会议室被别人抢用,会议室创建失败,请重新申请 </ Description >
< ErrCode > 101 </ ErrCode >
</ Err >
< Err >
< Description > 必须有端口号 </ Description >
< ErrCode > 200 </ ErrCode >
</ Err >
< Err >
< Description > 用户名或者密码错误 </ Description >
< ErrCode > 300 </ ErrCode >
</ Err >
</ ErrMessage >
异常定义:
< ErrMessage >
< Err >
< Description > 登录会议室错误 </ Description >
< ErrCode > 100 </ ErrCode >
</ Err >
< Err >
< Description > 您申请的会议室被别人抢用,会议室创建失败,请重新申请 </ Description >
< ErrCode > 101 </ ErrCode >
</ Err >
< Err >
< Description > 必须有端口号 </ Description >
< ErrCode > 200 </ ErrCode >
</ Err >
< Err >
< Description > 用户名或者密码错误 </ Description >
< ErrCode > 300 </ ErrCode >
</ Err >
</ ErrMessage >
using
System;
using System.Collections.Generic;
using System.Text;
namespace MeetingProxy
{
public class MeetingBaseException:ApplicationException
{
int errCode;
public MeetingBaseException(string message, int errCode)
: base(message)
{
this.errCode = errCode;
}
public MeetingBaseException(int errCode)
{
this.errCode = errCode;
}
public int ErrCode
{
get { return errCode; }
set { this.errCode = value; }
}
}
}
using System.Collections.Generic;
using System.Text;
namespace MeetingProxy
{
public class MeetingBaseException:ApplicationException
{
int errCode;
public MeetingBaseException(string message, int errCode)
: base(message)
{
this.errCode = errCode;
}
public MeetingBaseException(int errCode)
{
this.errCode = errCode;
}
public int ErrCode
{
get { return errCode; }
set { this.errCode = value; }
}
}
}
异常抛出方式:
private
string
VerifySession()
{
string passport = null;
if (HttpContext.Current != null)
{
passport = HttpContext.Current.Session["Username"] as string;
}
if (passport == null)
{
//用户没有通过Session验证
throw new MeetingBaseException(ErrProcedure.GetErrMessages()[301].ToString(), 301);
}
return passport;
}
客户端:
{
string passport = null;
if (HttpContext.Current != null)
{
passport = HttpContext.Current.Session["Username"] as string;
}
if (passport == null)
{
//用户没有通过Session验证
throw new MeetingBaseException(ErrProcedure.GetErrMessages()[301].ToString(), 301);
}
return passport;
}
客户端如果检测到是MeetingBaseException就可以直接把错误信息显示给客户,而不用解析错误码。
缺点:虽然省去了错误码的解析,但是如果有多语言化问题,错误信息直接显示就不行了。
如果客户端想只显示某些错误信息给客户,这种方式也不方便。
二、只返回错误码,客户端去解析错误码,这样提供了,最大的灵活性。
实现:服务器省去了错误码的解析。
异常抛出方式:
throw
new
MeetingBaseException(
108
);
客户端实现:
下面是用到资源文件的例子,如果只有一种资源,就可以用ErrProcedure处理。
因为全局资源被编译为资源类,而错误码是数字,不能做标志符,因此把他做简单处理,正数前加“R”,负数加“R_”,修改后类似(简体资源):
<
data name
=
"
R303
"
xml:space
=
"
preserve
"
>
< value > 用户名已经存在 </ value >
</ data >
<data name="R_500" xml:space="preserve">
<value>系统异常</value>
</data>
处理方式:
< value > 用户名已经存在 </ value >
</ data >
<data name="R_500" xml:space="preserve">
<value>系统异常</value>
</data>
public
static
string
GetErrInfo(
int
errCode)
{
string resourceKey;
if (errCode >= 0)
{
resourceKey = "R" + errCode.ToString();
}
else
{
errCode = errCode * -1;
resourceKey = "R_" + errCode.ToString();
}
Type t = typeof(Resources.Login);
PropertyInfo pi = t.GetProperty(resourceKey);
return pi.GetValue(null, null).ToString();
}
{
string resourceKey;
if (errCode >= 0)
{
resourceKey = "R" + errCode.ToString();
}
else
{
errCode = errCode * -1;
resourceKey = "R_" + errCode.ToString();
}
Type t = typeof(Resources.Login);
PropertyInfo pi = t.GetProperty(resourceKey);
return pi.GetValue(null, null).ToString();
}
此处用反射简化了很多,见 http://www.cnblogs.com/bluewater/archive/2006/09/08/498660.html
我认为第二种方式在大多数情况下都比较好,如果是很小的项目,第一种方式会简单些。
webservice异常处理:
在webservice中抛出异常,让客户端去解析是很困难的,因为客户端可能是js,php等,对ws的封装很差。因此我认为好一些的异常处理应该这样:
返回结果分两种类型,一种是只包含简单的错误码:
using
System;
using System.Collections.Generic;
using System.Text;
namespace YahooBase.Result
{
/**//// <summary>
/// 普通返回值
/// </summary>
public class SoapResult
{
private int errCode;
public SoapResult()
{ }
public SoapResult(int errCode)
{
this.errCode = errCode;
}
public int ErrCode
{
get
{ return errCode; }
set { errCode = value; }
}
}
}
web服务方法实现:
using System.Collections.Generic;
using System.Text;
namespace YahooBase.Result
{
/**//// <summary>
/// 普通返回值
/// </summary>
public class SoapResult
{
private int errCode;
public SoapResult()
{ }
public SoapResult(int errCode)
{
this.errCode = errCode;
}
public int ErrCode
{
get
{ return errCode; }
set { errCode = value; }
}
}
}
[WebMethod()]
public SoapResult FreeConfrence()
{
try
{
mc.FreeConfrence();
return new SoapResult(0);
}
catch (MeetingBaseException me)
{
return new SoapResult(me.ErrCode);
}
catch (ApplicationException ae)
{
Log4net.log.Error(ae);
return new SoapResult(-500);
}
catch (Exception e)
{
if (e.InnerException != null)
{
Log4net.log.Error(e.InnerException);
}
Log4net.log.Error(e);
return new SoapResult(-500);
}
}
另一种返回复杂结果:
public SoapResult FreeConfrence()
{
try
{
mc.FreeConfrence();
return new SoapResult(0);
}
catch (MeetingBaseException me)
{
return new SoapResult(me.ErrCode);
}
catch (ApplicationException ae)
{
Log4net.log.Error(ae);
return new SoapResult(-500);
}
catch (Exception e)
{
if (e.InnerException != null)
{
Log4net.log.Error(e.InnerException);
}
Log4net.log.Error(e);
return new SoapResult(-500);
}
}
先定义返回值类型如,HistoryFeeResult
using
System;
using System.Collections.Generic;
using System.Text;
namespace YahooBase.Result
{
/**//// <summary>
/// 查询历史帐单信息
/// </summary>
public class HistoryFeeResult:SoapResult
{
public HistoryFeeResult(int errCode):base(errCode)
{}
public HistoryFeeResult()
{}
public MonthFee[] MonthFeeList;
}
public class MonthFee
{
public string MonthName;
public Category[] CategoryList;
}
public class Category
{
public Category(decimal fee, string name)
{
Fee = fee;
Name = name;
}
public Category()
{ }
public decimal Fee;
public string Name;
}
}
web方法实现:
using System.Collections.Generic;
using System.Text;
namespace YahooBase.Result
{
/**//// <summary>
/// 查询历史帐单信息
/// </summary>
public class HistoryFeeResult:SoapResult
{
public HistoryFeeResult(int errCode):base(errCode)
{}
public HistoryFeeResult()
{}
public MonthFee[] MonthFeeList;
}
public class MonthFee
{
public string MonthName;
public Category[] CategoryList;
}
public class Category
{
public Category(decimal fee, string name)
{
Fee = fee;
Name = name;
}
public Category()
{ }
public decimal Fee;
public string Name;
}
}
实现方式和第一种一样,只是如果有自定义异常,则调用HistoryFeeResult的只有错误码的构造函数。
如果调用成功会返回(Post方式):
<?
xml version="1.0" encoding="utf-8"
?>
- < HistoryFeeResult xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd ="http://www.w3.org/2001/XMLSchema" xmlns ="http://tempuri.org/" >
< ErrCode > 0 </ ErrCode >
- < MonthFeeList >
- < MonthFee >
< MonthName > 三月 </ MonthName >
- < CategoryList >
- < Category >
< Fee > 44.6 </ Fee >
< Name > 市话 </ Name >
</ Category >
- < Category >
< Fee > 46.6 </ Fee >
< Name > 长途 </ Name >
</ Category >
</ CategoryList >
</ MonthFee >
</ MonthFeeList >
</ HistoryFeeResult >
出错会返回(Post方式):
- < HistoryFeeResult xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd ="http://www.w3.org/2001/XMLSchema" xmlns ="http://tempuri.org/" >
< ErrCode > 0 </ ErrCode >
- < MonthFeeList >
- < MonthFee >
< MonthName > 三月 </ MonthName >
- < CategoryList >
- < Category >
< Fee > 44.6 </ Fee >
< Name > 市话 </ Name >
</ Category >
- < Category >
< Fee > 46.6 </ Fee >
< Name > 长途 </ Name >
</ Category >
</ CategoryList >
</ MonthFee >
</ MonthFeeList >
</ HistoryFeeResult >
<?
xml version="1.0" encoding="utf-8"
?>
< HistoryFeeResult xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd ="http://www.w3.org/2001/XMLSchema" xmlns ="http://tempuri.org/" >
< ErrCode > 105 </ ErrCode >
</ HistoryFeeResult >
这样客户端就可以从解析服务器端异常的繁重工作中解脱出来,也易于和非.net程序的交互。
< HistoryFeeResult xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd ="http://www.w3.org/2001/XMLSchema" xmlns ="http://tempuri.org/" >
< ErrCode > 105 </ ErrCode >
</ HistoryFeeResult >