我有一个使用WCF服务的Silverlight 2应用程序。这样,它对服务方法的所有调用都使用异步回调。如果在这些调用之一之前或期间服务未运行,服务崩溃或网络中断等,则将按您期望的那样生成异常。问题是,我不知道如何捕获此异常。
-
因为它是一个异步调用,所以我不能用try / catch块package我的begin调用,并且不能让它拾取从该点开始执行程序之后发生的异常。
-
由于服务代理是自动生成的,因此我无法在每个调用EndInvoke的已生成函数(实际显示异常的地方)上放置try / catch块。这些生成的函数在调用堆栈中也被外部代码包围,因此在堆栈中没有其他地方可以放置try / catch。
-
我无法将try / catch放入回调函数中,因为在调用它们之前会发生异常。
-
我的App.xaml.cs中有一个Application_UnhandledException函数,该函数捕获所有未处理的异常。我可以使用它,但这似乎是一种凌乱的方法。我宁愿将此功能保留给真正的意外错误(又称错误),而不是针对我想以特定方式处理的每种情况最终获得该功能中的代码。
我缺少一个明显的解决方案吗?还是使用Application_UnhandledException卡住了?
[编辑]
如下所述,Error属性正是我想要的。让我陷入循环的是这样的事实,即引发了异常并且似乎未捕获到异常,但是执行能够继续进行。它触发Application_UnhandledException事件并导致VS2008中断执行,但是在调试器中继续执行可以继续执行。这不是一个真正的问题,只是看起来很奇怪。
我在服务方法完成的事件处理程序中检查事件args的Error属性。我没有遇到事件处理程序没有被调用的问题。如果服务器关闭,则调用将花费几秒钟,然后返回,并在Error属性中返回ProtocolException。
假设您尝试过此方法,但实际上从未调用过回调,则可以考虑自定义生成的代理类。请参阅本文。
我找到了一个讨论此话题的论坛主题,它提到最佳实践是使用Error属性。在此线程和我自己的经验之间,这是我可以得出的结论:
我希望这是他们将在最终版本中解决的问题之一。
现在,我将使用Error属性,只处理调试器中断执行的过程。如果太烦人了,我可以关闭ProtocolException的异常中断。
n
在WP7上使用XNA时,我发现我别无选择,只能将try / catch手动添加到各种异步End * FunctionName *()方法中。我尝试过的其他任何事情都不会阻止应用程序失败
使用自定义WCF代理生成器是在Silver-light中处理异步异常的好方法。单击此处下载源代码。
使用Silverlight 3,Visual Studio调试器可以捕获这些异常,因此,永远不会到达令人困惑的异常处理程序。但是,在没有调试器的情况下运行时,将按预期方式调用异常处理程序。我猜只要知道这一点就可以。我承认我浪费了几个小时试图弄清楚如何深入了解Silverlight / Wcf / Browser的内部工作原理,以解决我的异常情况。不要去那里。
我不是水管工,所以我决定创建自己的WCF服务类,该类重写由Visual Studio自动生成的类文件" reference.cs"的某些功能,然后我添加了自己的try /捕获块以捕获通信错误。
我创建的类如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
| 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;
}
}
} |
OOpps ....
对不起,我的答案是错误的(MSFT家伙没打过写答案服务回调,是在同一UI线程上调用的),事实是
更多信息:
1 2
| - 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
非常有趣的话题。
您可能会忘记asyn客户端回调上的Application_UnhandledException,原因如下:
Application_UnhandledException仅UI线程上触发的异常可以被Application.UnhandledExceptions
捕获
这意味着...根本不为WCF异步调用:-)调用。
检查来自MSFT的详细回复
http://silverlight.net/forums/t/21828.aspx
您好,Application.UnhandledExceptions只能捕获UI线程上触发的异常。它无法捕获其他线程的异常。您可以尝试解决该问题:在Visual Studio中,从"调试"菜单中选择"异常"。然后检查"公共语言运行时异常"。每当抛出异常时,这将使调试器停止。但是请注意,有时这可能会很烦人,因为即使已经捕获到异常。您可以使用CheckBoxes筛选要捕获的异常。
在我的情况下,好消息是,如果不进行调试,仅在clietn服务回调中处理错误消息就足够了。
谢谢