【问题标题】:wcf callback referencewcf 回调参考
【发布时间】:2014-07-10 09:40:22
【问题描述】:

我有一个带有双工 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));

对于服务,我创建了一个订阅函数,其中回调通道保存在全局变量中,然后回调使用该全局变量与客户端对话(将只有一个客户端连接)。

IPeriodicCallback callbackClient;

public IPeriodicCallback Proxy
{
     get
     {
        return this.callbackClient;
     }
}

public void joinPeriodicService()
{
    Console.WriteLine("Client subscribe");
    this.callbackClient = OperationContext.Current.GetCallbackChannel<IPeriodicCallback>();
}

我现在要做的是从另一个类调用回调客户端。 在另一个类中,我将服务创建为:

private PeriodicService periodicService = new PeriodicService();

我尝试使用以下方法向其写入数据:

if(this.periodicService.Proxy != null)
{ 
     this.periodicService.Proxy.On1MinuteDataAvailable(tmpPeriod);
}

但是代理保持为空,我也尝试将代理部分移动到类,但这也导致它保持为空。

当客户端连接时,我很好地收到“客户端订阅”消息,但似乎有两个实例正在运行周期性服务。

但我的问题是我没有看到其他访问周期性服务的方法,然后在我的类中创建它,还是它也已经由 svcHost 创建?

谁能指出我正确的方向?

【问题讨论】:

标签: c# wcf callback duplex


【解决方案1】:

此存储库显示了我为回答类似问题而制作的双工 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>();
        }
    }
}

这里重要的是回调。这就是您的服务允许您访问客户端指定给您的方式。

你还需要定义回调接口,在我的例子中它很简单:

[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 实现,现在它是一个处理所有请求的单个实例(为了方便起见)。
  • 我在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,则会联系这两个客户。

【讨论】:

  • 感谢您对双工的非常清晰的解释。问题在于您在同一个类中调用回调的 DoWork() 函数,但我想从程序中的另一个对象调用它。然后如何获取对包含回调函数的对象的引用?因为它似乎是由 svchost 创建的,并且不知道我需要的功能。
  • @GerardvandenBosch 更新完成,希望对您有所帮助
  • Aelphaeis 感谢您的清晰解释,我想我会让它与它一起工作。
猜你喜欢
  • 1970-01-01
  • 2011-08-19
  • 1970-01-01
  • 2018-09-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-04-25
相关资源
最近更新 更多