多个WPF控件使用的WCF双工服务

时间:2016-06-22 07:59:09

标签: c# .net wpf wcf mvvm

我正在开发一个MVVM WPF应用程序,它使用服务器应用程序(WPF)托管的WCF服务。我有一些疑问,知道这是服务服务的最佳方式:

    该服务的
  1. InstanceContextMode 设置为 Single
  2. WCF服务使用双面合同与回调
  3. MainWindow 定期调用服务的“ Ping ”方法,以便知道该服务是否可用(并用图标直观显示)。 MainWindow 实现 PingReply 回调以获得回复。
  4. MainWindow 有一个 Frame ,用于加载不同的 Pages 。每个 Page 都包含多个 UserControls ,它们会调用服务来更新其视图。
  5. 以下是简化的服务界面 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);
    }
    

    这样当我在 MainWindow 中实现 ISrvServiceCallback 接口以进行 PingReply 回调时,我还需要实现 GetUserControlAReply GetUserControlBReply (现在我只是在没有代码的情况下实现它们)

    MainWindow.xaml.cs中的GetUserControlAReply

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

    当我在UserControlA的模型中实现 ISrvServiceCallback 接口时,会发生同样的事情:我必须实现 PingReply ,而不需要代码。

    我不认为这是一种很好的合作方式。哪种解决此类问题的最佳做法?你能给我一些谈论这种情况的教程吗?

    修改 正如@lokusking建议的那样,我提供了一个UserControl示例的Model和ViewModel。视图绑定到ViewModel的 LblStatus

    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));
        }
    }
    

1 个答案:

答案 0 :(得分:2)

创建一个单独的类来实现您的ISrvService

下一步使这个类成为Singleton。 现在,您可以在任何地方访问您的wcf函数,并且只有一个实现。

编辑:这是基于我之前代码的解决方案。

<强>实施

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);
    }
}

<强>用法

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

注意

我一直这样做。我将回调实现包装在Singleton-Proxy隧道服务器响应中,包含事件。

优点: 你有一个!始终可用的课程。 你只需要实现一次逻辑! 每个消费者都会收到您可以根据需要订阅的事件的通知。