// Procedure executed on background thread to perform a task.
        private static string PerformWork(object stateObj)
        {
            // Get the state object.
            JavascriptCallbackState state = (JavascriptCallbackState)stateObj;

            if (state.Token.IsCancellationRequested)
            {
                return(null);
            }

            int    id            = (int)state.Data;
            string imageResource = String.Format("WPFJavascriptSample.images.alphanumeric-number-{0}.png", id);
            string result        = null;

            // Get the embedded resource of the Awesomium logo.
            var assembly = Assembly.GetExecutingAssembly();
            var info     = assembly.GetManifestResourceInfo(imageResource);

            // The resource does not exist.
            if (info == null)
            {
                return(null);
            }

            if (state.Token.IsCancellationRequested)
            {
                return(null);
            }

            using (var stream = assembly.GetManifestResourceStream(imageResource))
            {
                // Get a byte array of the resource.
                byte[] buffer = new byte[stream.Length];
                stream.Read(buffer, 0, buffer.Length);

                if (state.Token.IsCancellationRequested)
                {
                    return(null);
                }

                result = Convert.ToBase64String(buffer);
            }

            // Throws an OperationCanceledException if this token has had
            // cancellation requested. When a task instance observes an
            // OperationCanceledException thrown by user code, it compares
            // the exception's token to its associated token. If they are the same
            // and the token's IsCancellationRequested property returns true,
            // the task interprets this as acknowledging cancellation and transitions
            // to the Canceled state.
            state.Token.ThrowIfCancellationRequested();

            return(result);
        }
        // Called on the UI thread after the working procedure is complete, or canceled.
        private void SendResponse(Task <String> t)
        {
            using (JavascriptCallbackState state = (JavascriptCallbackState)t.AsyncState)
            {
                if (!webControl.IsLive)
                {
                    return;
                }

                // Check if the user has navigated away,
                // or the operation timed out.
                if (t.IsCanceled)
                {
                    // If we timed out, send an indication.
                    if (state.TimedOut)
                    {
                        InvokeCallback(state.Callback, "ERR_TIMEOUT");
                    }

                    // Disposing the JavascriptCallbackState
                    // will dispose the callback as well.
                    return;
                }

                if ((t.Exception != null) || String.IsNullOrEmpty(t.Result))
                {
                    // The operation failed.
                    // Disposing the JavascriptCallbackState
                    // will dispose the callback as well.
                    return;
                }

                // Invoke the callback. JSObject supports the DLR so for
                // this example we assign to a dynamic which makes invoking the
                // callback, pretty straightforward (just as you would in JS).
                InvokeCallback(state.Callback, t.Result);
            }
        }
        // Handler of the external.app.performHeavyWork method.
        private void OnWork(object sender, JavascriptMethodEventArgs e)
        {
            // Must have 2 arguments passed.
            if (e.Arguments.Length != 3)
            {
                return;
            }

            // Must be a function object.
            if (!e.Arguments[0].IsFunctionObject)
            {
                return;
            }

            // Must be a timeout value.
            if (!e.Arguments[1].IsNumber)
            {
                return;
            }

            // Must be the image id.
            if (!e.Arguments[2].IsNumber)
            {
                return;
            }

            // Get the NavigationInterceptor. This will allow us to cancel the operation
            // if the user navigates away.
            INavigationInterceptor navigationInterceptor = webControl.GetService(typeof(INavigationInterceptor)) as INavigationInterceptor;

            // Without this, do not proceed.
            if (navigationInterceptor == null)
            {
                return;
            }

            // You can cache the callback and call it only when your application
            // has performed all work necessary and has a result ready to send.
            // Note that this callback object is valid for as long as the current
            // page is loaded; a navigation will invalidate it. This is why we
            // need the NavigationInterceptor service acquired above.
            JSFunction callbackArg = e.Arguments[0];
            // Get the image id.
            int id = (int)e.Arguments[1];
            // Get the timeout specified.
            int timeout = (int)e.Arguments[2];

            // Make sure it's a function object.
            if (!callbackArg)
            {
                return;
            }

            // See it!
            Debug.Print(callbackArg.ToString());

            // You need to copy the object if you intend to cache it. The original
            // object argument passed to the handler is destroyed by default when
            // the handler returns. A copy will keep it alive. Note that the clone
            // of a JSFunction, will definitely be a JSFunction as well.
            JSFunction callback = (JSFunction)callbackArg.Clone();

            // Create a state object. This holds the callback and controls
            // cancellation. It is passed to both the background operation procedure
            // and the response procedure.
            JavascriptCallbackState state = new JavascriptCallbackState(navigationInterceptor, callback, id, timeout);

            // Perform your heavy work.
            Task.Factory.StartNew(
                /* The function that will perform the work. */
                (Func <Object, String>)PerformWork,
                /* Pass the state object. */
                state,

                /* The CancellationToken that will let us know if we
                 * should cancel passing back the result. */
                state.Token).ContinueWith(
                /* Send the result when complete. */
                SendResponse,

                /* Make sure the result is sent on the
                 * initial thread. */
                TaskScheduler.FromCurrentSynchronizationContext());
        }