/// <summary>
        /// Attempts to execute the provided JavaScript code using a non-pooled JavaScript engine (ie.
        /// creates a new JS engine per-thread). This is because Babel uses a LOT of memory, so we
        /// should completely dispose any engines that have loaded Babel in order to conserve memory.
        ///
        /// If an exception is thrown, retries the execution using a new thread (and hence a new engine)
        /// with a larger maximum stack size.
        /// This is required because JSXTransformer uses a huge stack which ends up being larger
        /// than what ASP.NET allows by default (256 KB).
        /// </summary>
        /// <typeparam name="T">Type to return from JavaScript call</typeparam>
        /// <param name="function">JavaScript function to execute</param>
        /// <param name="args">Arguments to pass to function</param>
        /// <returns>Result returned from JavaScript code</returns>
        public virtual T ExecuteWithBabel <T>(string function, params object[] args)
        {
            var engine = _engineFactory.GetEngineForCurrentThread();

            EnsureBabelLoaded(engine);

#if NET40 || NET45 || NETSTANDARD2_0
            try
            {
                return(engine.CallFunctionReturningJson <T>(function, args));
            }

            catch (Exception)
            {
                // Assume the exception MAY be an "out of stack space" error. Try running the code
                // in a different thread with larger stack. If the same exception occurs, we know
                // it wasn't a stack space issue.
                T         result  = default(T);
                Exception innerEx = null;
                var       thread  = new Thread(() =>
                {
                    // New engine will be created here (as this is a new thread)
                    var threadEngine = _engineFactory.GetEngineForCurrentThread();
                    EnsureBabelLoaded(threadEngine);
                    try
                    {
                        result = threadEngine.CallFunctionReturningJson <T>(function, args);
                    }
                    catch (Exception threadEx)
                    {
                        // Unhandled exceptions in threads kill the whole process.
                        // Pass the exception back to the parent thread to rethrow.
                        innerEx = threadEx;
                    }
                    finally
                    {
                        _engineFactory.DisposeEngineForCurrentThread();
                    }
                }, LARGE_STACK_SIZE);
                thread.Start();
                thread.Join();
                // Rethrow any exceptions that occured in the thread
                if (innerEx != null)
                {
                    throw innerEx;
                }
                return(result);
            }
#else
            return(engine.CallFunctionReturningJson <T>(function, args));
#endif
        }
Exemple #2
0
        /// <summary>
        /// Attempts to execute the provided JavaScript code using the current engine. If an
        /// exception is thrown, retries the execution using a new thread (and hence a new engine)
        /// with a larger maximum stack size.
        /// This is required because JSXTransformer uses a huge stack which ends up being larger
        /// than what ASP.NET allows by default (256 KB).
        /// </summary>
        /// <typeparam name="T">Type to return from JavaScript call</typeparam>
        /// <param name="function">JavaScript function to execute</param>
        /// <param name="args">Arguments to pass to function</param>
        /// <returns>Result returned from JavaScript code</returns>
        public virtual T ExecuteWithLargerStackIfRequired <T>(string function, params object[] args)
        {
            // This hack is not required when pooling JavaScript engines, since pooled MSIE
            // engines already execute on their own thread with a larger stack.
            if (_config.ReuseJavaScriptEngines)
            {
                return(Execute <T>(function, args));
            }

            try
            {
                return(Execute <T>(function, args));
            }
            catch (Exception)
            {
                // Assume the exception MAY be an "out of stack space" error. Try running the code
                // in a different thread with larger stack. If the same exception occurs, we know
                // it wasn't a stack space issue.
                T         result  = default(T);
                Exception innerEx = null;
                var       thread  = new Thread(() =>
                {
                    // New engine will be created here (as this is a new thread)
                    var engine = _engineFactory.GetEngineForCurrentThread();
                    try
                    {
                        result = engine.CallFunction <T>(function, args);
                    }
                    catch (Exception threadEx)
                    {
                        // Unhandled exceptions in threads kill the whole process.
                        // Pass the exception back to the parent thread to rethrow.
                        innerEx = threadEx;
                    }
                    finally
                    {
                        _engineFactory.DisposeEngineForCurrentThread();
                    }
                }, LARGE_STACK_SIZE);
                thread.Start();
                thread.Join();
                // Rethrow any exceptions that occured in the thread
                if (innerEx != null)
                {
                    throw innerEx;
                }
                return(result);
            }
        }