Корректная обработка службы WCF с использованием фабрики и служебных прокси в C#
У меня есть часть моей программы, которая отправляет мне электронное письмо и / или push-сообщение на мой iphone, когда что-то происходит. Это делается с помощью вызовов двух отдельных служб WCF с использованием MSMQ. Я следовал этому руководству (модель 4.0), чтобы сделать его общим и удобным для тестирования. Мне нравится создание общего канала, но мой вопрос заключается в том, действительно ли прокси-серверы и фабрики каналов действительно закрыты / расположены корректно, или если это взорвется, когда он достигнет 10000 пользовательских сред (что в конечном итоге произойдет). Код отлично работает в моей тестовой среде на 50 пользователей.
Поэтому, пожалуйста, просмотрите следующий код:
Сервисный прокси
public class ServiceProxy<TChannel> : IServiceProxy<TChannel> where TChannel : ICommunicationObject
{
private readonly TChannel InnerChannel;
public ServiceProxy(TChannel innerChannel)
{
this.InnerChannel = innerChannel;
}
public void Execute(Action<TChannel> operation)
{
try
{
operation(InnerChannel);
InnerChannel.Close();
}
catch (CommunicationException)
{
InnerChannel.Abort();
}
catch (TimeoutException)
{
InnerChannel.Abort();
}
catch (Exception)
{
InnerChannel.Abort();
throw;
}
}
public TResult Execute<TResult>(Func<TChannel, TResult> operation)
{
TResult result = default(TResult);
try
{
result = operation(InnerChannel);
InnerChannel.Close();
}
catch (CommunicationException)
{
InnerChannel.Abort();
}
catch (TimeoutException)
{
InnerChannel.Abort();
}
catch (Exception)
{
InnerChannel.Abort();
throw;
}
return result;
}
}
Сервисная Прокси Фабрика
public class ServiceProxyFactory : IServiceProxyFactory
{
public IServiceProxy<TChannel> GetProxy<TChannel>(string endpointName) where TChannel : ICommunicationObject
{
var factory = new ChannelFactory<TChannel>(endpointName);
return new ServiceProxy<TChannel>(factory.CreateChannel());
}
}
Звонок в сервис (для простоты без типа возврата)
public class MessageSender : IMessageSender
{
private const string PushServiceEndpoint = "PushEndpointName";
private const string MailServiceEndpoint = "MailEndpointName";
private readonly IServiceProxyFactory ServiceProxyFactory;
public MessageSender()
{
ServiceProxyFactory = new ServiceProxyFactory();
}
public void NotifyMe(*some args*)
{
ServiceProxyFactory.GetProxy<MailServiceChannel>(MailServiceEndpoint)
.Execute(a => a.SendEmail(*some args*));
}
Вопросы:
Должен ли я закрыть Service Proxy после выполнения?
Разумно ли создавать ChannelFactory каждый раз, когда я вызываю GetProxy(), и должен ли этот ChannelFactory снова закрываться, если это так?
Действительно ли производительность благоприятна для генерации Service Proxy для каждого вызова? (мне кажется, это действительно тяжело, но, возможно, кто-то может доказать, что я не прав)
Я оставил интерфейсы из этого поста, но они действительно просты, и вся эта установка с прокси и интерфейсами действительно хорошо работает с модульным и интеграционным тестированием.
Я надеюсь, что у некоторых из вас есть мастера по программированию, и они поделятся этим.
Заранее спасибо!
1 ответ
Основное влияние на производительность оказывает создание ChannelFactory
,
Создание экземпляров ChannelFactory связано с некоторыми дополнительными затратами, поскольку включает в себя следующие операции: Построение дерева ContractDescription.
Reflecting all of the required CLR types Constructing the channel stack Disposing of resources
https://msdn.microsoft.com/en-us/library/hh314046%28v=vs.110%29.aspx
Команда WCF внедрила кеширование для ClientBase<TChannel>
класс, это подходит, когда у вас есть автоматически сгенерированные прокси-классы. Как вы используете чистый ChannelFactory
Вы должны быть осторожны при создании фабрик при каждом вызове, чтобы иметь лучшую производительность.
Хорошим решением было бы реализовать кэширование ChannelFactory<TChannel>
свой (есть хорошая идея, как это сделать). Так что в конце в вашем ServiceProxyFactory
вместо того, чтобы иметь new ChannelFactory<TChannel>(endpointName);
Вы должны использовать кэшированные экземпляры, такие как CachedChannelFactory<TChannel>.GetInstance()
,
Изменить: Есть еще одна хорошая статья, написанная Мишель Леру Бустаманте, которая объясняет, когда кэшировать или не кэшировать