Как взаимодействовать между службой WCF и ведущим приложением?

Я создал службу WCF с помощью этого руководство. Это отлично работает, здесь нет проблем. Теперь я размещаю службу в управляемом приложении. Но в то же время я хотел бы использовать входные данные от клиента для службы в хост-приложении.

Мне не нужна двусторонняя связь между Клиентом и Сервисом. Мне просто нужна связь между Сервисом и Хостом.

Как лучше всего с этим справиться?


person Martijn    schedule 13.01.2011    source источник


Ответы (3)


Мне удалось решить эту проблему, используя информацию из этого вопроса. В нем было указано, что классы обслуживания также могут быть переданы хосту. Тогда это так же просто, как добавить прослушиватель событий, который реагирует на события от Сервиса.

person Martijn    schedule 13.01.2011
comment
В таком случае ваш сервис будет одиночным. - person Ladislav Mrnka; 13.01.2011

Это похоже на общение между потоками. Вам нужна общая переменная с правильной блокировкой / синхронизацией. Ваше ведущее приложение будет писать в эту переменную, и ваша служба сможет читать из этой переменной.

person Ladislav Mrnka    schedule 13.01.2011
comment
Спасибо за ваше предложение. Хорошо, я видел, как это работает. Но как мне получить доступ к переменным, являющимся частью объекта службы, из хост-приложения или наоборот? У меня нет ссылки на службу, поскольку я использую команду Host.open () для размещения службы. - person Martijn; 13.01.2011
comment
У вас нет доступа к переменным в экземпляре службы. Ваши переменные должны использоваться известным объектом. Например, вы можете реализовать синглтон, который будет предоставлять такие переменные как службе, так и хосту. Другой подход заключается в использовании локатора служб для общего объекта. - person Ladislav Mrnka; 13.01.2011
comment
Вы имеете в виду, что мне нужно создать отдельный объект с одноэлементными свойствами в приложении Host. Как я могу создать ссылку на этот объект из моего Сервиса? Моя конечная цель - запустить функцию в главном приложении, когда служба WCF получает данные от клиента, будет ли это работать с использованием метода singleton? - person Martijn; 13.01.2011

Доступны структура и учебное пособие, которые, кажется, неплохо справляются с этой проблемой Хост службы WPF на Codeplex.

РЕДАКТИРОВАТЬ: обновлено, чтобы проиллюстрировать технику, созданную шаблоном узла службы WPF.

Узел службы WPF - это шаблон для Visual Studio, который создает скелет приложения и тестового клиента. Я опишу здесь соответствующие части.

Вот как выглядит скелетный проект:

Проект скелета

ClientServiceHost.cs

using System;
using System.ServiceModel;

namespace WPFServiceHost1.Service
{
    public class ClientServiceHost : IDisposable
    {
        private bool _Initalized;

        private ServiceHost _InnerServiceHost;
        private MainWindow _MainWindow;

        public ClientServiceHost(MainWindow mainWindow)
        {
            _MainWindow = mainWindow;
            InitializeServiceHost();
        }

        private void InitializeServiceHost()
        {
            try
            {
                ClientService clientService = new ClientService(_MainWindow);
                _InnerServiceHost = new ServiceHost(clientService);

                _InnerServiceHost.Opened += new EventHandler(_InnerServiceHost_Opened);
                _InnerServiceHost.Faulted += new EventHandler(_InnerServiceHost_Faulted);
                _InnerServiceHost.Open();
            }
            catch (Exception ex)
            {
                throw new Exception("Unable to initialize ClientServiceHost", ex);
            }
        }

        void _InnerServiceHost_Opened(object sender, EventArgs e)
        {
            _Initalized = true;
        }

        void _InnerServiceHost_Faulted(object sender, EventArgs e)
        {
            this._InnerServiceHost.Abort();

            if (_Initalized)
            {
                _Initalized = false;
                InitializeServiceHost();
            }
        }

        #region IDisposable Members

        public void Dispose()
        {
            try
            {
                _InnerServiceHost.Opened -= _InnerServiceHost_Opened;
                _InnerServiceHost.Faulted -= _InnerServiceHost_Faulted;
                _InnerServiceHost.Close();
            }
            catch
            {
                try { _InnerServiceHost.Abort(); }
                catch { }
            }
        }
        #endregion
    }
}

MainWindow.xaml

<Window x:Class="WPFServiceHost1.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="WPFServiceHost1" Height="344" Width="343" Closing="Window_Closing">
    <Grid>
        <Label Height="28" Margin="12,12,0,0" Name="label1" VerticalAlignment="Top" HorizontalAlignment="Left" Width="119">Messages received:</Label>
        <ListBox Margin="21,38,26,21" Name="listBox1" />
    </Grid>
</Window>

MainWindow.xaml.cs

using System.Threading;
using WPFServiceHost1.Service;

namespace WPFServiceHost1
{
    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public SynchronizationContext _SyncContext = SynchronizationContext.Current;
        private ClientServiceHost _ClientServiceHost;

        public MainWindow()
        {
            InitializeComponent();
            _ClientServiceHost = new ClientServiceHost(this);
        }

        private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            _ClientServiceHost.Dispose();
        }
    }
}

IClientService.cs

using System.ServiceModel;

namespace WPFServiceHost1.Service
{
    [ServiceContract(Namespace = "urn:WPFServiceHost")]
    public interface IClientService
    {
        [OperationContract]
        void ClientNotification(string message);
    }
}

ClientService.cs

using System;
using System.ServiceModel;

namespace WPFServiceHost1.Service
{
    [ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Single, InstanceContextMode = InstanceContextMode.Single, UseSynchronizationContext = false)]
    public class ClientService : IClientService
    {
        private MainWindow _MainWindow;

        public ClientService(MainWindow window)
        {
            _MainWindow = window;
        }

        #region IClientService Members
        public void ClientNotification(string message)
        {
            try
            {
                _MainWindow._SyncContext.Send(state =>
                {
                    _MainWindow.listBox1.Items.Add(message);
                }, null);
            }
            catch (Exception ex)
            {
                throw new FaultException(ex.Message);
            }
        }
        #endregion
    }
}

App.config

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <system.serviceModel>
        <behaviors>
            <serviceBehaviors>
                <behavior name="ClientServiceBehavior">
                    <serviceDebug includeExceptionDetailInFaults="false" />
                </behavior>
            </serviceBehaviors>
        </behaviors>
        <services>
            <service behaviorConfiguration="ClientServiceBehavior"
                name="WPFServiceHost1.Service.ClientService">
                <endpoint address="ClientService" binding="basicHttpBinding" contract="WPFServiceHost1.Service.IClientService"/>
                <host>
                    <baseAddresses>
                        <add baseAddress="http://localhost:8010" />
                    </baseAddresses>
                </host>
            </service>
        </services>
    </system.serviceModel>
</configuration>

И TestClient, Program.cs:

using System;
using System.ServiceModel;
using System.Threading;

namespace TestClient
{
    class Program
    {
        static void Main(string[] args)
        {
            IClientService proxy = null;

            try
            {
                proxy = ChannelFactory<IClientService>.CreateChannel(new BasicHttpBinding(), new EndpointAddress("http://localhost:8010/ClientService"));
                Console.WriteLine("Press <Enter> when ClientService is running.");
                Console.ReadLine();
                Console.WriteLine();

                Console.WriteLine("Sending a single message to ClientService");
                proxy.ClientNotification("Hello from TestClient");

                Console.WriteLine();

                Console.Write("Enter a valid number to load test ClientService: ");
                string result = Console.ReadLine();
                int testCount = Convert.ToInt32(result);
                int counter = 0;
                object counterLock = new object();

                while (true)
                {
                    lock (counterLock)
                    {
                        Thread t = new Thread(() => proxy.ClientNotification(string.Format("Load test from TestClient: {0}", ++counter)));
                        t.Start();
                    }

                    if (counter == testCount)
                        break;
                }

                Console.ReadLine();
            }
            finally
            {
                ICommunicationObject co = proxy as ICommunicationObject;
                try
                {
                    co.Close();
                }
                catch { co.Abort(); }
            }

            Console.ReadLine();
        }
    }
}
person PIntag    schedule 06.08.2014