A frequently asked question I see is whether it’s possible to cancel a streamed operation. The simple answer is that gracefully shutting down a streamed operation requires some work and planning at design time. It’s always possible to rudely shut down the operation by aborting the stream, and in many cases this is what people end up doing. Aborting is a very direct way of stopping an operation although it can be heavy-handed to use abort as your primary mechanism. This is particularly true if after aborting you need to spend significant resources on the client or server reestablishing the connection. Aborting also doesn’t give you any feedback about why the other side had to abort.
Let’s look at a couple of different workarounds to aborting the stream that I see people trying. One thing that people seem to try a lot is either returning early or simply not reading from the stream for either the request or response that they no longer want. This does not work. Ignoring the problem does not make it go away in this case. You have to actively do something on either the client or server to stop the stream of data. Aborting is one active way of doing this, with the problems discussed above.
Sending a fault message is a tempting alternative to aborting, which is going to be the basis of the final idea. Trying to directly fault the streamed operation unfortunately doesn’t work. Sending a fault back while streaming a request doesn’t work because the client only creates the response object after the request is finished. Sending a fault back while streaming a response has the obvious problem of how to transmit the fault message back if you don’t have a communication channel. Both of these problems with fault messages can be solved by creating an out-of-band mechanism for transmitting the cancel message. This cancel message can be a normal message contract and doesn’t specifically have to be a fault message.
A common networking pattern is to have both a data channel and a control channel, such as in FTP. The data channel is modeled in this case by the streamed operation. We can model the control channel with an operation in the opposite direction that takes an identifier for the stream being controlled. It’s possible for the control channel to have a one-way contract if that makes it simpler because the result of the cancel control operation is readily apparent on the data channel. If you find yourself using this pattern frequently, you might want to build a layered channel that encapsulates the data and control connections together. Using a layered channel would allow you to remove the logic for establishing the control connection from the application and would eliminate the need to define the control operation contracts by hand.
Next time: Using Composite Duplex