aDone
aDone

Reputation: 135

WCF duplex service consumed by multiple WPF Controls

I'm developing a MVVM WPF application that consumes a WCF service hosted by a server application (WPF). I have some doubts about which is the best way to consume the service knowing that:

  1. InstanceContextMode of the service is set to Single
  2. The WCF service uses duplex contract with callbacks
  3. The MainWindow calls periodically a "Ping" method of the service to know (and visually display with an icon) if the service is available. MainWindow implements a PingReply callback to get the reply.
  4. The MainWindow has a Frame used to load different Pages. Every Page includes several UserControls that call the service to update their views.

Here is the simplified service interface ISrvService.cs

[ServiceContract(CallbackContract = typeof(ISrvServiceCallback))]
public interface ISrvService
{
    [OperationContract(IsOneWay = true)]
    void Ping();

    [OperationContract(IsOneWay = true)]
    void GetUserControlAStatus();

    [OperationContract(IsOneWay = true)]
    void GetUserControlBStatus();
}

public interface ISrvServiceCallback
{
    [OperationContract(IsOneWay = true)]
    void PingReply(string reply);

    [OperationContract(IsOneWay = true)]
    void GetUserControlAReply(string reply);

    [OperationContract(IsOneWay = true)]
    void GetUserControlAReply(string reply);
}

In this way when I implement ISrvServiceCallback interface in MainWindow to have PingReply callback, I also need to implement GetUserControlAReply and GetUserControlBReply (right now I just implement them with no code)

GetUserControlAReply in MainWindow.xaml.cs

    public void GetUserControlAReply(string reply)
    {
        //nothing to do
    }

The same thing happens when I implement the ISrvServiceCallback interface in the model of the UserControlA: i have to implement PingReply with no code inside.

I don't think this is a good way to work with. Which are the best practices to solve this kind of problem? Can you suggest me some tutorials that talk about this situation?

EDIT As @lokusking suggested, I provide Model and ViewModel of a example of UserControl. The View is binded to LblStatus of ViewModel.

UserControlAModel.cs

public class UserControlAModel: INotifyPropertyChanged, SrvService.ISrvServiceCallback
{
    System.ServiceModel.InstanceContext instanceContext;
    SrvService.SrvServiceClient client;

    public event PropertyChangedEventHandler PropertyChanged;

    private string _Status;
    public string Status
    {
        get { return _Status; }
        set { _Status = value; NotifyPropertyChanged(); }
    }

    public UserControlAModel()
    {
        Status = "NOT CONNECTED";
    }

    public void GetStatus()
    {
        instanceContext = new System.ServiceModel.InstanceContext(this);
        client = new SrvService.SrvServiceClient(instanceContext);
        client.GetUserControlAStatus();
    }

    private void NotifyPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    //callbacks implementation
    public void GetUserControlAReply(string reply)
    {
        Status = reply;
    }

    public void GetUserControlBReply(string reply)
    {
        //nothing to do
    }

    public void PingReply(string reply)
    {
        //nothing to do
    }
}

UserControlAViewModel.cs

public class UserControlAViewModel : INotifyPropertyChanged
{
    private UserControlAModel _uControlAModel;
    public UserControlAModel MyUserControlAModel
    {
        get
        { return _uControlAModel; }
        set
        { _uControlAModel = value; NotifyPropertyChanged(); }
    }

    public string LblStatus
    {
        get { return MyUserControlAModel.Status; }
        set { MyUserControlAModel.Status = value; NotifyPropertyChanged(); }
    }

    public UserControlAViewModel()
    {
        MyUserControlAModel = new UserControlAModel();
        MyUserControlAModel.PropertyChanged -= UserControlAModel_PropertyChanged;
        MyUserControlAModel.PropertyChanged += UserControlAModel_PropertyChanged;

        MyUserControlAModel.GetStatus();
    }

    private void UserControlAModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        NotifyPropertyChanged(string.Empty);
    }

    public event PropertyChangedEventHandler PropertyChanged;

    private void NotifyPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

Upvotes: 3

Views: 531

Answers (1)

lokusking
lokusking

Reputation: 7456

Make a seperate class which implents your ISrvService.

Next step make this class a Singleton. Now you can access your wcf-functions everywhere and have only one Implementation.

EDIT: This is a solution based on my previous code.

Implementation

public class SrvServiceCallbackProxy : ISrvServiceCallback
  {

    public event EventHandler PingReplyReceived;

    private SrvServiceClient _innerClient;

    private SrvServiceCallbackProxy() {
      var instanceContext = new System.ServiceModel.InstanceContext(this);
      _innerClient = new SrvService.SrvServiceClient(instanceContext);

    }

    private static SrvServiceCallbackProxy _instance;
    public static SrvServiceCallbackProxy Instance => _instance ?? (_instance = new SrvServiceCallbackProxy());


    public void PingReply(string reply) {
      this.PingReplyReceived?.Invoke(reply, EventArgs.Empty);
    }
}

Usage

SrvServiceCallbackProxy.Instance.PingReplyReceived += ..Here goes the method..

NOTE

Im doing this all the time. Im wrapping my callback-implementation in Singleton-Proxy tunneling server-responses with events.

Benefits: You have ONE! class which is always available. You have only to implement your Logic once! Every consumer will get notified by events you can subsrcribe to on demand.

Upvotes: 3

Related Questions