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

时间:2008-09-18 17:20:32

标签: wcf silverlight exception

我有一个使用WCF服务的Silverlight 2应用程序。因此,它对所有对服务方法的调用使用异步回调。如果在其中一个调用之前或期间服务未运行,或崩溃,或网络出现故障等,则会产生异常,如您所料。问题是,我不知道如何捕获这个异常。

  • 因为它是一个异步调用,所以我不能用try / catch块包装我的begin调用,并让它接收一个在程序从那一点开始移动后发生的异常。

  • 因为服务代理是自动生成的,所以我不能在每个调用EndInvoke的生成函数上放置一个try / catch块(异常实际显示的位置)。这些生成的函数也被调用堆栈中的外部代码包围,因此堆栈中没有其他地方可以放置try / catch。

  • 我不能把try / catch放在我的回调函数中,因为异常发生在它们被调用之前。

  • 我的App.xaml.cs中有一个Application_UnhandledException函数,它捕获所有未处理的异常。我可以使用它,但这似乎是一种混乱的方式。我宁愿保留这个函数来解决真正意想不到的错误(也就是错误),并且不会在我希望以特定方式处理的每个环境中使用此函数中的代码。

我错过了一个明显的解决方案吗?还是我坚持使用Application_UnhandledException?

[编辑]
如下所述,Error属性正是我所寻找的。抛弃循环的原因是异常被抛出并且似乎未被捕获,但执行能够继续。它触发Application_UnhandledException事件并导致VS2008中断执行,但继续在调试器中允许继续执行。这不是一个真正的问题,它看起来很奇怪。

9 个答案:

答案 0 :(得分:12)

我在服务方法完成事件处理程序中检查事件args的Error属性。我没有遇到没有被调用的事件处理程序的问题。在服务器出现故障的情况下,调用需要几秒钟,然后在Error属性中返回一个ProtocolException。

假设你已经尝试了这个并且你的回调真的永远不会被调用,你可能会考虑自定义生成的代理类。请参阅this article

答案 1 :(得分:5)

我发现a forum thread正在讨论这个问题,它提到最佳做法是使用Error属性。在这个主题和我自己的经历之间,我可以得出结论:

  • 在正常的.NET代码中,生成的代理类通过将异常放在Error属性中而不是抛出它来正确处理异常。

  • 在Silverlight中,生成的代理类设置Error属性,但不完全处理异常。调试器会选择异常,它会弹出异常框,并显示消息“ProtocolException未被用户代码处理”。尽管有这条消息,但异常似乎并没有真正使它成为Application_UnhandledException函数。

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

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

答案 2 :(得分:0)

您可以忘记asyn客户端回调中的 Application_UnhandledException ,原因是:

Application_UnhandledException只有在UI线程上触发的异常才能被Application.UnhandledExceptions捕获

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

检查来自MSFT的详细回复

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

您好,只有在UI线程上触发的异常才能被Application.UnhandledExceptions捕获。它无法捕获其他线程的异常。您可以尝试此操作来解决问题:在Visual Studio中,从“调试”菜单中选择“例外”。然后选中“Common Language Runtime Exceptions”。这将使调试器在抛出异常时停止。但请注意,有时这可能会非常烦人,因为即使已经发现异常。您可以使用CheckBoxes过滤要捕获的异常。

在我的情况下,好消息是,如果您没有调试,只需在clietn服务回调中处理错误消息即可。

由于

Braulio

答案 3 :(得分:0)

... OOpps

抱歉,我身边的错误答案(好的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

非常有趣的主题。

答案 4 :(得分:0)

我不是水管工,所以我决定创建自己的WCF服务类,它覆盖了由Visual Studio自动生成的类文件“reference.cs”的一些功能,然后我添加了自己的try /捕获块以捕获通信错误。

我创建的类看起来像这样:

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

答案 5 :(得分:0)

使用Silverlight 3时,Visual Studio调试器会捕获这些异常,以便永远不会遇到异常处理程序 - 容易混淆。但是,在没有调试器的情况下运行时,将按预期调用异常处理程序。只要有人意识到这一点,我想这是可以的。我承认我浪费了几个小时试图弄清楚如何深入了解Silverlight / Wcf / Browser的内部工作以获得我的例外。不要去那里。

答案 6 :(得分:0)

使用自定义WCF代理生成器是处理Silver-light.Click here中的异步异常以下载源代码的好方法。

答案 7 :(得分:0)

在WP7上使用XNA,我发现我别无选择,只能手动将try / catch添加到各种异步End * FunctionName *()方法中;没有别的我试过会阻止应用程序失败&amp;服务器不可用时关闭。当服务发生变化时,必须手动更新此代码。

我很惊讶这不是一个更大的问题,因为似乎没有任何其他方法可以使用XNA在WP7上捕获这些异常,但我想这只是说更多关于有多少(==不是很多)人试图这样做比什么都重要。如果他们只是让slsvcutil.exe生成同步方法,我们可以轻松地在我们自己的工作线程中捕获这些,但遗憾的是生成的代码使用线程池线程而无法捕获异常。

答案 8 :(得分:0)

要处理此情况,请使用TargetInvocationException。当网络关闭或您的服务不可用时,这将捕获异常。