[WCF编程]11.错误:错误类型
一、错误概述
不管是哪一种操作,在任意时刻都可能出现不可预期的错误。问题在于我们应该如何将错误报告给客户端。异常和异常处理机制是与特定技术紧密结合的,不能跨越边界的。此外,如果有客户端来处理错误,必定会导致耦合度增加。通常,错误处理应该是本地的实现细节,并不会影响到客户端。在设计良好的应用程序中,服务应该是被封装的,客户端无法知道有关错误的消息。设计良好的服务应尽可能是自治的,不能依赖客户端去处理或恢复错误。任何非空的错误通知都应该是客户端与服务端之间契约交互的一部分。
二、错误隔离和解耦
WCF中错误的表现。当代表某个客户端的服务调用导致异常时,并不会借宿宿主进程,其它客户端仍然可以访问该服务。托管在相同进程中的其它服务也不会受到影响。所以,当一个未经处理的异常离开服务范围时,分发器会捕获它,并将它序列化到返回消息中传递给客户端。当返回消息到达代理时,代理会在客户端抛出一个异常。这一方式为每个WCF服务提供了进程级的隔离。客户端与服务端能够共享一个进程,但对于错误的处理却完全是独立的。唯一的例外是能够导致.NET崩溃的关键错误,如堆栈溢出,才会影响到宿主进程。
错误隔离是WCF的三个关键错误解耦特性之一。第二个是错误屏蔽,第三个是通道故障。
三、错误屏蔽
当客户端试图调用服务时,实际上可能会遭遇三种错误类型。
第一种错误类型是通信错误。如网络故障,地址错误,宿主进程没运行等等。客户端的通信错误表现为CommunicationException异常或其子类异常,如EndpointNotFoundException。
第二种错误类型与代理和通道的状态有关。这种类型存在很多可能的异常。如,试图访问已经关闭的代理,就会导致ObjectDisposedException异常;契约和绑定的安全级别不想匹配时,就会导致InvalidOperationException异常等等
第三种错误类型源于服务调用。这种错误节能是服务抛出异常,也可能是服务在调用其它对象或资源通过内部调用抛出的异常。
客户端所关注的就是错误发生了,对于大多数客户端而言,最佳实践就是简单地让异常在调用链中向上传递。最顶端的客户端会捕获异常,但并不是为了处理,而仅仅是为了不让程序突然关闭。
设计良好的客户端应该永远都不考虑实际的错误,WCF对此进行了强制要求。出于对封装和解耦的考虑,在默认情况下,所有的服务抛出的异常总是以FaultException类型到达客户端。
[...]
public class FaultException : CommunicationException
{...}如果要解耦客户端与服务,就应该对所有的服务异常一视同仁。客户端对服务端直到的越少,则两者之间关系的解耦才越彻底。
四、通道故障
在传统的.NET编程中,客户端可以捕获异常,并继续调用对象。这样的类和接口可以定义为:
interface IMyContract
{
void MyMethod();
}
class MyClass : IMyContract
{...}问题是客户端捕获了对象抛出的异常后,它还是可以被再次调用:
IMyContract obj = new MyClass();
try
{
obj.MyMethod();
}
catch
{}
obj.MyMethod();这是.NET平台的一个重要缺陷。客户端怎么可以知道可能抛出异常,仍然会使用它呢。
在经典的.NET编程模型中,开发人员必须在每个对象中委会一个标志:在抛出异常之前或在抛出异常之后设置该标志,然后在公开方法内检查该标志,如果对象是在抛出异常之后被调用,则拒绝使用该对象。当然,这很繁琐而且乏味。
WCF自动实现了这一最佳实践。如果服务具有传输会话,则任何未经处理的异常(保存在继承子FaultException类中)都会导致通道发生错误(代理的状态就会被修改为CommunicationState.Faulted),这样就避免了客户端使用该代理,而对象也可以隐藏在异常之后。换句话说,对于如下的服务和代理的定义,最直接的解决方案就是客户端不要在抛出异常之后使用WCF代理。如果具有传输会话,客户端甚至不能关闭代理。
在抛出异常之后,客户端唯一可以安全执行的就是取消代理,或者防止其它的客户端使用代理:
MyContractClient proxy = new MyContractClient();
try
{
proxy.MyMethod();
}
catch
{
proxy.Abort();
}现在的问题是,对于每个方法调用,你都必须重复这些代码。最好能把这些代码封装在代理类中。
class MyContractClient : ClientBase<IMyContract>,IMyContract
{
public void MyMethod()
{
try
{
Channel.MyMethod();
}
Catch
{
Abort();
throw;
}
}
}关闭代理和using语句
这里反对使用using语句关闭代理。其原因在于,如果存在传输会话,则任何服务端的异常都会导致通道故障。一旦通道出现故障,试图释放代理就会抛出CommunicationObjectFaultException异常,因此,在using语句之后的代码永远不会调用,在using语句内捕获了所有异常也是如此。
using(MyContrctClient proxy = new MyContractClient())
{
try
{
proxy.MyMethod();
}
catch
{}
}这就降低了代码的可读性,并可能导致BUG,因为代码的执行结果并非开发人员所期望的那样。唯一的解决之道使用try/catch语句将using语句包裹起来:
try
{
using(MyContrctClient proxy = new MyContractClient())
{
try
{
proxy.MyMethod();
}
catch
{}
}
}
catch
{}当然这比Close()方法要好得多。出现异常时,异常会跳出对Close()的调用:
MyContrctClient proxy = new MyContractClient()
proxy.MyMethod();
proxy.Close();当然,你也可以捕获异常,这样的代码具有可读性:
MyContrctClient proxy = new MyContractClient()
try
{
proxy.MyMethod();
proxy.Close();
}
catch
{
proxy.Abort();
}异常和实例管理
如果服务被配置为单调模式或会话模式,则客户端异常就不会访问同一个实例。当然,这本身就是单调服务的特点。对于会话服务,则是通道出现故障,终止了传送会话所造成的后果。单例服务并不会被终止,而会继续运行。如果没有传输会话,客户端会继续使用代理连接单例对象。通道出现故障,客户端还是能够创建一个新的代理实例,重新连接单例服务。
参考:《WCF服务编程 第三版》
[WCF编程]11.错误:错误类型的更多相关文章
- [WCF编程]11.错误:错误契约
一.错误传播 服务需要向客户端报告特定错误,当WCF默认的错误屏蔽方法并不包含这一实现.另一个重要的问题与传播到客户端有关,即由于异常是针对特定技术的,因此无法跨越服务边界而被共享.要实现无缝的互操作 ...
- Windows核心编程第一章.错误处理
Windows核心编程第一章,错误处理. 一丶错误处理 1.核心编程学习总结 不管是做逆向,开始做开发.在Windows下.你都需要看一下核心编程这本书.这本书确实写得很好.所以自己在学习这本书的同时 ...
- 分析器错误消息: 类型“test.test.testx”不明确: 它可能来自程序集“F:\testProject\bin\test.test.DLL”或程序集“F:\testProject\bin \testProject.DLL”。请在类型名称中显式指定程序集。
问题描述: RT 分析器错误消息: 类型“test.test.testx”不明确: 它可能来自程序集“F:\testProject\bin\test.test.DLL”或程序集“F:\testProj ...
- 错误提示:类型“GridView”的控件“GridView1”必须放在具有 runat=server 的窗体标记内 .
错误提示:类型“GridView”的控件“GridView1”必须放在具有 runat=server 的窗体标记内 在做导出数据到EXCEL程序中,出现了错误提示:类型“GridView”的控件“Gr ...
- [转载]WCF 几种常见错误
WCF标准的配置文件为: <system.serviceModel> <services> <service name=" ...
- 在 root 下执行 Oracle 程序时找不到 libclntsh.so.11.1 错误的解决办法。
在 root 下执行 Oracle 程序时找不到 libclntsh.so.11.1 错误的解决办法. 先确定 libclntsh.so.11.1 所在目录: [oracle@localhost ~] ...
- WCF分布式开发常见错误解决(1):An error occurred while attempting to find services at...添加服务引用出错
WCF分布式开发常见错误解决(1):An error occurred while attempting to find services at...添加服务引用出错 当我们在客户端添 ...
- 2015/9/10 Python基础(11):错误和异常
程序在执行的过程中会产生异常,出现错误在以前的一个时期是致命的,后来随着程序的发展,使得一些错误的处理方式是柔和的,发生错误会产生一些错误的诊断信息和一些模糊的提示.帮助我们来处理异常.今天将学习Py ...
- 程序员之---C语言细节24(段错误、类型提升、sizeof 'A')
主要内容:段错误.类型提升.sizeof 'A' #include <stdio.h> int main() { union test{ char a[10]; int b; }u; i ...
随机推荐
- [ASP.NET MVC 小牛之路]11 - Filter
Filter(筛选器)是基于AOP(面向方面编程)的设计,它的作用是对MVC框架处理客户端请求注入额外的逻辑,以非常简单优美的方式实现横切关注点(Cross-cutting Concerns).横切关 ...
- ORM小练习代码
DOG类 namespace RupengORM { public class Dog { public Dog() { } /// <summary> /// 显示提供无参构造函数 // ...
- 启用WebApi 2里的Api描述信息(Help下的Description)
环境:vs2013+web api 2 问题:默认情况下新建的Web Api 2项目,自带的Help页下会显示Api的相关信息,但Description那一栏无法获取到数据,如下图所示: 解决: 1. ...
- JavaScript Json对象和Json对象字符串的关系 jsonObj<->JsonString
JavaScript Json对象和Json对象字符串的关系 jsonObj<->JsonString 如下示例: 直接写的a1就是一个Json对象,a2 就是一个Json对象字符串; 通 ...
- C语言static
1. static 变量 静态变量的类型说明符是static. 静态变量当然是属于静态存储方式,但是属于静态存储方式的量不一定就是静态变量. 例如外部变量虽属于静态存储方式,但不一定是静态变量,必须由 ...
- 数据访问模式:Identity Map(标识映射)模式
1.Identity Map模式简介 Identity Map(标识映射)模式是通过将所有已加载对象放在一个映射中确保所有对象只被加载一次,并且在引用这些对象时使用该映射来查找对象.在处理数据并发访问 ...
- Polynomial Library in OpenCascade
Polynomial Library in OpenCascade eryar@163.com 摘要Abstract:分析幂基曲线即多项式曲线在OpenCascade中的计算方法,以及利用OpenSc ...
- 深入理解javascript对象系列第一篇——初识对象
× 目录 [1]定义 [2]创建 [3]组成[4]引用[5]方法 前面的话 javascript中的难点是函数.对象和继承,前面已经介绍过函数系列.从本系列开始介绍对象部分,本文是该系列的第一篇——初 ...
- 【开源】OSharp3.3框架解说系列:重新开源及3.3版本新特性
OSharp是什么? OSharp是个快速开发框架,但不是一个大而全的包罗万象的框架,严格的说,OSharp中什么都没有实现.与其他大而全的框架最大的不同点,就是OSharp只做抽象封装,不做实现.依 ...
- SQL Server-数据库架构和对象、定义数据完整性(二)
前言 本节我们继续SQL之旅,本节我们如题来讲讲一些基本知识以及需要注意的地方,若有不妥之处,还望指出,简短的内容,深入的理解,Always to review the basics. 数据库架构和对 ...