I'm looking for a way to let a client invoke an asynchronous process from a client UI to a WCF service host and then notify the client about the process' status. I guess this can be achieved with sagas (process managers), domain events and a WCF duplex connection, but I'm not sure how!
The case sequence (I guess) would be as following:
Am I right on this? How would, in short, the related classes look like? And yes, I am aware of NServiceBus (it gets mentioned a lot in such cases), but I do not want to rely on an additional framework (I have already a lot of what NServiceBus can solved by myself and I'm already using hundreds of different frameworks for all kinds of stuff..)
Edit: Example Here goes a real world example that might specify my question.
I've got a image processing server that does some magic and unicorn stuff with images. A WCF client uploads an image to the server and then shows a progress bar denoting how much of the image has been processed. The server starts a new ImageProcessService (in request scope). During the processing, he might throw numerous ImageProcessStateChanged events with a number indicating the process by percent. After he's done, he might throw a ImDoneEvent. All of the events should be caught by a Event Bus which signals them back to the right client. The process might take up to 60 seconds and can be fired once per client, but for as many clients as possible.
It sounds like all you are looking for is the behavior enabled by setting IsOneWay=true on your operation contracts. When you set IsOneWay=true in your operation contract, the caller sends the request but does not wait for a response. To get your response, the callee would need to invoke another operation on the callback channel of your duplex channel that also has IsOneWay=true set.
Here is a bare-bones example:
Service Contract:
[ServiceContract( CallbackContract = typeof( IClientCallback ), SessionMode = SessionMode.Required )]
public interface IClientService
{
[OperationContract( IsInitiating = true )]
void CreateSession( string windowsUserName );
[OperationContract( IsOneWay = true )]
void LongOp( );
[OperationContract( IsTerminating = true )]
void Terminate( );
}
Client Callback Contract:
[ServiceContract]
public interface IClientCallback
{
[OperationContract( IsOneWay = true )]
void LongOpResponse( );
}
Service Implementation:
class ServerService : IClientService
{
public void CreateSession( string windowsUserName )
{
//Do stuff to set up your session as desired
}
public void LongOp( )
{
//Do something that takes a long time
LongRunningFunctionCall();
Callback.LongOpResponse();
}
public void Terminate( )
{
//Do stuff to tear down your session
}
public IClientCallback Callback { get { return OperationContext.Current.GetCallbackChannel<IClientCallback>( ); } }
}
Client Callback Implementation:
class CallbackHandler : IClientCallback
{
public void LongOpResponse( )
{
Console.WriteLine( "Received long operation response from server." );
}
}
As long as you have a reference to the client service object that is handling each session, you can access its callback channel directly through that object, so you can initiate a function on the callback contract from any point in your server application, so long as the channel is open.
We usually end up with a lot more one-way operations in our service contracts for duplex channels than we do operations with IsOneWay=false, except for operations where immediate response is critical to continuation of the calling application.