【问题标题】:How to communicate between WCF service and host application?如何在 WCF 服务和宿主应用程序之间进行通信?
【发布时间】:2011-01-13 12:22:13
【问题描述】:

我通过这个tutorial 创建了一个WCF 服务。这很好用,这里没有问题。 现在我在托管应用程序中托管服务。但同时我想使用来自客户端的输入到主机应用程序中的服务。

我不需要客户端和服务之间的双工通信。我只需要Service和Host之间的通信。

解决这个问题的最佳方法是什么?

【问题讨论】:

    标签: c# .net wcf service host


    【解决方案1】:

    我设法使用来自 question 的信息解决了这个问题。其中有人指出,服务类也可以传递给主机。然后就像添加一个响应来自服务的事件的事件侦听器一样简单。

    【讨论】:

    • 在这种情况下,您的服务将是单例的。
    【解决方案2】:

    这就像线程之间的通信。您需要一些具有适当锁定/同步的共享变量。您的宿主应用程序将写入此变量,而您的服务将能够从该变量中读取。

    【讨论】:

    • 感谢您的建议。好的,我可以看到这个工作。但是如何从主机应用程序访问服务对象的变量部分,反之亦然?我没有对服务的引用,因为我使用 Host.open() 命令来托管服务。
    • 您不能访问服务实例中的变量。您的变量必须由知名对象共享。例如,您可以实现单例,它将向服务和主机公开这些变量。其他方法是使用共享对象的服务定位器。
    • 你的意思是我必须在主机应用程序中创建一个具有单例属性的单独对象。如何从我的服务创建对此对象的引用?我的最终目标是在宿主应用程序中触发一个函数,当 WCF 服务从客户端接收数据时,使用单例方法是否可以工作?
    【解决方案3】:

    有一个框架和教程似乎可以很好地处理这个问题WPF Service Host on 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();
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-09-29
      • 2011-01-10
      • 2020-02-19
      • 1970-01-01
      相关资源
      最近更新 更多