2012-04-05 6 views
0

У меня возникли проблемы с добавлением правильной обработки исключений к существующему коду, который сильно использует совместимость Silverlight - JavaScript. В этом случае мой JavaScript может генерировать исключение, которое я хочу осмысленно обрабатывать в Silverlight.Обработка исключений JavaScript от Silverlight

С помощью 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

После довольно много экспериментов я пришел к выводу, что нет способа напрямую обработать исключение JavaScript из Silverlight. Чтобы иметь возможность обрабатывать исключение, код 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 механизм примерочных поймать прозрачно, однако в моем случае я имел прямой контроль над исходным кодом JavaScript, так что не было не нужно это делать.

Вместо использования встроенного JavaScript объекта Error, вы можете использовать свои пользовательские объекты, если свойство name заканчивается Error.

Чтобы использовать обертку, исходный код меняется на:

public MyWrapper() 
{ 
    _myJSObject = new ScriptObjectWrapper(
        HtmlPage.Window.CreateInstance("MyJSObject")); 
} 
Смежные вопросы