[英]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.