Насмешливые родовые асинхронные вызовы WCF ClientChannelWrapper
Недавно я разработал приложение Silverlight, которое использует Mark J MillersClientChannelWrapper<T>
взаимодействовать с сервисным уровнем WCF (эффективно уничтожая ссылку на сервис и упаковывая его IClientChannel
а также ClientChannelFactory
). Вот интерфейс:
public interface IClientChannelWrapper<T> where T : class
{
IAsyncResult BeginInvoke(Func<T, IAsyncResult> function);
void Dispose();
void EndInvoke(Action<T> action);
TResult EndInvoke<TResult>(Func<T, TResult> function);
}
Оболочка в основном использует общий интерфейс асинхронного сервиса (который мог быть создан с помощью slsvcutil или вручную после WCF). ServiceContract
) и упаковывает вызовы, чтобы в случае сбоя канала был создан новый канал. Типичное использование выглядит так:
public WelcomeViewModel(IClientChannelWrapper<IMyWCFAsyncService> service)
{
this.service = service;
this.synchronizationContext = SynchronizationContext.Current ?? new SynchronizationContext();
this.isBusy = true;
this.service.BeginInvoke(m => m.BeginGetCurrentUser(new AsyncCallback(EndGetCurrentUser), null));
}
private void EndGetCurrentUser(IAsyncResult result)
{
string strResult = "";
service.EndInvoke(m => strResult = m.EndGetCurrentUser(result));
this.synchronizationContext.Send(
s =>
{
this.CurrentUserName = strResult;
this.isBusy = false;
}, null);
}
Все работает нормально, но теперь я бы хотел провести модульное тестирование моделей представлений, использующих ClientChannelWrapper
, Я настроил простой модульный тест, используя Moq:
[TestMethod]
public void WhenCreated_ThenRequestUserName()
{
var serviceMock = new Mock<IClientChannelWrapper<IMyWCFAsyncService>>();
var requested = false;
//the following throws an exception
serviceMock.Setup(svc => svc.BeginInvoke(p => p.BeginGetCurrentUser(It.IsAny<AsyncCallback>(), null))).Callback(() => requested = true);
var viewModel = new ViewModels.WelcomeViewModel(serviceMock.Object);
Assert.IsTrue(requested);
}
Я получаю NotSupportedException:
Неподдерживаемое выражение: p => p.BeginGetCurrentUser(IsAny(), null).
Я довольно новичок в Moq, но я думаю, что есть некоторая проблема с ClientChannelWrapper
используя общие сервисные интерфейсы. Попытка обернуть мою голову вокруг этого в течение довольно долгого времени, возможно, у кого-то есть идея. Спасибо.
1 ответ
Извините, что отвечаю на мой вопрос, но я, наконец, получил его. Вот подробности:
Как и часто, решение было прямо передо мной, так как оно было в конкретной реализации Марка Дж. Миллера IClientChannelWrapper. Там он предоставляет два конструктора, один из которых принимает строку имени конечной точки WCF (которую я использую в рабочем коде), а второй:
public ClientChannelWrapper(T service)
{
m_Service = service;
}
Без лишних слов, вот мой новый тестовый код:
[TestMethod]
public void WhenCreated_ThenRequestUserName()
{
var IMySvcMock = new Mock<IMyWCFAsyncService>();
var serviceMock = new ClientChannelWrapper<IMyWCFAsyncService>(IMySvcMock.Object);
var requested = false;
IMySvcMock.Setup(svc => svc.BeginGetCurrentUser(It.IsAny<AsyncCallback>(), null)).Callback(() => requested = true);
var viewModel = new ViewModels.WelcomeViewModel(serviceMock);
Assert.IsTrue(requested);
}
Поэтому я в основном игнорирую интерфейс ChannelWrapper и создаю новый его экземпляр с помощью Mock Object моего интерфейса службы WCF. Затем я настраиваю вызов службы, которая будет использоваться в конструкторе моей модели представления, как показано выше. Теперь все работает как шарм. Я надеюсь, что это будет полезно для кого-то, так как я думаю, что идея ClientChannelWrapper отлично подходит для связи Silverlight <-> WCF. Пожалуйста, не стесняйтесь комментировать это решение!