C # WCF передает данные от Задачи, выполняющейся на Сервере, к Клиенту - PullRequest
0 голосов
/ 02 июля 2018

Я новичок в области WCF. Я хочу сделать скриншот на сервере и отправить их клиенту с помощью WCF nettcpbinding. На клиенте я хочу обновить пользовательский интерфейс с этими данными. Но я не знаю, что мне нужно и как это сделать. Я читал о полнодуплексном контракте с обратным вызовом, но я не знаю, действительно ли он нужен.

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

Ответы [ 2 ]

0 голосов
/ 04 июля 2018

На мой взгляд, и в соответствии с тем, что делает ваш пример, похоже, вам просто нужно получить результаты 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<byte[]> 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 = "")
    {

    }
}
0 голосов
/ 02 июля 2018

Ваш IService интерфейс не является дуплексным контрактом. В нем должен быть указан контракт обратного вызова, который реализует клиент, т. Е. Ваша модель представления в клиентском приложении. Реализация сервиса на стороне сервера будет затем вызывать операции обратного вызова.

Вы можете получить ссылку на обратный вызов, используя класс OperationContext в своей реализации сервиса, например:

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

Затем вы вызываете метод обратного вызова для передачи данных с сервера клиенту. Вот пример того, как создать и настроить дуплексную службу WCF, доступную на MSDN здесь .

Как: создать дуплексный контракт: https://docs.microsoft.com/en-us/dotnet/framework/wcf/feature-details/how-to-create-a-duplex-contract

...