【问题标题】:C# WCF pass data from Task running on Server to ClientC# WCF 将数据从在服务器上运行的任务传递到客户端
【发布时间】:2018-07-02 13:46:11
【问题描述】:

我是 WCF 领域的新手。我想在服务器上制作屏幕截图并使用 WCF nettcpbinding 将它们发送到客户端。在客户端上,我想用这些数据更新 UI。但我不知道我需要什么以及如何做到这一点。我读到了带有回调的全双工合同,但我不知道它是否真的需要。

WPFClient.cs

namespace WPFClient
{
    [ServiceContract]
    interface IService
    {
        [OperationContract]
        byte[] GetData();
    }

    public class ViewModel : INotifyPropertyChanged
    {
        private string bytesSum;

        public string BytesSum
        {
            get { return bytesSum; }
            set { bytesSum = value; this.NotifyPropertyChanged("BytesSum"); }
        }


        public ViewModel()
        {
            ChannelFactory<IService> channel = new ChannelFactory<IService>(new NetTcpBinding(), new EndpointAddress(@"net.tcp://localhost:8554/"));
            IService s = channel.CreateChannel();
            //How to get data from server and update UI?
        }

        public event PropertyChangedEventHandler PropertyChanged;

        private void NotifyPropertyChanged(String propertyName = "")
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }
}

Server.cs

namespace Server
{
    [ServiceContract]
    interface IService
    {
        [OperationContract]
        byte[] GetData();
    }

    public class Service : IService
    {
        public byte[] GetData()
        {
            byte[] result = new byte[5000];
            return result;
        }
    }

    public class ScreenLogger
    {
        public byte[] GenerateImage()
        {
            byte[] result = new byte[5000];
            Random rnd = new Random();
            for (int i = 0; i < result.Length; i++)
            {
                result[i] = (byte)rnd.Next();
            }
            return result;
        }

        public void Start()
        {
            var imageTask = Task.Factory.StartNew(() =>
            {
                byte[] GeneratedBytes = GenerateImage();
                //How to send GeneratedBytes to client?
            });
        }

        public void Stop()
        {

        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            ScreenLogger screenLogger = new ScreenLogger();
            screenLogger.Start();

            ServiceHost host = new ServiceHost(typeof(Service));
            host.AddServiceEndpoint(typeof(IService), new NetTcpBinding(), new Uri(@"net.tcp://localhost:8554/"));
            Console.WriteLine("Server start");
            host.Open();
            Console.ReadLine();
            host.Close();
        }
    }
}

【问题讨论】:

    标签: c# wpf wcf


    【解决方案1】:

    您的IService 接口不是双工合同。它应该指定客户端(即客户端应用程序中的视图模型)实现的回调协定。然后,服务器端的服务实现将调用回调上的操作。

    您可以在服务实现中使用OperationContext 类获取对回调的引用,如下所示:

    var callback = OperationContext.Current.GetCallbackChannel<IYourDuplexCallback>();
    

    然后您调用回调方法将数据从服务器传递到客户端。 MSDN here 上有一个如何创建和设置双工 WCF 服务的示例。

    如何:创建双工合同: https://docs.microsoft.com/en-us/dotnet/framework/wcf/feature-details/how-to-create-a-duplex-contract

    【讨论】:

    • @A191919:你看过这个例子还是发生了什么?
    【解决方案2】:

    在我看来,根据您的示例所做的,您似乎只需要在您的服务实例可用的空间中获取 Task 的结果。

    我的简化版本在服务合同和实现上有一个属性:

    [ServiceContract]
    public interface IService
    {
        // not exposed 
        byte[] TaskResults { get; set; }
    
        [OperationContract]
        byte[] GetData();
    }
    
    public class Service : IService
    {
        public byte[] TaskResults { get; set; }
        public byte[] GetData()
        {
            //byte[] result = new byte[5000];
            //return result;
            return TaskResults;
        }
    }
    

    然后将 ScreenLogger.Start() 签名更改为 ScreenLogger.Start(Action&lt;byte[]&gt; bytesAction) 以使用任务工作的结果调用该操作。

    public void Start(Action<byte[]> bytesAction)
        {
            var imageTask = Task.Factory.StartNew(() =>
                                                      {
                                                          //var GeneratedBytes = GenerateImage();
    
                                                          //How to send GeneratedBytes to client?
                                                          bytesAction(GenerateImage());
                                                      });
        }
    

    最后传递一个将任务结果分配给服务属性的操作。

    static void Main(string[] args)
        {
            ScreenLogger screenLogger = new ScreenLogger();
            ServiceHost host = new ServiceHost(typeof(Service));
    
            screenLogger.Start(ba => ((Service)host.SingletonInstance).TaskResults = ba);
    
            host.AddServiceEndpoint(typeof(IService), new NetTcpBinding(), new Uri(@"net.tcp://localhost:8554/"));
            Console.WriteLine("Server start");
            host.Open();
            Console.ReadLine();
            host.Close();
        }
    

    客户端代码(简化)如下所示。

    public class ViewModel 
    {
        private string bytesSum;
    
        public string BytesSum
        {
            get { return bytesSum; }
            set { bytesSum = value; this.NotifyPropertyChanged("BytesSum"); }
        }
    
    
        public ViewModel()
        {
            ChannelFactory<IService> channel = new ChannelFactory<IService>(new NetTcpBinding(), new EndpointAddress(@"net.tcp://localhost:8554/"));
            IService s = channel.CreateChannel();
    
            //How to get data from server and update UI?
            s.GetData().ToList().ForEach(b => Console.Write(b));
        }
    
    
        private void NotifyPropertyChanged(String propertyName = "")
        {
    
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2013-11-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-01-05
      • 1970-01-01
      • 1970-01-01
      • 2018-06-18
      • 1970-01-01
      相关资源
      最近更新 更多