Handling CLR exceptions in JS

Mar 4, 2014 at 5:23 AM
Hi,

I'm using the V8ScriptEngine and am wondering how to handle CLR exceptions.

Right now, the object I use with AddHostObject may throw some exceptions but I haven't found a way to properly handle them. Wrapping the call (in JS) with a try/catch block didn't really help as the CLR exception remains unhandled, and what I seem to catch in JS is a TargetInvocationException, not the exception actually thrown by the CLR object (which, I guess, is down the InnerException stack).

Is there some best practice here?
Thanks in advance,
Thomas
Coordinator
Mar 4, 2014 at 3:02 PM
Hi Thomas,

ClearScript doesn't expose .NET exceptions through the script language's native exception handling mechanism. V8 actually might make this possible, but JScript and VBScript definitely do not.

Instead, we recommend that you expose a function that runs script code inside a .NET try/catch block and returns any caught exception to the script. For example:
engine.Script.tryCatch = new Func<dynamic, object>(func => {
    try {
        return new { returnValue = func() };
    }
    catch (Exception exception) {
        return new { exception = exception.GetBaseException() };
    }
});
Here's an example of how you'd use such a function:
engine.AddHostType("File", typeof(File));
engine.AddHostType("Console", typeof(Console));
engine.Execute(@"
    result = tryCatch(function () {
        return File.ReadAllText('SomeFileName.txt');
    });
    if (result.exception)
        Console.WriteLine(result.exception);
    else
        Console.WriteLine(result.returnValue);
");
Hopefully this solution, or something similar, is practical in your scenario.

Cheers!
Mar 5, 2014 at 4:19 AM
Hi,

Thanks once again for your quick and thorough reply. I guess this method should be usable in my context.

I'd like to take this opportunity to thank you for the outstanding support you're giving to the community, it's rather rare to find this level of support in open-source projects!

Cheers
Thomas
Coordinator
Mar 5, 2014 at 3:28 PM
Thomas,

Your positive feedback is greatly appreciated!

By the way, we're adding a more general version of the tryCatch method above to the ClearScript API.

Thanks for your input, and please let us know if you run into any other issues.
Dec 18, 2014 at 8:48 PM
Edited Dec 19, 2014 at 12:14 AM
I see there was mention of a more general version of this but I don't know where to look for follow-up.

Is there some sort of interface or magic return type we can use to signal the result of an invocation should be turned into a hosted script exception?

e.g.
   public void MyCLRMethod() {
      if (errorCondition) { 
         return new ITurnIntoaScriptingExceptionType('Oops you did something wrong');
      }
   }
script:
  try {
     o.MyClrMethod();
  }
  catch(x) {
     // yay I was handled?
  }
I need a way to raise errors in the .NET world that can be handled by the script (V8).
Coordinator
Dec 19, 2014 at 2:04 PM
Hello!

ClearScript 5.4 does include a generalized version of tryCatch(). Here's an example:
engine.AddHostObject("host", new HostFunctions());
engine.AddHostType("Console", typeof(Console));
engine.AddHostType("WebClient", typeof(WebClient));
engine.Execute(@"
    var webClient = new WebClient();
    host.tryCatch(
        function () {
            // download web document
            Console.WriteLine(webClient.DownloadString('http://cnn.com'));
        },
        function (exception) {
            // dump exception
            Console.WriteLine('*** ERROR: ' + exception.GetBaseException().ToString());
            return true;
        },
        function () {
            // clean up
            Console.WriteLine('*** CLEANING UP ***');
            webClient.Dispose();
        }
    );
");
Please let us know if handling host exceptions this way isn't practical in your scenario. Unlike the older script engines, V8 could probably enable a more natural pattern, although ClearScript currently doesn't support that.

Thanks!
Dec 23, 2014 at 11:07 PM
Edited Dec 23, 2014 at 11:08 PM
I'll see how often it comes up. My app downloads and executes script from the web and 3rd party scripts may try/catch to test for features, but I don't know how much I should care until I hit some cases. I have a feeling the boilerplate above won't work in the scenarios I have in mind, though, if the original script block can't try/catch/continue.

Thanks again for this awesome project and responses to my many questions!
Coordinator
Dec 26, 2014 at 4:06 PM
Hi krisoye,

Thanks for your positive feedback!

I have a feeling the boilerplate above won't work in the scenarios I have in mind, though, if the original script block can't try/catch/continue.

​Actually, if you're using V8, you can catch a host exception using a JavaScript try...catch statement. However, the exception that's delivered to script code currently isn't very useful; its message text is likely to be that of the generic TargetInvocationException, and there's no way to examine the original .NET exception.

We're going to address both of these issues in the next ClearScript point release:
  1. A JavaScript exception that's triggered by a .NET exception will have message text that reflects the root exception.
  2. Such an exception will also have a hostException property that provides access to the .NET exception.
Thanks again!
Dec 26, 2014 at 8:29 PM
Awesome! I had some other issues that were resolved by reading from the forum here. Originally I had exceptions bubbling up and out, but now that I've been able to attach a debugger I can see it hitting the catch block and that it was able to continue on after (presumably after I fixed my other issues). The error message I got was not what I expected ("An expression of type 'System.Boolean' cannot be used to initialize an array of type 'System.Object'") but I don't care too much about that so long as it hits the catch block and continues on.

Thanks again!