繁体   English   中英

WCF单向异常故障通道

[英]WCF oneway exception faults channel

我还没有找到明确的答案。 因此,如果已经对此有疑问,我不好。

我有一个WCF服务,该服务通过回调方法将数据推送到连接的客户端。 此回调方法是单向的。 因此,每当有新数据时,我都会遍历连接的用户并推送数据。 我现在遇到的问题是,当客户端断开连接时,它将引发错误并且通道出现故障。 我一直以为,不管消息到达目的地,单向都不在乎。 因此,如果没有客户,那就运气不好。 但也不例外。 但是有一个异常,该异常使通道发生故障。

现在,我在某处读到,如果您启用可靠的会话,则该异常不会使通道出错。 这是真的? 单向呼叫发生异常时,如何防止通道进入故障状态?

您可以存储在某些资源(例如列表)中的已注册和可用客户端的列表。
创建另一个公开Connect / Disconnect方法的接口。 当应用程序启动并将方法客户端添加到列表中时,将调用Connect。 应用程序关闭时依次调用断开连接以摆脱客户端列表。 OnStartup / OnClosing事件或其等效事件,取决于应用程序客户端的类型,是指启动和关闭应用程序的时刻。 这样的解决方案确保资源仅存储可访问的用户。

[ServiceContract]
interface IConnection
{
    [OperationContract(IsOneWay = true)]
    void Connect();

    [OperationContract(IsOneWay = true)]
    void Disconnect();
}

[ServiceContract]
interface IServiceCallback
{
    [OperationContract(IsOneWay = true)]
    void CallbackMethod();
}

[ServiceContract(CallbackContract = typeof(IServiceCallback))]
interface IService
{
    [OperationContract]
    void DoSth();
}

class YourService : IConnection, IService
{
    private static readonly List<IServiceCallback> Clients = new List<IServiceCallback>();

    public void Connect()
    {
        var newClient = OperationContext.Current.GetCallbackChannel<IServiceCallback>();
        if (Clients.All(client => client != newClient))
            Clients.Add(newClient);
    }

    public void Disconnect()
    {
        var client = OperationContext.Current.GetCallbackChannel<IServiceCallback>();
        if (Clients.Any(cl => cl == client))
            Clients.Remove(client);
    }

    public void DoSth()
    {
        foreach(var client in Clients)
            client.CallbackMethod();
    }
}

最后,使用IConnection公开另一个端点,以便客户端可以创建仅用于连接/断开连接的代理。

编辑:

我知道自从发布answear以来已经有一段时间了,但是我没有找到准备示例的方法。 解决方法是让服务的接口派生IConnection,然后仅将服务公开为端点。 我将WCF和WPF应用的简单示例作为客户端。 客户端的应用程序违反了MVVM模式,但在这种情况下无关紧要。 在这里下载。

补充马克西姆斯所说的话。

我已经在一个类中实现了这种模式,在该类中,客户端可以订阅以获取系统内部状态的更新,因此监视客户端可以显示图,而其他客户端则可以执行其他操作(例如,如果某些状态处于活动状态则启用/禁用按钮)。 当它们出现故障时,它将故障通道从列表中删除。 当客户端连接时,还将发送所有当前状态。

这是代码,希望对您有所帮助!

[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple)]
public class Publish : IPublish
{
    private struct SystemState
    {
        public string State;
        public string ExtraInfo;
    }

    private static Dictionary<Key<string>, IPublishCallback> mCallbacks = new Dictionary<Key<string>, IPublishCallback>();

    private static Dictionary<string, SystemState> mStates = new Dictionary<string, SystemState>();

    public void RegisterClient(string name, string system)
    {
        lock (mCallbacks)
        {
            IPublishCallback callback = OperationContext.Current.GetCallbackChannel<IPublishCallback>();

            Key<string> key = new Key<string>(name, system);

            if (!mCallbacks.ContainsKey(key))
            {
                mCallbacks.Add(key, callback);
            }
            else
            {
                mCallbacks[key] = callback;
            }

            foreach (KeyValuePair<string, SystemState> s in mStates)
            {
                mCallbacks[key].ServiceCallback(s.Key, s.Value.State, s.Value.ExtraInfo);
            }
        }
    }

    public void UnregisterClient(string name)
    {
        lock (mCallbacks)
        {
            outer:  foreach (var key in mCallbacks.Keys)
            {
                if (key.Key1 == name)
                {
                    mCallbacks.Remove(key);
                    goto outer;
                }
            }
        }
    }

    public void SetState(string system, string state, string extraInfo)
    {
        lock (mCallbacks)
        {
            List<Key<string>> toRemove = new List<Key<string>>();

            SystemState s = new SystemState() { State = state, ExtraInfo = extraInfo };
            SystemState systemState;
            if (!mStates.TryGetValue(system, out systemState))
                mStates.Add(system, s);
            else
                mStates[system] = s;

            foreach (KeyValuePair<Key<string>, IPublishCallback> callback in mCallbacks)
            {
                try
                {
                    callback.Value.ServiceCallback(system, state, extraInfo);
                }
                catch (CommunicationException ex)
                {
                    toRemove.Add(new Key<string>(callback.Key.Key1, callback.Key.Key2));
                }
                catch
                {
                    toRemove.Add(new Key<string>(callback.Key.Key1, callback.Key.Key2));
                }
            }

            foreach (Key<string> key in toRemove)
                mCallbacks.Remove(key);
        }
    }
}

暂无
暂无

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

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