【微软技术栈】实现EAP的最佳做法

2023-11-29 10:28

本文主要是介绍【微软技术栈】实现EAP的最佳做法,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

本文内容

  1. 必需的行为保证
  2. 指南

基于事件的异步模式提供了一种在类中使用熟悉的事件和委托语义公开异步行为的有效方法。 若要实现基于事件的异步模式,你需要遵循某些特定的行为要求。 以下部分描述了在你实现遵循基于事件的异步模式的类时应该考虑的要求和准则。

1、必需的行为保证

若要实现基于事件的异步模式,你必须提供一些保证来确保类的行为正确且类的客户端能够依赖这种行为。

1.1 Completion

操作成功完成、出错或取消时,始终应调用 MethodNameCompleted 事件处理程序。 任何情况下,应用程序都不应遇到这样的情况:应用程序保持空闲状态,而操作却一直不能完成。 此规则的例外情况是:异步操作本身设计为永不完成。

1.2 已完成的事件和 EventArgs

针对每个单独的 MethodNameAsync 方法,请应用以下设计要求:

  • 在与该方法相同的类上定义 MethodNameCompleted 事件。

  • 为派生自 AsyncCompletedEventArgs 类的 MethodNameCompleted 事件定义一个 EventArgs 类和随附委托。 默认类名应采用 MethodNameCompletedEventArgs 形式。

  • 确保 EventArgs 类特定于 EventArgs 方法的返回值。 在使用 EventArgs 类时,切勿要求开发人员强制转换结果。

    下面的代码示例分别演示了此项设计要求的合理实现和错误实现。

// Good design
private void Form1_MethodNameCompleted(object sender, xxxCompletedEventArgs e)
{DemoType result = e.Result;
}// Bad design
private void Form1_MethodNameCompleted(object sender, MethodNameCompletedEventArgs e)
{DemoType result = (DemoType)(e.Result);
}
  • 不要为返回 EventArgs 的返回方法定义 void 类。 而应使用 AsyncCompletedEventArgs 类的实例。

  • 应务必始终抛出 MethodNameCompleted 事件。 成功完成、出错或者取消时应引发此事件。 任何情况下,应用程序都不应遇到这样的情况:应用程序保持空闲状态,而操作却一直不能完成。

  • 确保可以捕获异步操作中发生的任何异常并将捕获的异常分配给 Error 属性。

  • 如果完成任务时出现错误,其结果应当不可访问。 当 Error 属性不为 null 时,确保访问 EventArgs 结构中的任何属性都会引发异常。 使用 RaiseExceptionIfNecessary 方法来执行此验证。

  • 将超时建模为错误。 如果发生超时,应抛出 MethodNameCompleted 事件,并将 TimeoutException 分配给 Error 属性。

  • 如果类支持多个并发调用,应确保 MethodNameCompleted 事件包含相应的 userSuppliedState 对象。

  • 应确保在应用生命周期中适时对相应线程抛出 MethodNameCompleted 事件。 有关更多信息,请参见“线程处理和上下文”部分。

1.3 同时执行操作

  • 如果类支持多个并发调用,应让开发人员可以单独跟踪各个调用,具体操作是定义 MethodNameAsync 重载,此重载需要使用对象赋值状态参数或任务 ID(名为 userSuppliedState)。 此参数应始终是 MethodNameAsync 方法签名中的最后一个参数。

  • 如果类定义了需要使用对象赋值状态参数或任务 ID 的 MethodNameAsync 重载,应务必使用相应任务 ID 跟踪操作的生存期,并将它 返回给完成事件处理器。 有一些用来提供帮助的帮助器类。

  • 如果类定义了不使用状态参数的 MethodNameAsync 方法,且它不支持多个并发调用,则应确保在先前 MethodNameAsync 调用完成前,只要尝试调用 MethodNameAsync 都会导致 InvalidOperationException 抛出。

  • 一般来说,如果多次调用不使用 userSuppliedState 参数的 MethodNameAsync 方法,导致多个未结操作出现,不得抛出异常。 如果类无法显式处理这种情况,将引发异常,但可假定开发人员能够处理多个不可区分回调。

1.4 访问结果

  • 如果在执行异步操作期间出现错误,其结果应当不可访问。 确保在 AsyncCompletedEventArgs 不为 Error 时访问 null 中的任何属性都会引发由 Error 引用的异常。 AsyncCompletedEventArgs 类为达到此目的提供了 RaiseExceptionIfNecessary 方法。

  • 确保访问结果的任何尝试都将引发 InvalidOperationException,指出该操作已被取消。 使用 AsyncCompletedEventArgs.RaiseExceptionIfNecessary 方法来执行此验证。

1.5 进度报告

  • 如有可能,支持进度报告。 在开发人员使用你的类时,这使他们能够提供更好的应用程序用户体验。

  • 如果实现 ProgressChanged 或 MethodNameProgressChanged 事件,应确保在抛出特定异步操作的 MethodNameCompleted 事件后,不会对此操作抛出所实现的事件。

  • 如果正在填充标准的 ProgressChangedEventArgs,则请确保始终能够将 ProgressPercentage 解释为一个百分比。 该百分比不必是一个精确值,但它应表示为百分数的形式。 如果你的进度报告指标不能是一个百分比,请从 ProgressChangedEventArgs 类中派生一个类并将 ProgressPercentage 保留为 0。 避免使用非百分比的报告指标。

  • 请确保在应用程序生命周期中的适当时间在适当的线程上引发了 ProgressChanged 事件。 

1.6 IsBusy 实现

  • 如果你的类支持多个并发调用,则不要公开 IsBusy 属性。 例如,XML Web services 代理不会公开 IsBusy 属性,因为它们支持异步方法的多个并发调用。

  • 在调用 MethodNameAsync 方法后,且在抛出 MethodNameCompleted 事件前,IsBusy 属性应返回 true。 否则,它应返回 false。 BackgroundWorker 和 WebClient 组件是公开 IsBusy 属性的类的示例。

1.7 取消

  • 如有可能,支持取消。 在开发人员使用你的类时,这使他们能够提供更好的应用程序用户体验。

  • 在发生取消时,设置 Cancelled 对象中的 AsyncCompletedEventArgs 标志。

  • 确保访问结果的任何尝试都将引发 InvalidOperationException,指出该操作已被取消。 使用 AsyncCompletedEventArgs.RaiseExceptionIfNecessary 方法来执行此验证。

  • 请确保对取消方法发出的调用始终能够成功返回,而且从不引发异常。 一般来说,客户端不会得到关于在任何给定时间是否真正可取消某个操作的通知,也不会得到关于以前发出的取消是否已经成功的通知。 不过,应用程序在取消成功时总能得到通知,因为应用程序参与了完成状态。

  • 取消操作时,应抛出 MethodNameCompleted 事件。

1.8 错误和异常

  • 捕获所有发生在异步操作中的异常并将 AsyncCompletedEventArgs.Error 属性的值设置为该异常。

1.9 线程处理和上下文

为了使类正确运行,应当使用给定应用程序模型(包括 ASP.NET 和 Windows 窗体应用程序)的适当线程或上下文调用客户端事件处理程序,这一点很重要。 我们提供了两个重要的帮助器类,以确保你的异步类在任何应用程序模型中都能正确运行,这两个帮助器类是 AsyncOperation 和 AsyncOperationManager。

AsyncOperationManager 提供了 CreateOperation 方法,该方法会返回一个 AsyncOperation。 MethodNameAsync 方法调用 CreateOperation,且类使用返回的 AsyncOperation 跟踪异步任务的生存期。

若要将进程、增量结果和完成情况报告给客户端,请调用 Post 上的 OperationCompleted 和 AsyncOperation 方法。 AsyncOperation 负责将对客户端事件处理程序的调用封送到合适的线程或上下文。

 备注

如果你明确想违反应用程序模型的策略,但仍想获得使用基于事件的异步模式的其他好处,则你可以避开这些规则。 例如,你可能希望在 Windows 窗体中进行操作的某个类是自由线程类。 只要开发人员了解隐含的限制,你就可以创建自由线程类。 控制台应用程序不会同步 Post 调用的执行。 这会导致按错误的顺序引发 ProgressChanged 事件。 如果希望序列化 Post 调用的执行,请实现并安装 System.Threading.SynchronizationContext 类。

若要详细了解如何使用 AsyncOperation 和 AsyncOperationManager 启用异步操作,请参阅AsyncOperation。

2、指南

  • 理论上,方法调用与方法调用之间应是相互独立的。 你应当避免在使用调用时使用共享资源。 如果要在不同调用之间共享资源,则你需要在你的实现中提供一个适当的同步机制。

  • 建议不要进行需要客户端实现同步的设计。 例如,你可以使用一个异步方法将全局静态对象作为参数来接收;这类方法的多个并发调用可能会导致数据损坏或死锁。

  • 如果你使用多个调用重载(签名中的 userState)实现方法,你的类将需要管理由一系列用户状态、任务 ID 及其相应的挂起操作构成的一个集合。 应当使用 lock 区域保护此集合,因为各种调用都会在此集合中添加和移除 userState 对象。

  • 请考虑在可行且适当的情况下,重新使用 CompletedEventArgs 类。 在这种情况下,命名和方法名不一致,因为给定的委托和 EventArgs 类型并不会与单独某个方法联系在一起。 不过,强制开发人员对从 EventArgs 上的属性检索的值进行强制转换,是绝对不可取的。

  • 如果你正在创建自 Component 派生的类,请不要实现和安装你自己的 SynchronizationContext 类。 所使用的 SynchronizationContext 由应用程序模型而不是组件控制。

  • 当你使用任何形式的多线程时,都有可能会遇到非常严重且复杂的 Bug。 

 

 

这篇关于【微软技术栈】实现EAP的最佳做法的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/432474

相关文章

SpringBoot3实现Gzip压缩优化的技术指南

《SpringBoot3实现Gzip压缩优化的技术指南》随着Web应用的用户量和数据量增加,网络带宽和页面加载速度逐渐成为瓶颈,为了减少数据传输量,提高用户体验,我们可以使用Gzip压缩HTTP响应,... 目录1、简述2、配置2.1 添加依赖2.2 配置 Gzip 压缩3、服务端应用4、前端应用4.1 N

SpringBoot实现数据库读写分离的3种方法小结

《SpringBoot实现数据库读写分离的3种方法小结》为了提高系统的读写性能和可用性,读写分离是一种经典的数据库架构模式,在SpringBoot应用中,有多种方式可以实现数据库读写分离,本文将介绍三... 目录一、数据库读写分离概述二、方案一:基于AbstractRoutingDataSource实现动态

Python FastAPI+Celery+RabbitMQ实现分布式图片水印处理系统

《PythonFastAPI+Celery+RabbitMQ实现分布式图片水印处理系统》这篇文章主要为大家详细介绍了PythonFastAPI如何结合Celery以及RabbitMQ实现简单的分布式... 实现思路FastAPI 服务器Celery 任务队列RabbitMQ 作为消息代理定时任务处理完整

Java枚举类实现Key-Value映射的多种实现方式

《Java枚举类实现Key-Value映射的多种实现方式》在Java开发中,枚举(Enum)是一种特殊的类,本文将详细介绍Java枚举类实现key-value映射的多种方式,有需要的小伙伴可以根据需要... 目录前言一、基础实现方式1.1 为枚举添加属性和构造方法二、http://www.cppcns.co

使用Python实现快速搭建本地HTTP服务器

《使用Python实现快速搭建本地HTTP服务器》:本文主要介绍如何使用Python快速搭建本地HTTP服务器,轻松实现一键HTTP文件共享,同时结合二维码技术,让访问更简单,感兴趣的小伙伴可以了... 目录1. 概述2. 快速搭建 HTTP 文件共享服务2.1 核心思路2.2 代码实现2.3 代码解读3.

MySQL双主搭建+keepalived高可用的实现

《MySQL双主搭建+keepalived高可用的实现》本文主要介绍了MySQL双主搭建+keepalived高可用的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,... 目录一、测试环境准备二、主从搭建1.创建复制用户2.创建复制关系3.开启复制,确认复制是否成功4.同

Java实现文件图片的预览和下载功能

《Java实现文件图片的预览和下载功能》这篇文章主要为大家详细介绍了如何使用Java实现文件图片的预览和下载功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... Java实现文件(图片)的预览和下载 @ApiOperation("访问文件") @GetMapping("

Spring Boot 配置文件之类型、加载顺序与最佳实践记录

《SpringBoot配置文件之类型、加载顺序与最佳实践记录》SpringBoot的配置文件是灵活且强大的工具,通过合理的配置管理,可以让应用开发和部署更加高效,无论是简单的属性配置,还是复杂... 目录Spring Boot 配置文件详解一、Spring Boot 配置文件类型1.1 applicatio

使用Sentinel自定义返回和实现区分来源方式

《使用Sentinel自定义返回和实现区分来源方式》:本文主要介绍使用Sentinel自定义返回和实现区分来源方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Sentinel自定义返回和实现区分来源1. 自定义错误返回2. 实现区分来源总结Sentinel自定

Java实现时间与字符串互相转换详解

《Java实现时间与字符串互相转换详解》这篇文章主要为大家详细介绍了Java中实现时间与字符串互相转换的相关方法,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录一、日期格式化为字符串(一)使用预定义格式(二)自定义格式二、字符串解析为日期(一)解析ISO格式字符串(二)解析自定义