WCF回调引用
本文关键字:引用 回调 WCF | 更新日期: 2023-09-27 18:12:13
我有一个带有双工WCF服务的桌面应用程序,但是我在使用回调时遇到了一些麻烦。
在program.cs的main中启动服务:
ServiceHost svcHost = new ServiceHost(typeof(PeriodicService));
svcHost.Open();
Console.WriteLine("Available Endpoints :'n");
svcHost.Description.Endpoints.ToList().ForEach(endpoint => Console.WriteLine(endpoint.Address.ToString() + " -- " + endpoint.Name));
对于服务,我创建了一个订阅函数,其中callbackchannel保存在一个全局变量中,然后回调使用该全局变量与客户端进行对话(将只有一个客户端连接)。
IPeriodicCallback callbackClient;
public IPeriodicCallback Proxy
{
get
{
return this.callbackClient;
}
}
public void joinPeriodicService()
{
Console.WriteLine("Client subscribe");
this.callbackClient = OperationContext.Current.GetCallbackChannel<IPeriodicCallback>();
}
我现在要做的是从另一个类调用callbackclient。在另一个类中,我将服务创建为:
private PeriodicService periodicService = new PeriodicService();
我试着用
向它写入数据if(this.periodicService.Proxy != null)
{
this.periodicService.Proxy.On1MinuteDataAvailable(tmpPeriod);
}
然而,代理保持null,我也试图将代理部分移动到类,但这也导致它保持null。
当客户端连接时,我很好地得到消息"客户订阅",但似乎有两个实例运行的周期性服务。
但我的问题是,我没有看到另一种方式来访问周期性服务,然后在我的类中创建它,或者它也已经由svcHost创建?
谁能给我指个方向吗?这个存储库显示了一个双工的WCF实现,我在一段时间前回答了一个类似的问题,它是一个完整的工作示例,尽可能少地添加了额外的东西。
https://github.com/Aelphaeis/MyWcfDuplexPipeExample假设我们有一个这样的服务契约:
[ServiceContract(CallbackContract = typeof(IMyServiceCallback),SessionMode = SessionMode.Required)]
public interface IMyService
{
[OperationContract(IsOneWay=true)]
void DoWork();
}
注意,我指定了一个CallbackContract。如果你想做一个双工,你可能想让上面契约的服务行为实现像这样:
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
public class MyService : IMyService
{
public void DoWork()
{
Console.WriteLine("Hello World");
Callback.WorkComplete();
}
IMyServiceCallback Callback
{
get
{
return OperationContext.Current.GetCallbackChannel<IMyServiceCallback>();
}
}
}
这里重要的是Callback。这就是您的服务允许您访问客户端指定给您的方式。
你还需要定义回调接口,在我的例子中它很简单:
[ServiceContract]
public interface IMyServiceCallback
{
[OperationContract(IsOneWay = true)]
void WorkComplete();
}
现在我想创建一个客户端来使用这个双工服务。我需要做的第一件事是实现IMyServiceCallback。我需要在客户端做这个。在本例中,实现如下:
class Callback : IMyServiceCallback
{
public void WorkComplete()
{
Console.WriteLine("Work Complete");
}
}
现在,当我想打开与服务的双工连接时,我将创建一个像这样的代理类,像这样:
public class MyServiceClient: IMyService, IDisposable
{
DuplexChannelFactory<IMyService> myServiceFactory { get; set; }
public MyServiceClient(IMyServiceCallback Callback)
{
InstanceContext site = new InstanceContext(Callback);
NetNamedPipeBinding binding = new NetNamedPipeBinding();
EndpointAddress endpointAddress = new EndpointAddress(Constants.myPipeService + @"/" + Constants.myPipeServiceName);
myServiceFactory = new DuplexChannelFactory<IMyService>(site, binding, endpointAddress);
}
public void DoWork()
{
myServiceFactory.CreateChannel().DoWork();
}
public void Dispose()
{
myServiceFactory.Close();
}
}
注意我指定了一个InstanceContext。那个实例上下文将是我创建的实现IMyServiceCallback的对象的一个实例。
这就是你所需要做的!就是这么简单!
:回调对象就像任何其他对象一样。您可以将它们存储到一个集合中,并根据某些条件遍历它们。
一种方法是在IMyServiceCallback中创建一个可以唯一标识它的属性。当客户端连接到服务时,它可以调用一个方法,该方法指定一个回调对象,该对象可以被缓存或保存以供以后使用。然后,您可以迭代回调,并基于某些条件为特定客户端调用方法。这当然更复杂;然而,这当然是可控的。我将添加一个例子在一点。
更新2 这就是你想要的一个有效的例子;然而,它要复杂得多。我将尽可能简单地解释:https://github.com/Aelphaeis/MyWcfDuplexPipeExample/tree/MultiClient
以下是更改列表:
- 我已经修改了客户端代理(和服务),以便在初始化时调用init方法
- 我还修改了服务实现,现在它是一个单独的实例处理所有的请求(为了方便)。
- 我在Service接口中添加了一个新的OperationContract,叫做Msg
- 我在IMyServiceCallback中添加了一个新方法,叫做RecieveMessage。
- 我添加了一种识别客户端的方法。
在代理类中,我有以下内容:
public MyServiceClient(IMyServiceCallback Callback)
{
InstanceContext site = new InstanceContext(Callback);
NetNamedPipeBinding binding = new NetNamedPipeBinding();
EndpointAddress endpointAddress = new EndpointAddress(Constants.myPipeService + @"/" + Constants.myPipeServiceName);
myServiceFactory = new DuplexChannelFactory<IMyService>(site, binding, endpointAddress);
Init();
}
public void Init()
{
myServiceFactory.CreateChannel().Init();
}
在我的服务中有以下几点:
public class MyService : IMyService
{
public List<IMyServiceCallback> Callbacks { get; private set; }
public MyService(){
Callbacks = new List<IMyServiceCallback>();
}
public void Init()
{
Callbacks.Add(Callback);
}
// and so on
我的IMyServiceCallback已被重新定义为:
[ServiceContract]
public interface IMyServiceCallback
{
[OperationContract]
int GetClientId();
[OperationContract(IsOneWay = true)]
void WorkComplete();
[OperationContract(IsOneWay = true)]
void RecieveMessage(String msg);
}
通过指定号码,您可以联系与该号码对应的客户端。如果两个客户端具有相同的Id,则将联系两个客户端。