简体   繁体   English

wcf回调参考

[英]wcf callback reference

I have a desktop app with a duplex WCF service, but I have some troubles using the callback. 我有一个带有双工WCF服务的桌面应用程序,但是使用回调存在一些麻烦。

The service is started as following in main of program.cs: 该服务在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));

For the service I created a subscribe function where the callbackchannel is saved in a global variable, then the callback uses that global variable to talk back to the client (there will be only one client connecting). 对于该服务,我创建了一个订阅函数,其中回调通道保存在全局变量中,然后回调使用该全局变量与客户端进行通讯(只有一个客户端在连接)。

IPeriodicCallback callbackClient;

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

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

The thing I want to do now is call the callbackclient from an other class. 我现在想做的是从另一个类中调用callbackclient。 In the other class I created the service as: 在另一个类中,我将服务创建为:

private PeriodicService periodicService = new PeriodicService();

And I try to write data to it using: 我尝试使用以下方法向其中写入数据:

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

However the proxy stays null, I also tried to move the proxy part to the class but this also results in it staying null. 但是,代理保持为空,我也尝试将代理部分移至类,但这也导致其保持为空。

When the client connects I nicely get the message "Client Subscribe" but it seems there are two instances running of the periodicservice. 当客户端连接时,我很好地收到消息“客户端订阅”,但似乎有两个实例正在运行periodicservice。

But my problem is I don't see an other way to access the periodicservice then creating it in my class, or is it also already created by the svcHost? 但是我的问题是我没有看到其他访问周期服务的方法,然后在我的类中创建它,或者它是否已经由svcHost创建?

Can ayone point me in the right direction? 谁能指出我正确的方向?

This repository shows the a duplex WCF imeplementation I made to answer a similar question a while ago, its a full working example with as little extra stuff as possible. 该存储库显示了我之前回答类似问题的双工WCF实现,它是一个完整的工作示例,并尽可能减少了额外的工作量。

https://github.com/Aelphaeis/MyWcfDuplexPipeExample https://github.com/Aelphaeis/MyWcfDuplexPipeExample

Lets say we have a Service Contract like this : 可以说我们有这样的服务合同:

[ServiceContract(CallbackContract = typeof(IMyServiceCallback),SessionMode = SessionMode.Required)]
public interface IMyService
{
    [OperationContract(IsOneWay=true)]
    void DoWork();
}

Note that I specified a CallbackContract. 请注意,我指定了一个CallbackContract。 If you want to make a duplex, you would want to perhaps make your Service Behavior implementation of the above contract like this : 如果要进行双工,则可能希望使上述合同的服务行为实现如下:

[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>();
        }
    }
}

The important thing here is the Callback. 这里重要的是回调。 This is how your service would allow you to access specified to you by the Client. 这就是您的服务将允许您访问客户端指定给您的方式。

You also need to define the callback interface, In my case its quite simple : 您还需要定义回调接口,就我而言,它非常简单:

[ServiceContract]
public interface IMyServiceCallback 
{
    [OperationContract(IsOneWay = true)]
    void WorkComplete();
}

Now I want to create a client to use this Duplex Service. 现在,我想创建一个客户端来使用此双工服务。 The first thing I need to do is implement the IMyServiceCallback. 我需要做的第一件事是实现IMyServiceCallback。 I need to do this on the client. 我需要在客户端上执行此操作。 In this case the implementation is this: 在这种情况下,实现是这样的:

class Callback : IMyServiceCallback
{
    public void WorkComplete()
    {
        Console.WriteLine("Work Complete");
    }
}

Now when I want to open my duplex connection with the services I would create a proxy class like this something like this: 现在,当我想打开与服务的双工连接时,我将创建一个像这样的代理类:

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();
    }
}

Notice that I specified an InstanceContext. 注意,我指定了InstanceContext。 That Instance Context will be an instance of the object I created that implements IMyServiceCallback. 该实例上下文将是我创建的实现IMyServiceCallback的对象的实例。

That's all you need to do! 这就是您需要做的! Simple as that! 就那么简单!

Update : Callback objects are just like any other object. 更新 :回调对象与其他任何对象一样。 You can store them into a collection and iterate through them and based on some condition. 您可以将它们存储到一个集合中,并根据某种条件遍历它们。

One way is to create a property in the IMyServiceCallback that can uniquely identify it. 一种方法是在IMyServiceCallback中创建可以唯一标识它的属性。 When a client connects to the service it can call a method which specifies a callback object which can then be cached or saved for later use. 当客户端连接到服务时,它可以调用一个方法,该方法指定一个回调对象,然后可以将其缓存或保存以供以后使用。 You can then iterate the callbacks and based on some condition you can call a method for a specific client. 然后,您可以迭代回调,并根据某些条件可以为特定客户端调用方法。

This is certainly more complicated; 这当然更加复杂。 however, it is certainly manageable. 但是,它肯定是可管理的。 I will add an example in a bit. 我将添加一个示例。

Update 2 This is a working example of exactly what you want; 更新2这是您想要的实际示例。 however, its a lot more complicated. 但是,它要复杂得多。 I'll try to explain as simply as I can : https://github.com/Aelphaeis/MyWcfDuplexPipeExample/tree/MultiClient 我将尝试尽可能简单地进行解释: https : //github.com/Aelphaeis/MyWcfDuplexPipeExample/tree/MultiClient

Here is a list of the changes: 以下是更改列表:

  • I've modified the client proxy (and service) so that when initialized it calls the init Method 我已经修改了客户端代理(和服务),以便在初始化时调用init方法。
  • I've also modified the Service implementation so that now it is a single instance dealing with all requests (for convenience). 我还修改了Service实现,以便现在它是处理所有请求的单个实例(为方便起见)。
  • I added a new OperationContract in the Service interface called Msg 我在服务接口中添加了一个名为Msg的新OperationContract
  • I've added a new Method in the IMyServiceCallback called RecieveMessage. 我在IMyServiceCallback中添加了一个名为RecieveMessage的新方法。
  • I've added a way to identify the client. 我添加了一种识别客户端的方法。

In the proxy class I have the following : 在代理类中,我有以下内容:

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();
}

In my service I have the following : 为我服务:

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

My IMyServiceCallback has been redefined to : 我的IMyServiceCallback已重新定义为:

[ServiceContract]
public interface IMyServiceCallback 
{
    [OperationContract]
    int GetClientId();

    [OperationContract(IsOneWay = true)]
    void WorkComplete();

    [OperationContract(IsOneWay = true)]
    void RecieveMessage(String msg);
}

By specifying a number, you can contact the client that corresponds with that number. 通过指定一个号码,您可以联系与该号码相对应的客户。 If two clients have the same Id, both clients will be contacted. 如果两个客户具有相同的ID,则将联系这两个客户。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM