zoukankan      html  css  js  c++  java
  • wcf服务编程(第3版)文摘

    第1章 wcf基础

    什么是wcf: System.ServiceModel.dll

    服务 服务的执行边界: proxy

    地址:http/https,tcp,ipc,peer newwork,msmq,service bus(服务总线地址)

    契约:服务契约,(类虽然可以使用内部的属性,索引器,静态成员,但WCF客户端却无法访问)

    数据契约,错误契约,消息契约(不是WCF 的常见情况)

    托管:iis托管只能使用http协议

    was托管:(window激活服务)

    wsa扩展程序(window server appfabric):主要面向的事wf服务

    选择宿主:p21,22(互联网,局域网)

    绑定:基本绑定,TCP绑定,IPC绑定,WEB服务绑定,MSMQ绑定

    选择绑定:p24

    终结点

    元数据的交换:1.基于http-get的元数据,2.元数据交换终结点

    客户端编程:生成代理

    WCF体系结构: 不使用代理类,使用通道直接调用服务ChannelFactory

    第2章 服务契约

    操作重载:不同的name区分操作

    契约继承

    服务契约分解与设计:服务契约的最佳数量3-5个

    第3章 数据契约

    net格式器:1.BinaryFormatter 2.SoapFormatter

    wcf格式器:DataContrct

    第4章 实例管理

    单调服务:percall 客户端持有一个代理的引用,不是实际的对象 (sessionmode.notallowed)

    会话服务:persession (sessionmode.required)

    单例服务:single 全局日志

    限流

    第5章 操作

    请求应答操作,默认的操作模式

    单向操作,没有返回值

    回调操作(双向操作)

    第6章 错误契约

    错误契约,客户端捕捉

    第7章 事务

    第8章 并发管理

    第9章 队列服务

    第10章 安全

    第11章 服务总线

    中继服务

    ----------------------------------------------------------------------

    WCF编码规范

    一个全面完整的编码规范是成功交付产品的根本。规范有助于推行最佳实践以及避免缺陷,可以让团队成员更容易分享知识与技能。传统的编码规范是一本浩如烟海一般的高文大册,厚达数百页,详尽了每个指南的基本原理。制定这样的规范固然是有胜于无,然而,如此努力却很难被大多数开发者所接受。比较而言,本书介绍的WCF编码规范却只有薄薄的几篇,主要介绍了WCF编码细节、编码内容以及设计目的。我相信,若要充分理解各种编程决策,可能需要阅读大量书籍,积累数年的经验,然而如果要实施编码规范则不必如此。当吸收一名新兵加入你的团队时,你可以交给他这份规范,告诉他:“先看看这个。”若要完全理解以及认识到范围的价值,或许需要时间与经验,然而,如果只是需要在此之前就能够遵循规范的约定,却是一蹴而就的事情。编码规范详细介绍了编码要求、缺陷、指南以及建议。编码规范同时还使用了本书介绍最佳实践以及辅助类。

    通用设计指南

    1. 所有的服务必须遵循以下原则:
      1. 服务是安全的。
      2. 服务操作在系统中应该保持状态一致。
      3. 服务是线程安全的,且可以被并发客户端访问。
      4. 服务是可靠的。
      5. 服务是健壮的。
    2. 服务应该遵循以下可选原则:
      1. 服务是可互操作的。
      2. 服务的规模是不变的。
      3. 服务是可用的。
      4. 服务是及时响应的。
      5. 服务是受限的,阻塞客户端的时间不能过长。

    WCF基础

    1. 应该将服务代码放入到类库中,而不是放到宿主EXE中。
    2. 不要为服务类提供参数构造函数,除非托管的服务是明确的单例服务。
    3. 在相关的绑定中启用可靠性。
    4. 要为契约提供有意义的命名空间。对于公开向外的服务,可以使用公司的URL或者等同的URN,然后加上年份和月份以避免版本冲突;例如:

    [ServiceContract(Namespace = "http://www.idesign.net/2009/06")]

    interface IMyContract

    {...}

    对于局域网服务,可以使用任何有意义的唯一的名称,如MyApplication;例如:

    [ServiceContract(Namespace = "MyApplication")]

    interface IMyContract

    {...}

    1. 对于运行在Windows XP以及Windows Server 2003 上的局域网应用程序,最好选用自托管,而不是IIS托管。
    2. 在Windows Vista和Windows Server 2008或更近版本中,最好选用WAS (IIS7)托管,而不是自托管。
    3. 启用元数据交换。
    4. 要为客户端配置文件中的所有终结点命名。
    5. 不要使用SvcUtil或者Visual Studio2008生成配置文件。
    6. 不要复制代理的代码。如果两个或多个客户端使用相同契约,可以将代理分解到单独的类库中。
    7. 总是关闭或释放代理。

    服务契约

    1. 总是将ServiceContract特性应用到接口上,而不是类上:

    //避免

    [ServiceContract]

    class MyService

    {

         [OperationContract]

         public void MyMethod()

    {...}

    }

    //正确

    [ServiceContract]

    interface IMyContract

    {

         [OperationContract]

         void MyMethod();

    }

    class MyService : IMyContract

    {

         public void MyMethod()

    {...}

    }

    1. 服务契约要添加前缀I:

    [ServiceContract]

    interface IMyContract

    {

         [OperationContract]

         void MyMethod();

    }

    1. 要避免准属性(Property-Like)操作:

    //避免

    [ServiceContract]

    interface IMyContract

    {

         [OperationContract]

         string GetName();

     

    [OperationContract]

         void SetName(string name);

    }

    1. 避免定义只有一个成员的契约。
    2. 每个服务契约最好只定义3~5个成员。
    3. 每个服务契约的成员不要超过20个。12个是可能的实际限定。

    数据契约

    1. 避免推断式数据契约(POCO)。总是显式地应用DataContract特性。
    2. 只在属性或只读公有成员上使用Datamember特性。
    3. 避免为定制类型显式地执行XML序列化。
    4. 避免使用消息契约。
    5. 当使用DataMemberAttribute特性的Order属性时,应该为同一类层级的所有成员分配相同的值。
    6. 数据契约应实现IExtensibleDataObject接口。使用显式接口实现。
    7. 避免在ServiceBehavior和CallbackBehavior特性上设置IgnoreExtensionDataObject。应保持它的默认值为false。
    8. 不要将委托和事件标记为数据成员。
      1. 不要将.NET的特殊类型例如Type作为操作的参数。
      2. 不要在操作中接受或返回ADO.NET的DataSet类型和DataTable类型(或者它们的类型安全子类)。应该返回一个与技术无关的表示形式,例如数组。
      3. 禁止为泛型的类型参数生成散列值,而应该提供易懂的类型名。

    实例管理

    1. 考虑系统的可伸缩性时,最好使用单调实例模式。
    2. 如果契约设置为SessionMode.NoAllowed,则总是将服务实例配置为InstanceContextMode.PerCall。
    3. 不要在相同的服务上混合使用会话契约与无会话契约。
    4. 避免使用单例服务,除非该服务本质上就是单例的。
    5. 要为会话服务使用有序递送。
    6. 避免为会话服务停止实例。
    7. 避免使用分步操作。
    8. 对于持久服务,总是指定完成操作。

    操作与调用

    1. 不要将单向调用设置为异步调用。
    2. 不要将单向调用设置为并发调用。
    3. 对单向操作抛出的异常做出预期。
    4. 为单向调用启用可靠性。对于单向调用而言,使用有序传递属于可选项。
    5. 避免在会话服务中定义单向操作。如果定义了,则应将它定义为终止操作:

    [ServiceContract(SessionMode = SessionMode.Required)]

    interface IMyContract

    {

         [OperationContract]

    void MyMethod1();

     

    [OperationContract(IsOneWay = true, IsInitiating = false, IsTerminating = true)]

    void MyMethod2();

    }

    1. 为服务端的回调契约取名时,应使用服务契约名加上Callback后缀:

    interface IMyContractCallback

    {...}

    [ServiceContract(CallbackContract = typeof(IMyContractCallback))]

    interface IMyContract

    {...}

    1. 尽量将回调操作标记为单向。
    2. 只为回调使用回调契约。
    3. 避免在相同的回调契约中将常规的回调与事件混为一谈
    4. 事件操作的设计应遵循如下规范:
      1. void返回类型
      2. 没有out参数
      3. 标记为单向操作
    5. 避免在事件管理中使用原来的回调契约,而应该使用发布-订阅框架
    6. 避免为回调显式地定义创建(Setup)方法和销毁(Teardown)方法:

    [ServiceContract(CallbackContract = typeof(IMyContractCallback))]

    Interface IMyContract

    {

    [OperationContract]

    void DoSomething();

     

    [OperationContract]

    Void Connect();

     

    [OperationContract]

    void Disconnect();

    }

    Interface IMyContractCallback

    {...}

    1. 使用类型安全的DuplexClientBase<T,C>,而不是DuplexClientBase<T>。
    2. 使用类型安全的DuplexChannelFactory<T,C>,而不是DuplexChannelFactory<T>。
    3. 调试或在局域网部署基于WSDualHttpBinding绑定的回调时,应该使用CallbackBaseAddressBehavior特性,并将CallbackPort设置为0:

    [CallbackBaseAddressBehavior(CallbackPort = 0)]

    Class MyClient:IMyContractCallback

    {...}

    错误

    1. 永远都不要在异常抛出之后使用代理实例,即使你捕获了该异常。
    2. 避免错误契约,并允许WCF屏蔽错误。
    3. 在异常抛出之后不要重用回调通道,即使你捕获了该异常,因为通道可能已经发生了错误。
    4. FaultContract特性中包含的类型应该是异常类类型,而不是单纯的可序列化类型:

    //避免

    [OperationContract]

    [FaultContract(typeof(double))]

    Double Divide(double number1,double number2);

     

    //正确:

    [OperationContract]

    [FaultContract(typeof(DivideByZeroException))]

    double Divide(double number1, double number2);

    1. 避免耗时过长的处理,例如IErrorHandler.ProvideFault()方法中的日志操作。
    2. 测试状态下,服务类与回调类的IncludeExceptionDetailInFaults值均应设置为true,可以在配置文件中配置,也可以采用编程方式:

    public class DebugHelper

        {

            public const bool IncludeExceptionDetailInFaults =

            #if DEBUG

                true;

            #else

                false;

            #endif

        }

        [ServiceBehavior(IncludeExceptionDetailInFaults =

        DebugHelper.IncludeExceptionDetailInFaults)]

    class MyService : IMyContract

    {...}

    1. 构建交付版本时,除了诊断场景,不要将未知异常作为错误返回。
    2. 如果要提升异常为错误契约,并实现自动地错误日志记录,可以考虑在服务上使用ErrorHandlerBehavior特性:

    [ErrorHandlerBehavior]

    class MyService : IMyContract

    {...}

    1. 如果要提升异常为错误契约,并实现自动地错误日志记录,可以考虑在回调客户端上使用CallbackErrorHandlerBehaviorAttribute特性:

    [CallbackErrorHandlerBehaviorAttribute]

    class MyClient : IMyContractCallback

    {

         public void OnCallback()

         {...}

    }

    事务

    1. 永远不要直接使用ADO.NET事务。
    2. 要将TransactionFlow特性应用在契约上,而不是服务类上。
    3. 不要再服务构造函数中执行事务型工作。
    4. 如果使用本书术语,服务应该被配置为Client事务或Client/Service事务。避免使用None事务或Service事务。
    5. 如果使用本书术语,回调应该被配置为Service事务或Service/Client事务。避免使用None事物或Callback事物。
    6. 使用Client/Service或Service/Callback模式时,应该使用BindingzRequirement特性约束绑定使用事务流。
    7. 如果服务被配置为None事务或Service事务,则客户端总是会捕获它所抛出来的异常。
    8. 在使用事务时,允许可靠性和有序传递。
    9. 在服务操作中,永远不要捕获一个异常,并手动取消事务。

    //避免

    [OperationBehavior(TransactionScopeRequired = true)]

    public void MyMethod()

    {

    try

    {

    ...

    }

    catch

    {

    rtansaction.Current.Rollback();

    }

    }

    1. 如果在事务型操作中捕获了一个异常,那么总是要重新抛出它,或者抛出其它异常。
    2. 保证事务尽可能短。
    3. 总是使用默认的隔离级别IsolationLevel.Serializable。
    4. 不要调用事务中的单向操作。
    5. 不要调用事务中的非事务型服务。
    6. 不要访问事务中的非事务型资源(例如文件系统)。
    7. 对于会话服务,避免在会话关闭时通过自动完成将会话边界与事务边界等同对待。
    8. 尽量使用TransationalBehavior特性管理会话服务的事务。

    [Serializable]

    [TransationalBehavior]

    class MyService :IMyContrant

    {

    public void MyMethod()

       {...}

    }

    1. 使用一个会话服务后事务型的单例服务时,应使用易失性资源管理器管理状态,同事避免显示的状态相关的编程,或者在完成时依赖WCF停止实例。
    2. 对于事务性持久服务,总是将SaveStateInOperationTransaction设置为true,从而将事务传播给持久存储。

    并发管理

    1. 总是线程安全访问如下内容:
      1. 会话服务或单例服务的内存状态
      2. 回调期间的客户端内存状态
      3. 共享资源
      4. 静态变量
      5. 建议选用ConcurrencyMode.Single(默认值)。它能够启用事务型访问,并提供线程安全的。
      6. 在ConcurrencyMode.Single模式下,保证会话服务和单例服务的操作耗时短,这是为了避免过长时间地堵塞其他客户端。
      7. 使用ConcurrencyMode.Multiple时,必须使用自动完成事务。
      8. 考虑为单调服务使用ConcurrencyMode.Multiple,从而允许并发调用。
      9. 配置为ConcurrencyMode.Multiple的事务型单例服务,则必须将ReleaseServiceInstanceOnTransactionComplete设置为false:

    [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single,

    ConcurrencyMode = ConcurrencyMode.Multiple,

    ReleaseServiceInstanceOnTransactionComplete = false)]

    class MySingleton : IMyContract

    {...}

    1. 永远不要在UI线程上实现自托管,也不要通过UI应用程序调用服务。
    2. 永远不要执行到达调用服务的UI应用程序的回调,除非回调使用SynchronizationContext.Post()方法传递调用。
    3. 为同步方法和异步方法提供代理时,只能将FaultContractAttribute特性应用到同步方法上。
    4. 保证异步操作尽可能短。不要将异步操作与长时间操作混为一谈。
    5. 不要混合使用事务与异步调用

    队列服务

    1. 在客户端,总是调用队列服务之前验证队列(如果可能则验证死信队列)是否可用。可以使用QueuedServiceHelper.VerifyQueue()方法进行验证。
    2. 在运行一个队列服务(通过ServiceHost<T>自动执行)时,总是要验证队列是否可用。
    3. 除了是在隔离场景中,要避免设计相同的服务同时工作在队列和非队列中。
    4. 服务应该参与回放事务。
    5. 参与回放事务时,要避免在队列服务中执行耗时过长的处理。
    6. 避免会话队列服务。
    7. 使用一个单例队列服务时,应使用易失性资源管理器管理单例状态。
    8. 使用一个单调队列服务时,要显式地将契约和服务配置为单调模式以及无会话状态:

    [ServiceConstract(SessionMode = SessionMode.NotAllowed)]

    interface IMyContract

    {...}

     

    [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]

    class MyService : IMyContract

    {...}

    1. 总是将单例队列服务的契约显式地设置为禁止会话:

    [ServiceConstract(SessionMode = SessionMode.NotAllowed)]

    interface IMyContract

    {...}

       

    [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]

    class MyService : IMyContract

    {...}

    1. 客户端应该在事务内调用一个队列服务。
    2. 在客户端,不要将队列服务代理储存在成员变量中。
    3. 避免将TimeToLive的值设置为相对较短的值,因为他们会抵消使用队列服务的价值。
    4. 避免非事务队列。
    5. 使用响应队列时,要让服务参与到回放事务中,并在事务中将响应放入队列。
    6. 要让响应服务参与到响应回放事务中。
    7. 避免在一个队列响应操作中执行耗时过长的处理。
    8. 对于MSMQ3.0 建议使用一个响应服务,而不是有害队列服务去处理服务自身的重复错误。
    9. 对于 MSMQ4.0 应对有害消息使用ReceiveErrorHandling.Reject, 除非通过ReceiveErrorHandling.Move 进行高级处理。应避免ReceiveErrorHandling.Fault和ReceiveErrorHandling.Drop。
    10. 对于 MSMQ4.0 考虑使用响应服务来处理服务回放失败。
    11. 除非是处理一个会话契约与会话服务,否则永远不要假定队列调用的顺序。

    安全

    1. 总是要保护消息,提供消息证书与完整性。
    2. 在局域网中,只要保护级别被设置为EncryptAndSign,就可以使用传输安全。
    3. 在局域网中要避免使用模拟。应将模拟级别设置为TokenImpersonationLevel.Identification.
    4. 当使用模拟时,客户端应使用TokenImpersonaltionLevel.ImPersonation。
    5. 应使用声明性安全框架,避免手动配置。
    6. 永远不要将PrincipalPermission特性直接应用到服务类上:

    //总是会失败

    [PrincipalPermisson (SecurityAction.Demand,Role = “…”) ]

    public calss MyService : IMyContract

    {...}

    1. 避免在服务构造函数中使用需要授权的敏感工作。
    2. 不管是否要求角色,都应该避免强制要求一个特定的用户:

    //避免

    [[PrincipalPermisson (SecurityAction.Demand,Role =”John”) ]

    public void MyService : IMyMethod

    {...}

    1. 在客户端的回调操作中不要依赖于基于角色的安全机制。
    2. 对于互联网客户端,总是要使用消息安全。
    3. 允许客户端与服务证书进行协商(默认)。
    4. 使用ASP.NET的Provider定制证书。
    5. 开发一个定制证书存储时,应将它开发为ASP.NET Provider.
    6. 在使用端点信任( Peer Trust )时要验证证书。
    7. 尽量将客户端运行在部分信任之下。只能将客户端许可授予:
      1. 执行
      2. 显示用户界面
      3. 连接服务
      4. 获得本地凭据
    8. 在获得服务宿主环境时,在完全信任下运行和托管。将Microsoft和ECMA授予完全信任,但要移除其他的代码组,并将他们授予无许可权。
    9. 在部分信任下托管,只能将宿主和服务许可授予为:
      1. 执行
      2. 接受客户端调用
      3. 获得本地凭据
      4. 认证和授权客户端
      5. 如果需要获得本地资源

     

     

  • 相关阅读:
    Haproxy 【转载】
    Nginx介绍
    Day 13 进程和线程
    运维第一课
    面试bb
    Day 12 字符串和正则表达式
    Day 11 文件和异常
    Day10 图形用户界面和游戏开发
    Day9 面向对象进阶
    day8 面向对象编程基础
  • 原文地址:https://www.cnblogs.com/smileberry/p/3539019.html
Copyright © 2011-2022 走看看