wcf回调引用

时间:2014-07-10 09:40:22

标签: c# wcf callback duplex

我有一个带有双工WCF服务的桌面应用,但是使用回调时遇到了一些麻烦。

该服务在program.cs的主要内容中启动如下:

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,我也尝试将代理部分移动到类,但这也导致它保持为空。

当客户端连接时,我很好地收到消息&#34;客户端订阅&#34;但似乎运行了定期服务有两个实例。

但我的问题是我没有看到另一种访问定期服务的方法,然后在我的课堂上创建它,或者它是否已经由svcHost创建了?

ayone可以指出我正确的方向吗?

1 个答案:

答案 0 :(得分: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>();
        }
    }
}

这里重要的是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实现,现在它是处理所有请求的单个实例(为方便起见)。
  • 我在名为Msg
  • 的服务界面中添加了一个新的OperationContract
  • 我在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,则将联系两个客户。