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回调引用

这个存储库显示了一个双工的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,则将联系两个客户端。