Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Handling WCF events in another process

I have a non-serializable object that I would like to access from a separate process. I've looked around and it seems the only viable option is to use WCF but I'm not sure how to do this as I'm new to WCF. If I create a WCF service, how do I 'hook' the WinForm into the various events in the WCF service? For example, the user communicates with the WCF service directly and I would likemy WinForm client to be notified. How would I be able to know when the user has done something with the WCF service and have the WinForm client pick up on that?

like image 421
Skoder Avatar asked Dec 28 '22 07:12

Skoder


1 Answers

A way to achieve what you are looking for is to implement a callback contract on your service. Then your win-forms app would be able to "subscribe" to events fired on the service (such as modifications to your object).

To do this you implement a service contract with a callback contract:

[ServiceContract]
public interface IMyService_Callback
{
    [OperationContract(IsOneWay = true)]
    void NotifyClients(string message);
}

[ServiceContract(CallbackContract = typeof(IMyService_Callback))]
public interface IMyService
{
    [OperationContract]
    bool Subscribe();
}

You then implement your service:

[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Reentrant)]
public class MyService : IMyService
{
    private List<IMyService_Callback> callbacks;

    public MyService()
    {
        this.callbacks = new List<IMyService_Callback>();
    }

    private void CallClients(string message)
    {
        callbacks.ForEach(callback => callback.NotifyClients(message));
    }

    public bool Subscribe()
    {
        var callback = OperationContext.Current.GetCallbackChannel<IMyService_Callback>();

        if (!this.callbacks.Contains(callback))
        {
            this.callbacks.Add(callback);
        }

        // send a message back to the client
        CallClients("Added a new callback");

        return true;
    }
}

In your winforms client you only need to implement the callback method:

[CallbackBehavior(ConcurrencyMode = ConcurrencyMode.Reentrant, UseSynchronizationContext = false)]
public partial class ServiceClient : Form, IMyService_Callback
{
    // Sync context for enabling callbacks
    SynchronizationContext uiSyncContext;

    public ServiceClient()
    {
        InitializeComponent(); //etc.

        uiSyncContext = SynchronizationContext.Current;

        // Create proxy and subscribe to receive callbacks
        var factory = new DuplexChannelFactory<IMyService>(typeof(ServiceClient), "NetTcpBinding_IMyService");
        var proxy = factory.CreateChannel(new InstanceContext(this));
        proxy.Subscribe();
    }

    // Implement callback method
    public void NotifyClients(string message)
    {
        // Tell form thread to update the message text field
        SendOrPostCallback callback = state => this.Log(message);

        uiSyncContext.Post(callback, "Callback");
    }

    // Just updates a form text field
    public void Log(string message)
    {
        this.txtLog.Text += Environment.NewLine + message;
    }
}    

Config for service:

<system.serviceModel>
  <services>
    <service name="TestService.MyService" behaviorConfiguration="Normal">
      <endpoint 
        address="net.tcp://localhost:8000/MyService" 
        contract="TestService.IMyService" 
        binding="netTcpBinding" />
    </service>
  </services>
  <behaviors>
    <serviceBehaviors>
      <behavior name="Normal" >
        <serviceDebug includeExceptionDetailInFaults="true"/>
      </behavior>
    </serviceBehaviors>
  </behaviors>
</system.serviceModel>

Config for client

<system.serviceModel>
  <client>
    <endpoint address="net.tcp://localhost:8000/MyService" 
              binding="netTcpBinding"
              contract="TestService.IMyService"
              name="NetTcpBinding_IMyService">
    </endpoint>
  </client>
</system.serviceModel>
like image 138
tom redfern Avatar answered Dec 29 '22 21:12

tom redfern