2012-04-05 65 views
0

我很难将适当的异常处理添加到大量使用Silverlight - JavaScript互操作性的现有代码中。在这种情况下,我的JavaScript可以抛出一个我想在Silverlight中有意义处理的异常。处理来自Silverlight的JavaScript异常

从Silverlight中,我创建一个JavaScript对象的实例,再后来我打电话说对象的方法:

public class MyWrapper 
{ 
    dynamic _myJSObject; 

    public MyWrapper() 
    { 
     _myJSObject = HtmlPage.Window.CreateInstance("MyJSObject"); 
    } 

    public int MyMethod() 
    { 
     try 
     { 
      int result = (int)_myJSObject.MyMethod(); 
     } 
     catch (Exception ex) 
     { 
      // I want to add meaningful exception handling here 
     }  
    } 
} 

每当MyJSObject.MyMethod抛出一个异常,有两个问题:

  • 浏览器显示发生异常的消息。
  • 关于异常的信息不会传递给我的托管代码。相反,我得到一个RuntimeBinderException,它只是说“不能调用非委托类型”,并且不包含任何其他信息。这似乎与here描述的不匹配;我期待InvalidOperationException

我试图避免铸方法的返回值:

object tmp= _myJSObject.MyMethod(); 

这没什么区别。更改JavaScript端引发的异常类型也没有效果。

MyJSObject.prototype.MyMethod = function() 
           { 
            throw "Hello Silverlight!"; 
           } 

我能想到的,现在唯一的办法就是滥用函数的返回值传递关于异常的信息,但是,这将使我的代码一大堆丑陋......这样:

为什么我看到的行为与文档中描述的行为不同?不知怎的,这与我使用dynamic有关吗?我如何正确处理托管代码中JavaScript中发生的异常?

回答

0

经过相当多的实验后,我断定无法直接处理Silverlight中的JavaScript异常。为了能够处理异常,JavaScript代码需要稍微改变。

而不是引发错误的,我回吧:

function MyMethod() 
{ 
    try 
    { 
     // Possible exception here 
    } 
    catch (ex) 
    { 
     return new Error(ex); 
    } 
} 

然后在Silverlight的一面,我周围使用ScriptObject的包装再次开启返回值放入一个例外。这里的关键是TryInvokeMember方法:

public class ScriptObjectWrapper : DynamicObject 
{ 
    private ScriptObject _scriptObject; 

    public ScriptObjectWrapper(ScriptObject scriptObject) 
    { 
     _scriptObject = scriptObject; 
    } 

    public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result) 
    { 
     result = _scriptObject.Invoke(binder.Name, args); 

     ScriptObject s = result as ScriptObject; 
     if (s != null) 
     { 
      // The JavaScript Error object defines name and message properties. 
      string name = s.GetProperty("name") as string; 
      string message = s.GetProperty("message") as string; 
      if (name != null && message != null && name.EndsWith("Error")) 
      { 
       // Customize this to throw a more specific exception type 
       // that also exposed the name property. 
       throw new Exception(message); 
      } 
     } 

     return true; 
    } 

    public override bool TrySetMember(SetMemberBinder binder, object value) 
    { 
     try 
     { 
      _scriptObject.SetProperty(binder.Name, value); 
      return true; 
     } 
     catch 
     { 
      return false; 
     } 
    } 

    public override bool TryGetMember(GetMemberBinder binder, out object result) 
    { 
     try 
     { 
      result = _scriptObject.GetProperty(binder.Name); 
      return true; 
     } 
     catch 
     { 
      result = null; 
      return false; 
     } 
    } 

} 

潜在的,你可以改善这种包装因此它实际上注入的JavaScript的的try-catch机制透明,但在我的情况下,我不得不在JavaScript源代码直接控制,所以有不需要这样做。

只要name属性以Error结尾,就可以使用自定义对象而不是使用内置的JavaScript Error对象。

要使用包装,原代码将变为:

public MyWrapper() 
{ 
    _myJSObject = new ScriptObjectWrapper(
        HtmlPage.Window.CreateInstance("MyJSObject")); 
}