WCF / Silverlight:我如何犯规?

时间:2011-02-03 22:23:05

标签: silverlight wcf

我被告知我不应该在Silverlight / WCF中缓存频道,因为它们可能会出现故障并且不合适。可以给我看一些可以证明它可能发生的示例代码。

  1. 调用服务以证明连接可以正常工作(即没有虚假URL)
  2. 进行第二次通话,使通道陷入故障状态
  3. 重复第一次通话,这将失败。

1 个答案:

答案 0 :(得分:2)

在我自己的测试中,关键是你使用的绑定是否是面向会话的。如果您正在使用像BasicHttpBinding这样的无状态绑定,那么您可以随心所欲地删除频道,并且您很好。例如,我有一个使用BasicHttpBinding的WCF服务,看起来像这样 - 特别注意SayGoodbye()中的Channel.Abort()调用:

public class HelloWorldService : IHelloWorldService
{
    public string SayHello()
    {
        return "Hello.";
    }

    public string SayGoodbye()
    {
        OperationContext.Current.Channel.Abort();
        return "Goodbye.";
    }
}

Silverlight客户端代码看起来像这样(丑陋地说,对不起)。

public partial class ServiceTestPage : Page
{

    HelloWorldServiceClient client;

    public ServiceTestPage()
    {
        InitializeComponent();
        client = new HelloWorldServiceClient();
        client.SayHelloCompleted += new EventHandler<SayHelloCompletedEventArgs>(client_SayHelloCompleted);
        client.SayGoodbyeCompleted += new EventHandler<SayGoodbyeCompletedEventArgs>(client_SayGoodbyeCompleted);
        client.SayHelloAsync();
    }

    void client_SayHelloCompleted(object sender, SayHelloCompletedEventArgs e)
    {
        if (e.Error == null)
        {
            Debug.WriteLine("Called SayHello() with result: {0}.", e.Result);
            client.SayGoodbyeAsync();
        }
        else
        {
            Debug.WriteLine("Called SayHello() with the error: {0}", e.Error.ToString());
        }
    }

    void client_SayGoodbyeCompleted(object sender, SayGoodbyeCompletedEventArgs e)
    {
        if (e.Error == null)
        {
            Debug.WriteLine("Called SayGoodbye() with result: {0}.");
        }
        else
        {
            Debug.WriteLine("Called SayGoodbye() with the error: {0}", e.Error.ToString());
        }
        client.SayHelloAsync(); // start over
    }

}

只要你愿意,它就会无限循环。

但是如果你使用面向会话的绑定,如Net.TCP或HttpPollingDuplex,你必须对你的频道处理更加小心。如果是这种情况,那么当然你正在缓存你的代理客户端,对吧?您在该实例中需要做的是捕获Channel_Faulted事件,中止客户端,然后重新创建它,当然,重新建立所有事件处理程序。有点痛苦。

另一方面,当谈到使用双工绑定时,我发现的最好的方法(我向其他人开放)就是在我的代理客户端周围创建一个包装器来完成三件事:

(1)将“添加服务引用”对话框生成的令人讨厌的事件引发代码转换为更有用的延续传递模式。

(2)包装从服务器端引发的每个事件,以便客户端可以在我的包装器上订阅事件,而不是代理客户端本身上的事件,因为代理客户端本身可能必须被删除并重新创建。

(3)处理ChannelFaulted事件,并且(多次,超时)尝试重新创建代理客户端。如果成功,它会自动重新订阅其所有事件包装器,如果失败,它会抛出一个真正的 ClientFaulted事件,这实际上意味着“你被搞砸了,稍后再试。”

这很痛苦,因为看起来这应该是首先应该包含在MS生成的代码中的东西。但它确实解决了很多问题。有一天我会看到我是否可以让这个包装器使用T4模板。