C# WCF向所有客户端广播消息
我有一个WCF服务和客户端应用程序——在本例中,我使用命名管道。服务和客户端能够相互通信。我要做的就是使用回调方法向所有客户端广播消息 在服务中,客户端使用两种方法在服务中注册自己:C# WCF向所有客户端广播消息,c#,wcf,message,broadcast,C#,Wcf,Message,Broadcast,我有一个WCF服务和客户端应用程序——在本例中,我使用命名管道。服务和客户端能够相互通信。我要做的就是使用回调方法向所有客户端广播消息 在服务中,客户端使用两种方法在服务中注册自己: public void RegisterInService(Guid clientID) { ICallbacks callback = OperationContext.Current.GetCallbackChannel<ICallbacks>();
public void RegisterInService(Guid clientID)
{
ICallbacks callback = OperationContext.Current.GetCallbackChannel<ICallbacks>();
lock (clients)
{
if (!clients.ContainsKey(clientID))
{
clients.Add(clientID, callback);
}
}
}
用于存储特定客户端信息的字典:
private static Dictionary<Guid, ICallbacks> clients = new Dictionary<Guid, ICallbacks>();
WCF服务行为已按以下方式配置:
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple)]
现在,在服务中,我有另一种方法,比如说更高级的操作。在这个方法中,我想执行另一个方法来向所有注册的客户机广播消息
代码如下:
public void MainProcessActions()
{
SendMessageToAllClients("Send to all clients ...");
}
private void SendMessageToAllClients(string data)
{
StreamWriter file = new System.IO.StreamWriter(@"E:\Temp\ClientsInvokingEvidence.txt", true);
lock (clients)
{
foreach (KeyValuePair<Guid, ICallbacks> client in clients)
{
client.Value.UpdateClientData(data);
file.WriteLine("Invoking method for client ID : {0}", client.Key);
}
}
file.Close();
}
现在,假设内存中有三个客户机实例(一个应用程序执行三次)。一旦我从一个客户机调用方法MainProcessActions()
,回调方法将只针对这个特定的客户机执行。其他客户端似乎忽略了回调方法UpdateClientData(字符串数据)
你们能给我一些建议我怎样才能解决这个问题
简而言之,我希望将数据从服务发送到所有注册的客户端
#编辑
我有一些更新。UpdateClientData(字符串数据)
方法实际上由所有客户端执行。。。问题在于使用从服务接收的数据在Windows窗体中设置TextBox控件
以下是此方法的主体:
public void UpdateClientData(string data)
{
this.DataFromService = data;
}
在代码的后面部分,我将使用属性DataFromService
在MainForm类的TextBox控件中设置文本
看起来TextBox控件的文本只能由客户端的一个实例设置
有趣的是,当我将对TextBox控件的引用传递给实现UpdateClientData
方法的类时,我就能够在所有客户机中同时设置TextBox控件中的文本
有什么建议吗
#编辑
下面是我使用DataFromService属性的代码部分
此属性是以下类的成员:
[CallbackBehavior(UseSynchronizationContext = false)]
class WCFServiceCommunication : ICallbacks
{
public string DataFromService;
...
public WCFServiceCommunication()
{
binding = new NetNamedPipeBinding();
pipeFactory = new DuplexChannelFactory<IGeneralContract>(this, binding, new EndpointAddress("net.pipe://localhost/SomeName"));
pipeProxy = pipeFactory.CreateChannel();
ClientID = Guid.NewGuid();
}
public void ExecuteOnServiceSide()
{
pipeProxy.MainProcessActions();
}
public void RegisterClient()
{
pipeProxy.RegisterInService(ClientID);
}
public void UnregisterClient()
{
pipeProxy.UnregisterFromService(ClientID);
}
public void UpdateClientData(string data)
{
// here I'm able to verify that this method actually has been invoked by service for each instance of the client
DataFromService = data;
}
}
另一件有趣的事。当我将整个服务通信配置(创建通道、回调方法的实现)移动到MainForm类中时,一切都正常工作——我能够为客户机的所有实例设置TextBox
问候 您会说“稍后在代码中,我将使用属性DataFromService在MainForm类的TextBox控件中设置文本。”。你能给我看看这个密码吗?你好,伊戈尔。看看这篇文章——它已经更新了,现在包含了你提到的代码。很抱歉离开了——这是假期。如果问题仍然相关,我建议修改
CallbackBehavior
属性并在那里添加ConcurencyMode=Multiple
(或至少可重入
)。默认情况下,它是single,这意味着当一个线程(uione)正在执行ExecuteOnServiceSide
方法时,回调不会启动。
public void UpdateClientData(string data)
{
this.DataFromService = data;
}
[CallbackBehavior(UseSynchronizationContext = false)]
class WCFServiceCommunication : ICallbacks
{
public string DataFromService;
...
public WCFServiceCommunication()
{
binding = new NetNamedPipeBinding();
pipeFactory = new DuplexChannelFactory<IGeneralContract>(this, binding, new EndpointAddress("net.pipe://localhost/SomeName"));
pipeProxy = pipeFactory.CreateChannel();
ClientID = Guid.NewGuid();
}
public void ExecuteOnServiceSide()
{
pipeProxy.MainProcessActions();
}
public void RegisterClient()
{
pipeProxy.RegisterInService(ClientID);
}
public void UnregisterClient()
{
pipeProxy.UnregisterFromService(ClientID);
}
public void UpdateClientData(string data)
{
// here I'm able to verify that this method actually has been invoked by service for each instance of the client
DataFromService = data;
}
}
class MainForm : Form
{
private WCFServiceCommunication wcfCommunication;
....
public MainForm()
{
InitalizeComponent();
wcfCommunication = new WCFServiceCommunication();
wcfCommunication.RegisterClient();
}
...
private void btnCheckForUpdates_Click(object sender, EventArgs e)
{
// here, on service side method MainProcessActions() is called
// in this method I'm calling broadcast method
wcfCommunication.ExecuteOnServiceSide();
textBox1.Text = wcfCommunication.DataFromService;
}
}