加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

c# – 如何在通过ChannelFactory创建的WCF服务上设置回调通道?

发布时间:2020-12-15 21:00:13 所属栏目:百科 来源:网络整理
导读:我需要我的WCF服务来向客户端发送事件.我已经读过这是通过回调通道发生的,我已经按照以下方式实现了它: 服务接口: public interface IServiceCallback{ [OperationContract(IsOneWay = true)] void OnNewAlert(Alert a); [OperationContract(IsOneWay = tr
我需要我的WCF服务来向客户端发送事件.我已经读过这是通过回调通道发生的,我已经按照以下方式实现了它:
服务接口:

public interface IServiceCallback
{
    [OperationContract(IsOneWay = true)]
    void OnNewAlert(Alert a);
    [OperationContract(IsOneWay = true)]
    void OnProductEdited(Product p);
    [OperationContract(IsOneWay = true)]
    void OnHighlightChanged(Dictionary<User,List<Product>> highlighted);
    [OperationContract(IsOneWay = true)]
    void OnCatalogUpdated();


    event EventHandler NewAlert;
    event EventHandler ProductEdited;
    event EventHandler HighlightChanged;
    event EventHandler CatalogUpdated;
}
[ServiceContract(CallbackContract = typeof(IServiceCallback))]
public interface IService : IDisposable
{
    [OperationContract]
    List<Product> GetProducts(Predicate<Product> match = null,int limit = 0,string username = null);
    [OperationContract]
    Product GetProduct(Predicate<Product> match,string username = null);
    [OperationContract]
    Product GetRandomProduct(Predicate<Product> match = null,string username = null);
    [OperationContract]
    int GetFlagIndex(string flagName);
    [OperationContract]
    void SetFlag(string pid,string flagName,bool value);
    [OperationContract]
    List<Alert> GetAlerts(string username);
    [OperationContract]
    void DismissAlert(Alert alert,String username);
    [OperationContract]
    void HighlightProduct(List<string> pids,string user);
    [OperationContract]
    void EditProduct(string pid,Dictionary<string,object> fieldValues,string username = null);
    [OperationContract]
    void AttachModule(IModule m);
    [OperationContract]
    void Ping();

    event EventHandler NewAlert;
    event EventHandler ProductEdited;
    event EventHandler HighlightChanged;
    event EventHandler CatalogUpdated;
}

服务实施:

namespace Service
{
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall,ConcurrencyMode = ConcurrencyMode.Reentrant)]
public class ServiceInstance : IService
{
    List<IServiceCallback> callbackChannels = new List<IServiceCallback>();
    //other vars

    public ServiceInstance()
    {
            //lots of stuff here
    }

    private User SignalUser(string username)
    {
        if (username == null)
            return null;

        IServiceCallback channel = OperationContext.Current.GetCallbackChannel<IServiceCallback>();
        if (!callbackChannels.Contains(channel)) //if CallbackChannels not contain current one.
        {
            callbackChannels.Add(channel);
        }

        User user = knownUsers.Find(p => p.username == username);
        if (user == null)
        {
            user = new User();
            user.username = username;
            user.highlighColor = Color.FromArgb(r.Next(0,128),r.Next(0,128));
            knownUsers.Add(user);
            foreach (KeyValuePair<Alert,List<User>> kvp in alerts)
            {
                kvp.Value.Add(user);
            }
        }
        user.lastOnline = DateTime.Now;
        if(!onlineUsers.Contains(user))
            onlineUsers.Add(user);

        return user;
    }

    //lots of other things here
}
}

客户端的回调实现:

class ServiceEventHandler : IServiceCallback
{
    public event EventHandler NewAlert;
    public event EventHandler ProductEdited;
    public event EventHandler HighlightChanged;
    public event EventHandler CatalogUpdated;

    public void OnCatalogUpdated()
    {
        CatalogUpdated?.BeginInvoke(null,null,null);
    }

    public void OnHighlightChanged(Dictionary<User,List<Product>> highlighted)
    {
        HighlightChanged?.BeginInvoke(highlighted,EventArgs.Empty,null);
    }

    public void OnNewAlert(Alert a)
    {
        NewAlert?.BeginInvoke(a,null);
    }

    public void OnProductEdited(Product p)
    {
        ProductEdited?.BeginInvoke(p,null);
    }
}

但这是我的问题:
在客户端,我应该将它传递给这样的服务:

EventHandler eventHandler = new EventHandler();
MyServiceClient client = new MyServiceClient(new InstanceContext(eventHandler));

根据StackOverflow的回答:
https://stackoverflow.com/a/1143777/2018696

但我没有像这样连接到我的服务,因为我的客户端不知道服务的实现,它只知道这两个接口!
所以我这样连接:

public static IService GetService(string serviceAddress)
    {
        Uri service_uri = new Uri(serviceAddress);
        var endpoint = new EndpointAddress(service_uri,new[] { AddressHeader.CreateAddressHeader(settings["username"],"","") });
        IService service = ChannelFactory<IService>.CreateChannel(new BasicHttpBinding(),endpoint);
        return service;
    }

那么如何让回调起作用呢?

更新:

好吧,正如评论所提出的,我用DuplexChannelFactory替换了ChannelFactory,用WsDualHTTPBinding替换了BasicHTTPBinding,我没有得到服务器的响应.如果我刮开回调处理程序,我会得到BasicHTTPBinding的响应.基本上:

[ServiceContract]
BasicHttpBinding();
ChannelFactory<IService>.CreateChannel(binding,endpoint);

^这有效

[ServiceContract(CallbackContract = typeof(IServiceCallback))]
WSDualHttpBinding(WSDualHttpSecurityMode.None);
DuplexChannelFactory<IService>.CreateChannel(new InstanceContext(handler),binding,endpoint);

^这不.

它适用于localhost,但不适用于LAN或Internet.服务器和客户端都禁用防火墙.当我尝试联系服务器时,我得到60秒超时.

解决方法

我发现我的连接问题是由于在客户端的路径上没有设置端口转发.由于我无法确保对客户端进行正确的端口访问,因此我已恢复为非回调模型,并将使用来自客户端的常规请求从服务接收累积的事件数据.可能效率不高,但到目前为止似乎是一种万无一失的方法.谢谢大家的关注.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读