Ответ 1
Я думаю, лучше поздно, а потом никогда... и похоже, что автор работает, это может помочь будущим пользователям WCF.
1) ChannelFactory упорядочивает канал, который включает в себя все виды поведения для канала. Создание канала с помощью метода CreateChannel "активирует" канал. Канальные заводы могут кэшироваться.
2) Вы формируете канал factory с привязками и поведением. Эта форма делится со всеми, кто создает этот канал. Как вы отметили в своем комментарии, вы можете прикреплять инспекторов сообщений, но более распространенным случаем является использование заголовка для отправки пользовательской информации о состоянии в службу. Вы можете прикреплять заголовки через 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) Это мой общий способ утилизации клиентского канала и factory (этот метод является частью моего класса 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 будет повреждать канал, а не factory. Вы можете реализовать логику повторного подключения, но это потребует, чтобы вы создавали и выводили своих клиентов из некоторых пользовательских 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) Создайте общий базовый класс прокси и выведите из него всех своих клиентов. Это может быть полезно, например, повторное подключение, используя логику pre-invoke/post invoke, потребляющую события от factory (например, Faulted, Opening)
7) Создайте свой собственный CustomChannelFactory, это даст вам дополнительный контроль над тем, как factory ведет себя, например. Установите тайм-ауты по умолчанию, выполните различные настройки привязки (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;
}
}