WCF oneway exception faults channel

馋奶兔 提交于 2019-12-11 12:48:44

问题


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. 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?


回答1:


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 is invoked when application starts off and within method client is added to the list. 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. 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.

EDIT:

I know it has been a while since I posted an answear but I did not find in order to prepare an example. The workaround is to let service's interface derive IConnection and then expose only service as an endpoint. I attach simple example of WCF and WPF app as client. Client's application violates MVVM pattern but in this case it is irrelevant. Download it here.




回答2:


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


来源:https://stackoverflow.com/questions/34284840/wcf-oneway-exception-faults-channel

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!