我想晚总比不晚好……而且看起来作者已经成功了,这可能会对未来的 WCF 用户有所帮助。
1)ChannelFactory对通道进行排列,其中包括通道的所有行为。通过 CreateChannel 方法创建通道会“激活”通道。通道工厂可以被缓存。
2) 您通过绑定和行为来塑造通道工厂。此形状与创建此频道的每个人共享。正如您在评论中指出的,您可以附加消息检查器,但更常见的情况是使用标头将自定义状态信息发送到服务。您可以通过OperationContext.Current附加标头
using (var op = new OperationContextScope((IContextChannel)proxy))
{
var header = new MessageHeader<string>("Some State");
var hout = header.GetUntypedHeader("message", "urn:someNamespace");
OperationContext.Current.OutgoingMessageHeaders.Add(hout);
}
3)这是我处理客户端通道和工厂的一般方法(此方法是我的 ProxyBase 类的一部分)
public virtual void Dispose()
{
CloseChannel();
CloseFactory();
}
protected void CloseChannel()
{
if (((IChannel)_client).State == CommunicationState.Opened)
{
try
{
((IChannel)_client).Close();
}
catch (TimeoutException /* timeout */)
{
// Handle the timeout exception
((IChannel)innerChannel).Abort();
}
catch (CommunicationException /* communicationException */)
{
// Handle the communication exception
((IChannel)_client).Abort();
}
}
}
protected void CloseFactory()
{
if (Factory.State == CommunicationState.Opened)
{
try
{
Factory.Close();
}
catch (TimeoutException /* timeout */)
{
// Handle the timeout exception
Factory.Abort();
}
catch (CommunicationException /* communicationException */)
{
// Handle the communication exception
Factory.Abort();
}
}
}
4)WCF将故障通道而不是工厂。您可以实现重新连接逻辑,但这需要您从某些自定义 ProxyBase 创建并派生客户端,例如
protected I Channel
{
get
{
lock (_channelLock)
{
if (! object.Equals(innerChannel, default(I)))
{
ICommunicationObject channelObject = innerChannel as ICommunicationObject;
if ((channelObject.State == CommunicationState.Faulted) || (channelObject.State == CommunicationState.Closed))
{
// Channel is faulted or closing for some reason, attempt to recreate channel
innerChannel = default(I);
}
}
if (object.Equals(innerChannel, default(I)))
{
Debug.Assert(Factory != null);
innerChannel = Factory.CreateChannel();
((ICommunicationObject)innerChannel).Faulted += new EventHandler(Channel_Faulted);
}
}
return innerChannel;
}
}
5) 不要重复使用通道。打开、做某事、关闭是正常的使用模式。
6) 创建公共代理基类并从中派生所有客户端。这可能会很有帮助,例如重新连接、使用调用前/调用后逻辑、使用工厂中的事件(例如故障、打开)
7) 创建您自己的 CustomChannelFactory 这使您可以进一步控制工厂的行为方式,例如设置默认超时、强制执行各种绑定设置(MaxMessageSizes)等。
public static void SetTimeouts(Binding binding, TimeSpan? timeout = null, TimeSpan? debugTimeout = null)
{
if (timeout == null)
{
timeout = new TimeSpan(0, 0, 1, 0);
}
if (debugTimeout == null)
{
debugTimeout = new TimeSpan(0, 0, 10, 0);
}
if (Debugger.IsAttached)
{
binding.ReceiveTimeout = debugTimeout.Value;
binding.SendTimeout = debugTimeout.Value;
}
else
{
binding.ReceiveTimeout = timeout.Value;
binding.SendTimeout = timeout.Value;
}
}