学习完本章,你将掌握:
1.了解要把你的工作流暴露为XML Web服务来使用的话,各个工作流活动该怎样进行设计
2.了解在ASP.NET中宿主工作流需要些什么
3.看看在基于XML Web服务的工作流中如何进行错误(fault)处理
4.针对各种情况对你的基于XML Web服务的工作流进行配置
在前一章“在你的工作流中调用Web服务”中,你看到了如何从你客户端一侧的工作流中使用WF所提供的InvokeWebService活动来调用XML Web服务。但是,在那章的应用程序范例中的XML Web服务是一个典型的ASP.NET的XML Web服务——没有什么特别的。
在这最后一章中,你将学会怎样对工作流进行处理并自动地把工作流暴露为XML Web服务以让客户去使用。这并不像创建一个工作流程序集库然后从一个Web服务项目中引用它那样简单,但是话又说回来,一旦你理解了一些基本概念并在一个应用程序范例中看看它的实现后,要做到也并不困难。
备注:本章的焦点是把WF作为XML Web服务集成到ASP.NET中使用。但是,在暴露XML Web服务的时候你应该意识到许多关键的问题,最大的问题是安全。对安全的充分讨论远远超过了我可以在此做的介绍,但是下面这个链接应该可以为你带来帮助:http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnnetsec/html/THCMCH12.asp。假如你想把你的工作流暴露为一个XML Web服务的话,我强烈建议你查阅一下ASP.NET安全方面的最佳实践,尤其是围绕XML Web服务的实践。
把工作流暴露为一个XML Web服务
你不能在ASP.NET环境中直接执行工作流的部分原因其实在本书中你已经了解过,默认情况下,工作流运行时是以异步的方式去执行工作流实例的。事实上,在非Web应用程序中使用工作流的时候,这是一个很重要的特性。
但是在基于Web的环境下,这会带来一个问题。如果一个ASP.NET请求发来后,不管它是一个XML Web服务还是一个ASP.NET Web页面,工作流实例都要开始执行并且运行时要把控制权返回给ASP.NET。你的XML Web服务或者ASP.NET页面会立即并持续执行准备输出并可能会在工作流实例完成之前结束。因为工作流实例是异步的,它和你的ASP.NET应用程序并行执行,因此你的ASP.NET代码可能会很快地完成并返回一个工作流处理过程并未完成的响应结果。
提示:在ASP.NET Web页面中正确地执行工作流实例实际上就是对ASP.NET异步Web页面进行调用,该话题超出了本书的范围。但是下面这个链接能带给你一些具体的细节:http://msdn.microsoft.com/msdnmag/issues/05/10/WickedCode/。
这个问题至少会给我们带来两个挑战。首先,我们需要禁用,或者至少要对我们的工作流的异步执行方式进行变通。我们需要它们以同步的方式执行,就像它们和我们的页面或者XML Web服务中使用的是同一个线程一样,以让该Web应用程序在我们结束之前是不会把响应结果返回给调用者的。当然,这并未解决长时间运行的工作流的问题,这是我们将需要去克服的第二个挑战性难题。
长时间运行的工作流所带来的难题紧紧地和基于Web的应用程序自身的性质联系在一起。在这最后一章中你知道了Web应用程序从本质上是无状态的。所发送的在数毫秒间就断开的请求是完全意识不到对方的,除非我们创建一个框架来提供这种能力。Web应用程序也在Web服务器上执行,它通常是非常昂贵的系统,旨在为许许多多的客户端提供服务。假如一个工作流要花费大量时间才能完成,那么它会完全占有Web服务器并降低应用程序的可伸缩性(指的是为越来越多的客户端请求提供服务的能力)。
解决的办法是进行状态管理以及对长时间运行的工作流进行持久化。假如你的工作流程要在超过一个以上的基于Web的调用(ASP.NET页面请求或者XML Web服务)后才能完成的话,你必须持久化该工作流实例并在下一个执行周期期间重新加载它。这也是为什么我在前一章中的“长时间运行的XML Web服务”一节中提到重新生成保存了session状态的cookie的原因。因为客户端也必须意识到有这种可能性并考虑到会有超过一个以上的请求-响应的情况。
Internet信息服务(IIS)特别擅于节约系统资源。在一个典型的客户端应用程序中,其实在本书中到目前为止你所看到过的每一个应用程序当中,工作流运行时是在应用程序开始执行的时候被启动并贯穿该应用程序的生命周期。然而,IIS要收回服务器的资源。我们作为ASP.NET的程序员,这就意味着下面的两件事。
首先,我们必须以某种方式来决定在什么地方以及怎样来启动工作流运行时。在同一个ASP.NET应用程序中的不同请求会被放到不同的线程上进行处理,但是它们在同一个应用程序域(AppDomain)中执行。就像你或许还记得的,在每一个AppDomain只能有唯一的一个WF工作流运行时的实例在执行。因此它并不像在你的ASP.NET应用程序每收到一个请求的时候就创建一个工作流运行时的实例那样简单。这样做可能会导致工作流运行时产生异常。
其次,我们需要找到一种方法来让我们的工作流以同步的方式执行。或者,如果我们的工作流需要长时间运行的话,我们必须在开始执行工作流实例的时候、停止执行的时候、持久化工作流实例的时候以及把工作流当前的状态返回给客户端的时候进行同步。为此,我们需要替换默认的工作流运行时的线程调度服务。要替换该线程调度服务,我们需要重新配置工作流运行时。