模拟通用 WCF ClientChannelWrapper 异步调用

发布于 2024-10-19 08:06:21 字数 2405 浏览 2 评论 0原文

我最近开发了一个 Silverlight 应用程序,它使用 Mark J Millers ClientChannelWrapper与 WCF 服务层通信(有效地终止服务引用并包装 IClientChannelClientChannelFactory)。 接口如下:

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 存在一些问题。我已经尝试思考这个问题很长一段时间了,也许有人有想法。谢谢。

I recently developed a Silverlight application which uses Mark J Millers ClientChannelWrapper<T> to communicate with the WCF service layer (effectively killing the service reference and wrapping IClientChannel and ClientChannelFactory).
Here is the interface:

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);
}

The Wrapper basically takes a generic async service interface (which might have been generated by slsvcutil or hand crafted after the WCF ServiceContract) and wraps the calls to ensure that in case of a channel fault, a new channel gets created.
Typical usage looks like this:

 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);
    }

It all works fine but now I'd like to unit test the view models which use the ClientChannelWrapper.
I've set up a simple unit test using 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);
    }

I get a NotSupportedException:

Unsupported expression: p => p.BeginGetCurrentUser(IsAny(), null).

I'm pretty new to Moq but I guess there is some problem with the ClientChannelWrapper using generic Service interfaces. Trying to wrap my head around this for quite some time now, maybe someone has an idea. Thank you.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

作业与我同在 2024-10-26 08:06:21

很抱歉回答我自己的问题,但我终于明白了。
详细信息如下:

一如既往,解决方案就在我面前,因为它是 Mark J Miller 的 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 的接口,使用我的 WCF 服务接口的模拟对象创建它的新实例。然后,我设置对服务的调用,该服务将在视图模型的构造函数中使用,如上所示。现在一切都像魅力一样。我希望这对某人有用,因为我认为 ClientChannelWrapper 的想法对于 Silverlight 来说很棒 <-> WCF 通信。请随时对此解决方案发表评论!

Sorry to answer my own question, but I finally got it.
Here are the details:

As so often, the solution was right in front of me since it was in Mark J Millers concrete implementation of the IClientChannelWrapper. In there he provides two constructors, one taking in a string of the WCF endpoint name (which I use in production code) and a second one:

public ClientChannelWrapper(T service)
    {
        m_Service = service;
    }

Without further ado, here's my new test code:

[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);
    }

So I basically ignore the interface of the ChannelWrapper and create a new instance of it with the Mock Object of my WCF service interface. Then I setup the call to the service which will be used in the constructor of my view model as shown above. Everything works like a charm now. I hope this is useful for someone since I think the idea the of the ClientChannelWrapper is great for Silverlight <-> WCF communication. Please feel free to comment on this solution!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文