WCF在同步和异常调用情况下的异常捕获
1 前言
关于WCF的基本信息,我就不在这里介绍了。一来是因为园子中的很多人都介绍过了,而且很是详细,再不行,还可以看书。二来是因为自己的概念表达还不是很好,别误导了大家。
在这里,我就直接讲解一种用法,然后贴点代码吧。
在WCF有一种契约,叫做错误契约FaultContract。
今天我就讲解一下,在同步和异步调用WCF服务的时候,客户端如何捕获服务端抛出来的异常。捕获之后,如何处理,那就是根据项目的要求了。是提示呢?还是记录日志呢?还是其他什么的。。。。。。。。。。。。
2 正文
其他对于同步和异步来说,WCF处理异常的手段是一致的。都是将异常信息,通过我们自定义的一个异常信息类,传输到客户端。客户端获取到这个类的信息,然后就知道了具体的异常。然后如何处理,就是客户端的事情了。
2.1 服务定义
错误契约定义
- [DataContract]
- public class CallException
- {
- public CallException() { }
- public CallException(string message, string detail)
- { Message = message;
- Detail = detail;
- }
- [DataMember]
- public string Message { get; set; }
- [DataMember]
- public string Detail { get; set; }
- }
接口定义
- [ServiceContract]
- public interface IService1
- {
- [OperationContract]
- [FaultContract(typeof(CallException))]
- User GetUserByID(int id,string communCode, out CallException callException);
-
- [OperationContract]
- [FaultContract(typeof(CallException))]
- [ServiceKnownType(typeof(User ))]
- BaseClass.EntityBase GetByIDWithAuthentication(int id, out CallException callException);
- }
接口实现
- [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
- [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
- [Common.MyServiceBehavior()]
- public class Service1Impl : BaseClass.ServiceBase, IService1
- {
-
- #region IService1 Members
-
- public User GetUserByID(int id, string communCode, out CallException callException)
- {
- callException = null;
- User user = null;
- BLL.UserBLL userBll = Common.ServiceLocator.LoadService<BLL.UserBLL>();
- user= userBll.GetUserByID(id, out callException);
- return user;
- }
-
-
- public BaseClass.EntityBase GetByIDWithAuthentication(int id, out CallException callException)
- {
- callException = null;
- User user = null;
- BLL.UserBLL userBll = Common.ServiceLocator.LoadService<BLL.UserBLL>();
- user = userBll.GetByID(id, out callException);
- return user;
- }
-
- #endregion
- }
业务逻辑类
- public class UserBLL : BaseClass.BLLBase
- {
- public UserBLL(Common.DALHelper dalHelper)
- {
- _dalHelper = dalHelper;
- }
- private Common.DALHelper _dalHelper;
-
-
- [Common.ExceptionCallHandler("你没有权限", "", "", "你没有权限啊BLL")]
- public User GetByID(int id, out CallException callException)
- {
- callException = null;
- if (id < 10)
- {
- callException = new CallException()
- {
- Message = "获取用户",
- Detail = "必须大于等于10"
- };
- throw new FaultException<CallException>(callException, "parameter error");
- }
- else
- {
- User user = null;
- int b = 0;
- user = _dalHelper.UserDal.GetByID(id, ref b, out callException);
- return user;
- }
- }
- [Common.ExceptionCallHandler("你没有权限", "", "", "你没有权限啊BLL")]
- public User GetUserByID(int id, out CallException callException)
- {
- User user = null;
- callException = null;
- if (id < 10)
- {
- callException = new CallException()
- {
- Message = "获取用户",
- Detail = "必须大于等于10"
- };
- }
- else
- {
- int b = 0;
- user = _dalHelper.UserDal.GetByID(id, ref b, out callException);
- } return user;
- }
- }
在业务逻辑类中判断参数的合法性,不合法抛出异常。大家看到有两个方法,一个是直接抛出异常,一个是没有抛出任何异常。后面将这两个的用处。
2.2 同步调用
同步调用,我们用控制台程序来模拟客户端。
同步方式调用WCF的时候,我们可以直接try。。。catch。。。来捕获这个异常信息,然后进行处理。
代码如下:
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.ServiceModel;
- using System.ServiceModel.Channels;
-
- namespace ConsoleConsumer
- {
- class Program
- {
- static void Main(string[] args)
- {
- Service1.Service1Client client = new Service1.Service1Client();
- using (OperationContextScope scope = new OperationContextScope((IContextChannel)client.InnerChannel))
- {
- MessageHeaders messageHeadersElement = OperationContext.Current.OutgoingMessageHeaders;
- messageHeadersElement.Add(MessageHeader.CreateHeader("username", "", "kd"));
- messageHeadersElement.Add(MessageHeader.CreateHeader("password", "", "kd"));
- }
- Console.WriteLine("请输入ID:");
- int id =int.Parse ( Console.ReadLine());
- Service1.CallException callException = null;
- try
- {
-
- client.GetByIDWithAuthentication(out callException, id);
- Console.WriteLine("成功调用");
- }
- catch (FaultException<Service1.CallException> ex)
- {
- Console.WriteLine("半路接获CallException Error:{0},{1}", ex.Detail.Message, ex.Detail.Detail);
- }
- catch (FaultException<System.IO.EndOfStreamException> ex)
- {
- Console.WriteLine("半路接获EndOfStreamException Error:{0},{1}", ex.Detail.Message, ex.Detail.HelpLink );
- }
- catch (Exception ex)
- {
- Console.WriteLine("最后一关 Error:{0},{1}", ex.Message, ex.HelpLink);
- }
-
- Console.Read();
- }
- }
- }
主要是看
catch (FaultException<Service1.CallException> ex) 这一句。就好像是,WCF将我们的异常信息类包装到FaultException这个类中。然后ex.Detail就是CallException这个我们自定义的实体类型了。那就可以根据这个实体的属性进行异常的处理了。
2.3 异步调用
异步调用,我们用Silverlight来模型客户端程序。
我们都知道,异步调用,其实就是多线程。然后再callback中处理返回的数据。
这时候,就会发现不能try。。。catch。。。了。因为调用成功,还是失败,是在方法完成的委托函数中才知道的。没有地方给你写try。。。catch。。。了。
Service1.Service1Client client =
new Service1.Service1Client(); client.GetUserByIDCompleted +=
new EventHandler<Service1.GetUserByIDCompletedEventArgs>(client_GetUserByIDCompleted); client.GetUserByIDAsync(
int.Parse(textBox1.Text.Trim()), "
123456");
void client_GetUserByIDCompleted(
object sender, Service1.GetUserByIDCompletedEventArgs e) { }
是通过e来获取数据的。
但是异常信息需要通过通道传递的客户端,这点和同步调用是一样的。既然这样,那我们在定义服务端方法的时候,就添加一个out类型的参数,在服务端就将CallException这个实体赋值给这个参数。然后通过e.CallException就可以获取异常信息了,如果不为空,说明有异常存在。为空,说明没有异常,访问正常。
- void client_GetUserByIDCompleted(object sender, Service1.GetUserByIDCompletedEventArgs e)
- {
-
- #region
-
- if (e.callException != null)
- {
- ChildWindow win = new ChildWindow();
- win.Title = e.callException.Message;
- win.Content = e.callException.Detail;
- win.MinHeight = 50;
- win.MinWidth = 200;
- win.Show();
- }
- else
- {
- ChildWindow win = new ChildWindow();
- win.Title = "ok";
- win.Content = "it is ok";
- win.MinHeight = 50;
- win.MinWidth = 200;
- win.Show();
- }
- #endregion
-
- }
3 结论
不知道大家在捕获和处理WCF的异常的时候,是如何处理的?有更好的办法,欢迎大家一起讨论。
源码下载:
Technorati 标签: WCF, FaultContract(typeof(CallException))