Я использовал вариант ответа , связанный с комментарием Марка и этой статьи здесь , чтобы найти решение, которое сработало для меня.
С учетом контракта на обслуживание, который вы определили, на шаге 1 будет определен интерфейс, реализующий ваш сервис, и IClientChannel
.
// Service Contract
public interface ICalculator
{
Add(double a, double b);
}
// Interface to expose Close and Abort
public interface ICalculatorChannel : ICalculator, IClientChannel { }
Шаг 2 включает создание кода многократного использования, который будет обрабатывать создание прокси-серверов и реализацию кода для закрытия или прерывания соединений.
public class ServiceClient<T> where T : class, IClientChannel
{
private ProxyGenerator _generator = new ProxyGenerator();
public T CreateProxy(string endpointConfigurationName)
{
return _generator.CreateInterfaceProxyWithoutTarget<T>
(new WcfInterceptor<T>(endpointConfigurationName));
}
}
T в ServiceClient<T>
примет ICalculatorChannel
, определенный на шаге 1. ProxyGenerator является частью проекта Castle. Здесь он используется для перехвата вызовов службы WCF и выполнения действий до и после публикации.
public class WcfInterceptor<T> : IInterceptor where T : IClientChannel
{
private ChannelFactory<T> _factory = null;
public WcfInterceptor(string endpointConfigurationName)
{
_factory = new ChannelFactory<T>(endpointConfigurationName);
}
public void Intercept(IInvocation invocation)
{
T channel = _factory.CreateChannel();
try
{
invocation.ReturnValue = invocation.Method.Invoke
(channel, invocation.Arguments);
}
finally
{
closeChannel(channel);
}
}
}
Как видите, метод Intercept инкапсулирует канал и вызов для закрытия канала. Метод closeChannel
будет обрабатывать решение о вызове Close()
или Abort()
.
private void closeChannel(T channel)
{
if (channel != null)
{
try
{
if (channel.State != CommunicationState.Faulted)
{
channel.Close();
}
else
{
channel.Abort();
}
}
catch
{
channel.Abort();
}
}
}
Теперь мы создаем класс, чтобы завершить использование этого ServiceClient.
public class Calculator : ICalculator
{
private var _calcualtor = new ServiceClient<ICalculatorChannel>();
public void Add(double a, double b)
{
var proxy = _calculator.CreateProxy("endpointConfigGoesHere");
return proxy.Add(a, b);
}
}
Обратите внимание, что реализация add больше не связана с проблемами соединения WCF. Класс потребления должен знать только о договоре на обслуживание. Ужасность работы с неисправными соединениями теперь о нас заботится класс ServiceClient
.
Теперь клиенту нужна только одна зависимость.
public class MyClient
{
private ICalculator _calculator;
public MyClient(ICalculator calculator)
{
_calculator = calculator;
}
}
И МОК может заполнить клиента:
Bind<ICalculator>().To<Calculator>();