1
votes

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:

  1. Client invokes process
  2. Client creates WCF proxy
  3. Proxy connects to service host
  4. Service host creates duplex channel to client
  5. Service host starts process using command bus & passes duplex channel
  6. Process state changes!
  7. Locate related duplex channel
  8. Push back status change
  9. Client receives status change and visualizes

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.

2
how much times can take your operation on the serverBRAHIM Kamel
@K.B What? How long does it take? Approx. up to 30 seconds.Acrotygma
Couldn't you just set a long timeout and lie to the client about progress?Zache
@Zache My example above is well.. just an example. Your solution might work for this, however my client requires the state changes that occur during the process (it's about a network discovery feature). So no, I can't fake and wait for a timeout.Acrotygma
which type of UI(winform,WPF,Asp.Net,Silverlight) and protocol(wsDualHttpBinding,netTcpBinding and netNamedPipeBinding) you would like to use because for each of this can be different architectureBRAHIM Kamel

2 Answers

4
votes

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.

0
votes

This can be achieved using Task Parallelism or IAsyncResult.

IAsyncResult has a WaitOne on its AsyncWaitHandle, so the client can wait for it to finish executing asynchronously and then get the value by invoking the End call of the asynchronous method.

Example would be.

public IAsyncResult Process(type param, AsyncCallback callback, object state)
{
   // code here to process
}

public TypeResult EndProcess(IAsyncResult ar)
{
   // return result here
}

Now the callback can be used to invoke methods from your client, in your case, can be used to notify about the state.

Details about IAsyncResult: Here