双向 WCF 客户端-服务器通信

发布于 2024-09-01 08:10:04 字数 7387 浏览 5 评论 0原文

我花了数周的时间来创建一个客户端/服务器来控制位于服务器端的音乐服务器应用程序,该应用程序由位于 LAN 上的多个客户端应用程序控制。我已经成功地让客户端与服务器进行通信,发送命令来操作音乐服务器,并通过使用回调来回复客户端,以便可以适当更新所有客户端 UI。然而,我的问题是,我无法弄清楚如何广播需要从服务器应用程序发送到客户端的其他消息。我希望利用回调方法;但是我无法从服务器端访问它。我是否需要修改或创建另一个合同来提供从服务器到客户端的通信?绑定需要修改吗?正如我之前提到的,我确实已经为此工作了几周(这开始感觉像是“几年”),并希望让应用程序的最后一部分正常工作。有人可以引导我走向正确的方向吗?

客户端服务参考:

<?xml version="1.0" encoding="utf-8"?>
<ServiceReference>
<ProxyGenerationParameters
    ServiceReferenceUri="http://localhost:8001/APService/mex"
    Name="APGateway"
    NotifyPropertyChange="True"
    UseObservableCollection="False">
</ProxyGenerationParameters>
<EndPoints>
    <EndPoint
        Address="net.tcp://localhost:8000/APService/service"
        BindingConfiguration="TcpBinding"
        Contract="APClient.APGateway.APUserService"
        >
    </EndPoint>
    <EndPoint
        Address="http://localhost:8001/APService/service"
        BindingConfiguration="HttpBinding"
        Contract="APClient.APGateway.APUserService"
        >
    </EndPoint>
</EndPoints>
</ServiceReference>

客户端 AP CONFIG

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
    <sectionGroup name="applicationSettings" type="System.Configuration.ApplicationSettingsGroup, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
        <section name="APClient.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
    </sectionGroup>
</configSections>
<system.serviceModel>
    <client>
        <endpoint
            address="net.tcp://localhost:8000/APService/service"
            binding="netTcpBinding"
            contract="APClient.APGateway.APUserService"
            name="TcpBinding" />
        <endpoint
            address="http://localhost:8001/APService/service"
            binding="wsDualHttpBinding"
            contract="APClient.APGateway.APUserService"
            name="HttpBinding" />
    </client>
</system.serviceModel>
<applicationSettings>
    <APClient.Properties.Settings>
        <setting name="pathToDatabase" serializeAs="String">
            <value>C:\Users\Bill\Documents\APData\</value>
        </setting>
    </APClient.Properties.Settings>
</applicationSettings>

服务器端 AP.CONFIG

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
   <system.serviceModel>
    <behaviors>
      <serviceBehaviors>
        <behavior name="MetadataBehavior">
           <serviceMetadata httpGetEnabled="true" httpGetUrl="http://localhost:8001/APService/mex" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <services>
      <service behaviorConfiguration="MetadataBehavior" name="APService.APService">
        <endpoint address="service" binding="netTcpBinding" name="TcpBinding"
          contract="APService.IAPServiceInventory" />
        <endpoint address="service" binding="wsDualHttpBinding" name="HttpBinding"
         contract="APService.IAPServiceInventory" />
        <endpoint address="mex" binding="mexHttpBinding" name="MexBinding"
          contract="IMetadataExchange" />
        <host>
          <baseAddresses>
            <add baseAddress="net.tcp://localhost:8000/APService/" />
            <add baseAddress="http://localhost:8001/APService/" />
          </baseAddresses>
        </host>
      </service>
    </services>
  </system.serviceModel>
</configuration>

服务器端 APSERVICE.CS

namespace APService
{
     [ServiceBehavior(ConcurrencyMode=ConcurrencyMode.Single,InstanceContextMode=InstanceContextMode.PerCall)]
 public class APService : IAPServiceInventory
 {
      private static List<IClientCallback> _callbackList = new List<IClientCallback>();
      private static int _beerInventory = Convert.ToInt32(System.Configuration.ConfigurationManager.AppSettings["InitialBeerInventory"]);
      public APService() {}
      public int SubscribeToServer(string guestName)
      {
           IClientCallback guest = OperationContext.Current.GetCallbackChannel<IClientCallback>();
           if(!_callbackList.Contains(guest)) { _callbackList.Add(guest); }
           else { Console.WriteLine(guest + " is already logged onto the Server."); }
           _callbackList.ForEach(delegate(IClientCallback callback) { callback.NotifyGuestJoinedParty(guestName); });
      }
      public void UpdateClients(string guestName,string UpdateInfo)
      {
           _callbackList.ForEach(delegate(IClientCallback callback) { callback.NotifyUpdateClients(guestName,UpdateInfo); });
      }
      public void SendRequestToServer(string guestName, string request)
      {
           _callbackList.ForEach(delegate(IClientCallback callback) { callback.NotifyRequestMadeToServer(guestName,request); });
           if(request == "Play") { APControl.Play(); }
           else if(request == "Stop") { APControl.Stop(); }
           else if(request == "Pause") { APControl.PlayPause(); }
           else if(request == "Next Track") { APControl.NextTrack(); }
           else if(request == "Previous Track") { APControl.PreviousTrack(); }
           else if(request == "Mute") { APControl.Mute(); }
           else if(request == "Volume Up") { APControl.VolumeUp(5); }
           else if(request == "Volume Down") { APControl.VolumeDown(5); }
      }
      public void CancelServerSubscription(string guestName)   
      {
           IClientCallback guest = OperationContext.Current.GetCallbackChannel<IClientCallback>();
           if(_callbackList.Contains(guest)) { _callbackList.Remove(guest); }
           _callbackList.ForEach(delegate(IClientCallback callback) { callback.NotifyGuestLeftParty(guestName); });
      }
 }

服务器端 IAPSERVICE.CS

namespace APService
{
     [ServiceContract(Name="APUserService",Namespace="http://AP.com/WCFClientServer/",SessionMode=SessionMode.Required, CallbackContract=typeof(IClientCallback))]
 public interface IAPServiceInventory
 {
      [OperationContract()]
      int SubscribeToServer(string guestName);
      [OperationContract(IsOneWay=true)]
      void SendRequestToServer(string guestName,string request);
      [OperationContract(IsOneWay=true)]
      void UpdateClients(string guestName,string UpdateInfo);
      [OperationContract(IsOneWay=true)]
      void CancelServerSubscription(string guestName);
 }
 }

服务器端 - IAPServiceCallback.cs

namespace APService
{
     public interface IClientCallback
     {
          [OperationContract(IsOneWay=true)]
          void NotifyGuestJoinedParty(string guestName);
          [OperationContract(IsOneWay=true)]
          void NotifyUpdateClients(string guestName,string UpdateInfo);
          [OperationContract(IsOneWay=true)]
          void NotifyRequestMadeToServer(string guestName,string request);
          [OperationContract(IsOneWay=true)]
          void NotifyGuestLeftParty(string guestName);
     }

I have been working for weeks on creating a client/server to control a music-server application located on the server-side that is controlled by several client apps located across the LAN. I've been successful in getting the client-side to communicate with the Server, sending commands to operate the music-server, and through the use of callbacks, reply to the clients so that all of the client UI's can be appropriately updated. My problem is however, that I unable to figure-out how to broadcast other messages that need to be sent from the server app to the clients. I was hoping to utilize the callback method; however I have not been able to access it from the server side. Do I need to modify or create another contract that provides for communication from the server to the clients? Does the binding require modification? As I mentioned earlier, I have truly been working on this for weeks (which is beginning to feel like 'years'), and hope to get this last piece of the application working. Would someone please steer me in the right direction?

Client Side SERVICE REFERENCE:

<?xml version="1.0" encoding="utf-8"?>
<ServiceReference>
<ProxyGenerationParameters
    ServiceReferenceUri="http://localhost:8001/APService/mex"
    Name="APGateway"
    NotifyPropertyChange="True"
    UseObservableCollection="False">
</ProxyGenerationParameters>
<EndPoints>
    <EndPoint
        Address="net.tcp://localhost:8000/APService/service"
        BindingConfiguration="TcpBinding"
        Contract="APClient.APGateway.APUserService"
        >
    </EndPoint>
    <EndPoint
        Address="http://localhost:8001/APService/service"
        BindingConfiguration="HttpBinding"
        Contract="APClient.APGateway.APUserService"
        >
    </EndPoint>
</EndPoints>
</ServiceReference>

Client Side AP CONFIG

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
    <sectionGroup name="applicationSettings" type="System.Configuration.ApplicationSettingsGroup, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
        <section name="APClient.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
    </sectionGroup>
</configSections>
<system.serviceModel>
    <client>
        <endpoint
            address="net.tcp://localhost:8000/APService/service"
            binding="netTcpBinding"
            contract="APClient.APGateway.APUserService"
            name="TcpBinding" />
        <endpoint
            address="http://localhost:8001/APService/service"
            binding="wsDualHttpBinding"
            contract="APClient.APGateway.APUserService"
            name="HttpBinding" />
    </client>
</system.serviceModel>
<applicationSettings>
    <APClient.Properties.Settings>
        <setting name="pathToDatabase" serializeAs="String">
            <value>C:\Users\Bill\Documents\APData\</value>
        </setting>
    </APClient.Properties.Settings>
</applicationSettings>

Server Side AP.CONFIG

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
   <system.serviceModel>
    <behaviors>
      <serviceBehaviors>
        <behavior name="MetadataBehavior">
           <serviceMetadata httpGetEnabled="true" httpGetUrl="http://localhost:8001/APService/mex" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <services>
      <service behaviorConfiguration="MetadataBehavior" name="APService.APService">
        <endpoint address="service" binding="netTcpBinding" name="TcpBinding"
          contract="APService.IAPServiceInventory" />
        <endpoint address="service" binding="wsDualHttpBinding" name="HttpBinding"
         contract="APService.IAPServiceInventory" />
        <endpoint address="mex" binding="mexHttpBinding" name="MexBinding"
          contract="IMetadataExchange" />
        <host>
          <baseAddresses>
            <add baseAddress="net.tcp://localhost:8000/APService/" />
            <add baseAddress="http://localhost:8001/APService/" />
          </baseAddresses>
        </host>
      </service>
    </services>
  </system.serviceModel>
</configuration>

Server Side APSERVICE.CS

namespace APService
{
     [ServiceBehavior(ConcurrencyMode=ConcurrencyMode.Single,InstanceContextMode=InstanceContextMode.PerCall)]
 public class APService : IAPServiceInventory
 {
      private static List<IClientCallback> _callbackList = new List<IClientCallback>();
      private static int _beerInventory = Convert.ToInt32(System.Configuration.ConfigurationManager.AppSettings["InitialBeerInventory"]);
      public APService() {}
      public int SubscribeToServer(string guestName)
      {
           IClientCallback guest = OperationContext.Current.GetCallbackChannel<IClientCallback>();
           if(!_callbackList.Contains(guest)) { _callbackList.Add(guest); }
           else { Console.WriteLine(guest + " is already logged onto the Server."); }
           _callbackList.ForEach(delegate(IClientCallback callback) { callback.NotifyGuestJoinedParty(guestName); });
      }
      public void UpdateClients(string guestName,string UpdateInfo)
      {
           _callbackList.ForEach(delegate(IClientCallback callback) { callback.NotifyUpdateClients(guestName,UpdateInfo); });
      }
      public void SendRequestToServer(string guestName, string request)
      {
           _callbackList.ForEach(delegate(IClientCallback callback) { callback.NotifyRequestMadeToServer(guestName,request); });
           if(request == "Play") { APControl.Play(); }
           else if(request == "Stop") { APControl.Stop(); }
           else if(request == "Pause") { APControl.PlayPause(); }
           else if(request == "Next Track") { APControl.NextTrack(); }
           else if(request == "Previous Track") { APControl.PreviousTrack(); }
           else if(request == "Mute") { APControl.Mute(); }
           else if(request == "Volume Up") { APControl.VolumeUp(5); }
           else if(request == "Volume Down") { APControl.VolumeDown(5); }
      }
      public void CancelServerSubscription(string guestName)   
      {
           IClientCallback guest = OperationContext.Current.GetCallbackChannel<IClientCallback>();
           if(_callbackList.Contains(guest)) { _callbackList.Remove(guest); }
           _callbackList.ForEach(delegate(IClientCallback callback) { callback.NotifyGuestLeftParty(guestName); });
      }
 }

Server Side IAPSERVICE.CS

namespace APService
{
     [ServiceContract(Name="APUserService",Namespace="http://AP.com/WCFClientServer/",SessionMode=SessionMode.Required, CallbackContract=typeof(IClientCallback))]
 public interface IAPServiceInventory
 {
      [OperationContract()]
      int SubscribeToServer(string guestName);
      [OperationContract(IsOneWay=true)]
      void SendRequestToServer(string guestName,string request);
      [OperationContract(IsOneWay=true)]
      void UpdateClients(string guestName,string UpdateInfo);
      [OperationContract(IsOneWay=true)]
      void CancelServerSubscription(string guestName);
 }
 }

Server side - IAPServiceCallback.cs

namespace APService
{
     public interface IClientCallback
     {
          [OperationContract(IsOneWay=true)]
          void NotifyGuestJoinedParty(string guestName);
          [OperationContract(IsOneWay=true)]
          void NotifyUpdateClients(string guestName,string UpdateInfo);
          [OperationContract(IsOneWay=true)]
          void NotifyRequestMadeToServer(string guestName,string request);
          [OperationContract(IsOneWay=true)]
          void NotifyGuestLeftParty(string guestName);
     }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文