У меня есть следующая запланированная архитектура для моей клиентской библиотеки WCF:
- использование ChannelFactory вместо сгенерированных svcutil прокси, потому что мне нужно больше контроля, а также я хочу сохранить клиента в отдельной сборке и избежать регенерации при изменении моей службы WCF
- нужно применить поведение с инспектором сообщений к моей конечной точке WCF, чтобы каждый канал мог отправлять свой собственный токен аутентификации
- моя клиентская библиотека будет использоваться из интерфейса MVC, поэтому мне придется подумать о возможных проблемах с потоками
- Я использую .NET 4.5 (может быть, у него есть помощники или новые подходы для лучшей реализации клиентов WCF?)
Я прочитал много статей о различных отдельных частях, но я все еще не понимаю, как правильно собрать все это вместе. У меня есть следующие вопросы:
- как я понимаю, рекомендуется кешировать ChannelFactory в статической переменной, а потом получать из нее каналы, не так ли?
- является ли поведение конечной точки специфичным для всей фабрики ChannelFactory, или я могу применить свое поведение аутентификации для каждого канала отдельно? Если поведение характерно для всей фабрики, это означает, что я не могу хранить какую-либо информацию о состоянии в моих объектах поведения конечной точки, потому что один и тот же токен аутентификации будет повторно использоваться для каждого канала, но, очевидно, я хочу, чтобы каждый канал имел свой собственный токен аутентификации для текущий пользователь. Это означает, что мне нужно будет вычислить токен внутри моего поведения конечной точки (я могу сохранить его в HttpContext, и мое поведение инспектора сообщений просто добавит его в исходящие сообщения).
- мой клиентский класс одноразовый (реализует IDispose). Как правильно расположить канал, зная, что он может быть в любом возможном состоянии (не открыт, открыт, сбой ...)? Я просто утилизирую это? Должен ли я прервать его, а затем утилизировать? Закрыть его (но, возможно, он еще не открылся), а затем утилизировать?
- Что делать, если при работе с каналом возникла какая-то ошибка? Неисправен только канал или вся фабрика ChannelFactory?
Думаю, строка кода говорит больше, чем о тысяче слов, так что вот моя идея в виде кода. Я пометил все свои вопросы выше знаком "???" в коде.
public class MyServiceClient : IDisposable
{
// channel factory cache
private static ChannelFactory<IMyService> _factory;
private static object _lock = new object();
private IMyService _client = null;
private bool _isDisposed = false;
/// <summary>
/// Creates a channel for the service
/// </summary>
public MyServiceClient()
{
lock (_lock)
{
if (_factory == null)
{
// ... set up custom bindings here and get some config values
var endpoint = new EndpointAddress(myServiceUrl);
_factory = new ChannelFactory<IMyService>(binding, endpoint);
// ???? do I add my auth behavior for entire ChannelFactory
// or I can apply it for individual channels when I create them?
}
}
_client = _factory.CreateChannel();
}
public string MyMethod()
{
RequireClientInWorkingState();
try
{
return _client.MyMethod();
}
catch
{
RecoverFromChannelFailure();
throw;
}
}
private void RequireClientInWorkingState()
{
if (_isDisposed)
throw new InvalidOperationException("This client was disposed. Create a new one.");
// ??? is it enough to check for CommunicationState.Opened && Created?
if (state != CommunicationState.Created && state != CommunicationState.Opened)
throw new InvalidOperationException("The client channel is not ready to work. Create a new one.");
}
private void RecoverFromChannelFailure()
{
// ??? is it the best way to check if there was a problem with the channel?
if (((IChannel)_client).State != CommunicationState.Opened)
{
// ??? is it safe to call Abort? won't it throw?
((IChannel)_client).Abort();
}
// ??? and what about ChannelFactory?
// will it still be able to create channels or it also might be broken and must be thrown away?
// In that case, how do I clean up ChannelFactory correctly before creating a new one?
}
#region IDisposable
public void Dispose()
{
// ??? is it how to free the channel correctly?
// I've heard, broken channels might throw when closing
// ??? what if it is not opened yet?
// ??? what if it is in fault state?
try
{
((IChannel)_client).Close();
}
catch
{
((IChannel)_client).Abort();
}
((IDisposable)_client).Dispose();
_client = null;
_isDisposed = true;
}
#endregion
}
lock (_lock){ if (_factory.State != CommunicationState.Opened) {_factory.Abort();_factory = null;}}
; а также у меня есть метод Initialize, который проверяет, исчезла ли фабрика, а затем создает новую. - person JustAMartin   schedule 05.12.2013MessageInterceptorBehavior : IEndpointBehavior, IClientMessageInspector, IDispatchMessageInspector
, в котором есть методы AfterReceiveRequest, которые вызываются WCF как на стороне сервера, так и на стороне клиента. - person JustAMartin   schedule 05.12.2013