简体   繁体   English

WCF单向异常故障通道

[英]WCF oneway exception faults channel

I haven't found a clear answer on this. 我还没有找到明确的答案。 so if there is already a question about this, my bad. 因此,如果已经对此有疑问,我不好。

I have a WCF service that pushes data via a callback method to connected clients. 我有一个WCF服务,该服务通过回调方法将数据推送到连接的客户端。 this callback method is oneway. 此回调方法是单向的。 so everytime there is new data I loop over the connected users and push the data. 因此,每当有新数据时,我都会遍历连接的用户并推送数据。 The problem I have right now is when a client disconnects it throws an error and the channel becomes faulted. 我现在遇到的问题是,当客户端断开连接时,它将引发错误并且通道出现故障。 I always thought that oneway didn't care if the message arrives at the destination. 我一直以为,不管消息到达目的地,单向都不在乎。 So if there's no client, then bad luck. 因此,如果没有客户,那就运气不好。 but no exception. 但也不例外。 but there is an exception and that exception faults the channel. 但是有一个异常,该异常使通道发生故障。

Now I've read somewhere that if you enable reliable sessions, that the exception won't fault the channel. 现在,我在某处读到,如果您启用可靠的会话,则该异常不会使通道出错。 Is this true? 这是真的? How can I prevent that the channel goes into faulted state when an exception happens on a oneway call? 单向呼叫发生异常时,如何防止通道进入故障状态?

The list of registered and avaiable clients you can store in some resource such as List. 您可以存储在某些资源(例如列表)中的已注册和可用客户端的列表。
Create another interface which exposes Connect/Disconnect methods. 创建另一个公开Connect / Disconnect方法的接口。 Connect is invoked when application starts off and within method client is added to the list. 当应用程序启动并将方法客户端添加到列表中时,将调用Connect。 Disconnect in turn is invoked when application shuts down in order to get rid client of list. 应用程序关闭时依次调用断开连接以摆脱客户端列表。 OnStartup/OnClosing events or their equivalents, depending on what kind of application client is, refer to moment when application is launched and closed. OnStartup / OnClosing事件或其等效事件,取决于应用程序客户端的类型,是指启动和关闭应用程序的时刻。 Such a solution ensures that resource stores only users avaiable to be reached. 这样的解决方案确保资源仅存储可访问的用户。

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

At the end expose another endpoint with IConnection so that client can create proxy meant to be used only for connection/disconnection. 最后,使用IConnection公开另一个端点,以便客户端可以创建仅用于连接/断开连接的代理。

EDIT: 编辑:

I know it has been a while since I posted an answear but I did not find in order to prepare an example. 我知道自从发布answear以来已经有一段时间了,但是我没有找到准备示例的方法。 The workaround is to let service's interface derive IConnection and then expose only service as an endpoint. 解决方法是让服务的接口派生IConnection,然后仅将服务公开为端点。 I attach simple example of WCF and WPF app as client. 我将WCF和WPF应用的简单示例作为客户端。 Client's application violates MVVM pattern but in this case it is irrelevant. 客户端的应用程序违反了MVVM模式,但在这种情况下无关紧要。 Download it here . 在这里下载。

To add on what Maximus said. 补充马克西姆斯所说的话。

I've implemented this pattern in a class where clients can subscribe to get updates of internal states of a system, so a monitoring client can show graphs and other clients do other stuff like enabling/disabling buttons if some state is active. 我已经在一个类中实现了这种模式,在该类中,客户端可以订阅以获取系统内部状态的更新,因此监视客户端可以显示图,而其他客户端则可以执行其他操作(例如,如果某些状态处于活动状态则启用/禁用按钮)。 It removes faulted channels from the list when they fail. 当它们出现故障时,它将故障通道从列表中删除。 Also all current states are sent when a client connects. 当客户端连接时,还将发送所有当前状态。

here's the code, hope it helps! 这是代码,希望对您有所帮助!

[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