如何强制 WF4 状态机工作流服务抛出意外的消息名称?

How to force WF4 State Machine workflow service to throw on unexpected message name?

我在 IIS 中有一个 *.xamlx 工作流服务 运行 并且有 State1、State2 和 State3。

Trigger T1 (State 1 -> State 2) listens to "Start" message on Receive Activity.
Trigger T2 (State 2 -> State 3) listens to "Proceed" message on Receive Activity.

我遇到的问题是,当我的状态机处于状态 1 并且 "Proceed" 消息即将到来时,我期望出现类似 InvalidOperationException 的情况。但是,看起来它只是在队列中等待并且因超时异常而失败。

如何在此处获得预期的行为?

我只是在这里粘贴我从 Jim Carley - MSFT 在 MSDN 论坛上得到的答案,这样它就不会在几年后消失。

Alexander,

You are running into a situation where the workflow has both "protocol bookmarks" and "non-protocol bookmarks". "Protocol bookmarks" are created by the messaging activities (e.g Receive). "Non-protocol bookmarks" are bookmarks that are unrelated to messaging activities. And State activities create non-protocol bookmarks internally.

This issue was reported when using "Pick" also - https://social.msdn.microsoft.com/Forums/vstudio/en-US/275f7817-1ec7-433c-89ba-fe48afd1dae8/wf4-wcf-send-message-at-wrong-time?forum=wfprerelease

Here is an excerpt from my explanation on that thread:

The root cause of the difference in behavior (timeout) when using a Pick or State activity to encapsulate the Receive for OperationB is that Pick and State activities create internal bookmarks that are unrelated to the bookmarks created by Receive activities.

The bookmarks created by Receive activities (let’s call them “protocol bookmarks”) are treated in a special way in order to preserve the messaging protocol implemented by the workflow service.

Imagine a scenario where the service has the messaging “protocol” of Operation1 followed by Operation2:

Receive(Operation1)

SendReply(Operation1)

DoSomeOtherWork

Receive(Operation2)

SendReply(Operation2)

If DoSomeOtherWork has asynchronous operations that may cause the workflow instance to go idle, they are going to create non-protocol bookmarks. These bookmarks will get resumed thru some other means, outside of the messaging protocol for the workflow service.

So it is possible for Operation1 to complete and for the client to send Operation2 before DoSomeOtherWork is complete. We don’t want to reject Operation2 immediately. Instead, we hang onto the Operation2 message in hopes that the work being done by DoSomeOtherWork completes and the bookmark associated with that work gets resumed. Once DoSomeOtherWork completes, the protocol bookmark for Receive(Operation2) will get created and now the message from the client can successfully get processed.

While DoSomeOtherWork is still outstanding, the message for Operation 2 is received. It discovers that there is no protocol bookmark for Operation2. We then check to see if there are any non-protocol bookmarks outstanding for the instance. If there are (as is the case when DoSomeOtherWork is still outstanding), we hang on to the message. But if there are no other non-protocol bookmarks, we immediately reject the message as being out of order.

Starting in .NET 4.6, there is an AppSetting that you can specify in the web.config file of your service that controls how non-protocol bookmarks and out-of-order messages are dealt with. To configure the AppSetting, add this to your web.config file:

The value of this "FilterResumeTimeoutInSeconds" specifies the length of time (in seconds) the workflow runtime hangs on to an out-of-order message before it times out. The default value is 60. A value of 0 specifies that it should not wait at all and reject out-of-order message with fault with the text:

Operation '' on service instance with identifier '' cannot be performed at this time. Please ensure that the operations are performed in the correct order and that the binding in use provides ordered delivery guarantees.

If the value is greater than 0, then you will still get a timeout exception after the specified time expires.

Again, this new AppSetting is available starting in .NET 4.6. And this all assumes that BufferedReceive is NOT being used.

This is also documented here: http://blogs.msdn.com/b/dotnet/archive/2015/07/20/announcing-net-framework-4-6.aspx?PageIndex=2