【问题标题】:WCF duplex service consumed by multiple WPF Controls多个 WPF 控件使用的 WCF 双工服务
【发布时间】:2016-06-22 07:59:09
【问题描述】:

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

  1. 服务的InstanceContextMode设置为Single
  2. WCF 服务使用 duplex 合同和 回调
  3. MainWindow 定期调用服务的“Ping”方法来了解(并以图标直观地显示)服务是否可用。 MainWindow 实现了一个 PingReply 回调来获取回复。
  4. MainWindow 有一个Frame 用于加载不同的Pages。每个 Page 都包含多个 UserControl,它们调用服务来更新他们的视图。

这里是简化的服务接口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 em> 和 GetUserControlBReply (现在我只是在没有代码的情况下实现它们)

MainWindow.xaml.cs 中的GetUserControlAReply

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

当我在 UserControlA 的模型中实现 ISrvServiceCallback 接口时也会发生同样的事情:我必须在没有代码的情况下实现 PingReply

我认为这不是一个好的工作方式。解决此类问题的最佳实践是哪些?你能给我推荐一些关于这种情况的教程吗?

编辑 正如@lokusking 所建议的,我提供了UserControl 示例的Model 和ViewModel。 View 绑定到 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));
    }
}

【问题讨论】:

    标签: c# .net wpf wcf mvvm


    【解决方案1】:

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

    下一步使这个类成为单例。 现在您可以在任何地方访问您的 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 隧道服务器响应中。

    好处: 你有一个!始终可用的类。 你只需要实现你的逻辑一次! 每个消费者都会收到您可以按需订阅的事件的通知。

    【讨论】:

    • 我的错误:我的意思是客户端的 ISrvServiceCallback 接口
    • 这里的答案相同;)此解决方案适用于双方
    • 我想我遗漏了一些东西:UserControlA 由绑定到包含 UserControlAModel 的 UserControlAViewModel 的 UserControlAView.xaml 形成。现在模型调用服务并实现回调以更新内部属性(向 viewModel 发送通知 bla bla bla)。如何从包含回调代码的实现中修改 UserControlAModel 的属性?
    • @aDone 你能编辑你的问题并粘贴代码,以便我更深入地了解一下吗?
    • 好建议!问题已编辑!我将尝试使用您上次编辑的代码,看看会发生什么! :) 我会告诉你的!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-17
    相关资源
    最近更新 更多