几周以来,我一直致力于创建一个客户端/服务器来控制位于服务器端的音乐服务器应用程序,该应用程序由位于 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 配置
<?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);
}