在Silverlight中捕获WCF异常的最佳方法?

时间:2020-03-06 14:22:26  来源:igfitidea点击:

我有一个正在使用WCF服务的Silverlight 2应用程序。这样,它对服务方法的所有调用都使用异步回调。如果在这些调用之一之前或者期间,该服务未运行,崩溃或者网络中断等,则将按预期生成异常。问题是,我不知道如何捕获此异常。

  • 因为这是一个异步调用,所以我不能用try / catch块包装begin调用,并且不能让它拾取在程序从该点继续执行之后发生的异常。
  • 因为服务代理是自动生成的,所以我不能在每个调用EndInvoke的生成函数上都放置try / catch块(实际上会显示异常)。这些生成的函数在调用堆栈中也被外部代码包围,因此在堆栈中没有其他地方可以放置try / catch。
  • 我不能将try / catch放在回调函数中,因为异常发生在它们被调用之前。
  • 我的App.xaml.cs中有一个Application_UnhandledException函数,该函数捕获所有未处理的异常。我可以使用它,但这似乎是一种凌乱的方法。我宁愿将此功能保留给真正的意外错误(即错误),也不要针对我想以特定方式处理的每种情况都以该功能中的代码结尾。

我是否缺少明显的解决方案?还是我使用Application_UnhandledException卡住了?

[编辑]
如下所述,Error属性正是我想要的。让我陷入循环的是这样的事实,即引发了异常并且似乎未捕获到异常,但是执行能够继续进行。它触发Application_UnhandledException事件并导致VS2008中断执行,但是在调试器中继续执行可以继续执行。这不是一个真正的问题,只是看起来很奇怪。

解决方案

我在服务方法完成的事件处理程序中检查事件args的Error属性。我没有遇到未调用事件处理程序的问题。如果服务器关闭,则调用将花费几秒钟,然后返回,并在Error属性中返回ProtocolException。

假设我们尝试过此方法,但实际上从未调用过回调,则可以考虑自定义生成的代理类。请参阅本文。

我找到了一个讨论此话题的论坛主题,它提到最佳实践是使用Error属性。在此线程和我自己的经验之间,我可以得出以下结论:

  • 在普通的.NET代码中,生成的代理类通过将异常置于Error属性中而不是将其引发来正确处理该异常。
  • 在Silverlight中,生成的代理类设置Error属性,但不能完全处理异常。调试器将拾取异常,该调试器将弹出异常框,并显示消息"用户代码未处理ProtocolException"。尽管有此消息,该异常似乎并未真正出现在Application_UnhandledException函数中。

我希望这是他们将在最终版本中解决的问题之一。

现在,我将使用Error属性,只处理调试器中断执行的过程。如果太烦人了,我可以关闭ProtocolException的异常中断。

我们可以忘记asyn客户端回调上的Application_UnhandledException,原因如下:

Application.UnhandledExceptions只能捕获UI线程上引发的Application_UnhandledExceptions

这意味着...根本不为WCF异步调用:-)调用。

查看来自MSFT的详细回复

http://silverlight.net/forums/t/21828.aspx

我们好,Application.UnhandledExceptions只能捕获UI线程上触发的异常。它无法捕获其他线程的异常。我们可以尝试解决该问题:在Visual Studio中,从"调试"菜单中选择"异常"。然后检查"公共语言运行时异常"。每当抛出异常时,这将使调试器停止。但是请注意,有时这可能会很烦人,因为即使已经捕获到异常。我们可以使用CheckBoxes筛选要捕获的异常。

对于我来说,好消息是,如果不进行调试,仅在clietn服务回调中处理错误消息就足够了。

谢谢

Braulio

哎呀...

对不起,我这边的答案不对(MSFT家伙没打在同一UI线程上调用写答案服务回调),这是

更多信息:

- In development even detaching from the debugger, this method is never reached. 
- On the production environment yes.

我猜想与Visual Studio选项和拦截异常有关。

更多信息,在此线程中
http://silverlight.net/forums/p/48613/186745.aspx#186745

非常有趣的话题。

我不是水管工,所以我决定创建自己的WCF服务类,该类重写由Visual Studio自动生成的类文件" reference.cs"的某些功能,然后向其中添加自己的try / catch块捕获通讯错误。

我创建的类如下所示:

public class myWCFService : MyWCFServiceClient
{

    protected override MyController.MyService.IMyWCFService CreateChannel()
    {
        return new MyWCFServiceClientChannel(this);
    }

}

private class MyWCFServiceClientChannel : ChannelBase<MyController.MyService.IMyWCFService>, MyController.MyService.IMyWCFService
{
    /// <summary>
    /// Channel Constructor
    /// </summary>
    /// <param name="client"></param>
    public MyWCFServiceClientChannel(System.ServiceModel.ClientBase<MyController.MyService.IMyWCFService> client) :
    base(client)
    {
    }
    /// <summary>
    /// Begin Call To RegisterUser
    /// </summary>
    /// <param name="memberInformation"></param>
    /// <param name="callback"></param>
    /// <param name="asyncState"></param>
    /// <returns></returns>
    public System.IAsyncResult BeginRegisterUser(MyDataEntities.MembershipInformation memberInformation, System.AsyncCallback callback, object asyncState)
    {               
        object[] _args = new object[1];
        _args[0] = memberInformation;
        System.IAsyncResult _result = base.BeginInvoke("RegisterUser", _args, callback, asyncState);
        return _result;               
    }
    /// <summary>
    /// Result from RegisterUser
    /// </summary>
    /// <param name="result"></param>
    /// <returns></returns>
    public MyDataEntities.MembershipInformation EndRegisterUser(System.IAsyncResult result)
    {
        try
        {
            object[] _args = new object[0];
            MyDataEntities.MembershipInformation _result = ((MyDataEntities.MembershipInformation)(base.EndInvoke("RegisterUser", _args, result)));
            return _result;
        }
         catch (Exception ex)
        {
            MyDataEntities.MembershipInformation _result = new MyDataEntities.MembershipInformation();
            _result.ValidationInformation.HasErrors = true;
            _result.ValidationInformation.Message = ex.Message;
            return _result;
        }
    }
}

使用Silverlight 3,Visual Studio调试器可以捕获这些异常,因此永远不会达到令人困惑的异常处理程序的目的。但是,在没有调试器的情况下运行时,将按预期方式调用异常处理程序。我想只要有人知道就可以了。我承认我浪费了几个小时试图弄清楚如何深入了解Silverlight / Wcf / Browser的内部工作原理,以解决我的异常情况。不要去那