Contact   •   Products   •   Search

Rick Strahl's Web Log

Wind, waves, code and everything in between...
ASP.NET • C# • HTML5 • JavaScript • AngularJs

Evaluating JavaScript code from C#


As was going through my JSON Serialization code the other day I kept re-thinking this idea I had some time ago: Why not use Microsoft’s built in JavaScript engine to perform the JavaScript and JSON deserialization. After all there is an official Microsoft JavaScript .NET language and it should be possible to take advantage of this from within an application. I finally had some time to check this out...

 

I started searching for how to do this and there’s not a heck of a lot of information available on this so I started playing around with this on my own. The good news is that it’s pretty straight forward to evaluate JavaScript code, the bad news is that for what I really need it for it doesn’t work quite right.

 

In order to use JScript you need to add a reference to the the Microsoft.vsa assembly.

<add assembly="Microsoft.Vsa, Version=8.0.0.0, Culture=neutral, PublicKeyToken=B03F5F7F11D50A3A"/></assemblies>

First here are a few eval scenarios and how you can call them from a bit of C# code in ASP.NET:

using Microsoft.JScript;

public partial class JavaScriptEval :  System.Web.UI.Page

{

    public static Microsoft.JScript.Vsa.VsaEngine Engine = Microsoft.JScript.Vsa.VsaEngine.CreateEngine();

 

    public static object EvalJScript(string JScript)

    {

        object Result = null;

        try

        {

            Result = Microsoft.JScript.Eval.JScriptEvaluate(JScript, Engine);

        }

        catch (Exception ex)

        {

            return ex.Message;

        }

 

        return Result;

    }

   

    public void Page_Load(object sender,EventArgs e)

    {

        // *** String Value

        object Result = EvalJScript(@"('hello world: ' + new Date())");

        Response.Write( Result.ToString() );

        Response.Write(" Type: " + Result.GetType().Name);

        Response.Write("<hr>");

 

        // *** Return an integer or numeric - no conversion required

        Result = EvalJScript(@"( 11 * 12)");

        Response.Write(Result.ToString());

        Response.Write(" Type: " + Result.GetType().Name);

        Response.Write("<hr>");

       

        // *** Date value - must be converted!

        Result = EvalJScript(@"(new Date())");

        Response.Write(Result);

        Response.Write(" - Type: " + Result.GetType().Name + "<br>");

       

        // *** Must convert from DateObject to DateTime by coercing

        DateObject dateObject = Result as DateObject;

              

        Result = Microsoft.JScript.Convert.Coerce(Result,typeof(DateTime));

        Response.Write("Converted to DateTime: "  + Result);

        Response.Write("<hr>");

                      

       

        // *** Block of code (last assignment is the return value)

        Result = EvalJScript(@"var out = 'hello';   for ( var x = 1; x < 10; x++) { out = out + 'Line ' + x  + '<br>'; }");

        Response.Write(Result);

        Response.Write(" - Type: " + Result.GetType().Name);

        Response.Write("<hr>");

 

        /// *** Closure - calling a JavaScript Function with return value

        Result = EvalJScript(@"( function Test(inputParm) {  return 'hello world ' + inputParm; } )");

 

        /// *** Invoke the function and retrieve the result

        Closure close = Result as Closure;

 

        // *** This requires full trust

        Result = close.Invoke(close, new object[1] { "Start with this bub..." });

        Response.Write(Result);

        Response.Write(" - Type: " + Result.GetType().Name);

        Response.Write("<hr>");

 

        // *** JSON style object

        Result = EvalJScript(@"( {""timeString"":'Time is: ' + new Date(),""dateValue"":new Date()} )");

 

        JSObject obj = Result as JSObject;

        Response.Write(Result);

       

        // *** JavaScript style property array access can be used

        object val = obj["dateValue"];

       

        Response.Write(Microsoft.JScript.Convert.Coerce(val,typeof(DateTime)));

 

        val = obj["timeString"];

       

        Response.Write(val);        

    }       

}

 

As you can see execution of simple bits of code is pretty straight forward. If you need to evaluate an expression that returns a simple type like string, bool or numeric you can simply eval the expression and you get the right value and type back.

 

If you eval something that results in a date however things get more tricky already. You basically need to coerce the JavaScript date into a .NET date. It’s fairly easy to do this luckily – and it might be a decent solution to the lousy kind of code you have to write to deal with all the different date formats available in JSON (new Date() syntax allows for string values, numeric values all in various format). This is somewhat useful.

 

More interesting is the ability to execute a whole block of code. There are a few ways to do this. You can simply pass the code directly and execute it which works just fine. The problem with this is that you can’t directly return a value. Instead the last assignment ends up as your return value. This is similar to the behavior you see in event handlers like onclick in Web pages where you sometimes get unexpected results if you don’t explicitly return a value. This is probably the best choice even though it’s a bit unconventional.

 

Result = EvalJScript(@"( function Test(inputParm) {  return 'hello world ' + inputParm; } )");

 

What happens here is that rather than returning you an evaluated result the parser returns you the closure – ie. essentially a function pointer. You can now use Reflection to execute the Result which is a little more involved:

Closure close = Result as Closure;

Result = close.Invoke(close, new object[1] { "Start with this bub..." });

 

This works fine, but it requires full Reflection rights in order to be able to access this anonymous function. The closure is treated like a private/internal/protected member by Reflection and so you need Full trust in ASP.NET to execute this code. Bummer – this would be the most natural way to execute code because you’d have the ability to pass in parameter and get a return value using standard .NET Reflection logic. But given the rights issues this is probably not an option. I can’t figure out any other way to pass a parameter into the parser.

 

Next, there’s the actual issue I was after: Being able to pass an arbitrary object (in JSON style format) in and get this object back in some way to that can be parsed in .NET.

 

Result = EvalJScript(@"( {""timeString"":'Time is: ' + new Date(),""dateValue"":new Date()} )");

 

This returns a JavaScript object which can then be parsed with typical JavaScript member arrays syntax:

 

Result = EvalJScript(@"( {""timeString"":'Time is: ' + new Date(),""dateValue"":new Date()} )");

 

JSObject obj = Result as JSObject;

foreach ( string FieldName in obj)

{

   object FieldVal = obj[FieldName];

   Response.Write( FieldVal.ToString() + " - "  + FieldVal.GetType().ToString() + "<br>");

}

 

This works and you can potentially parse out the different types , but that still leaves the issue of how to get an actual object from the JavaScript object or more specifically how to ‘cast’ this object to another object.

 

I’m just thinking out loud here <s>:

 

Say you have a JSON method you call and you have a method which takes an object as a strongly typed object parameter:

 

Public bool SaveCustomer(CustomerEntity Customer)

 

I suppose one could use the Customer object as the ‘schema’ and walk through that object with Reflection and then pull values from the JavaScript with the code above and then assign them.

 

I took a closer look at what MS Ajax is doing – and well they’re manually parsing the javascript which is fine, but MS AJAX doesn’t work with a lot of types and doesn’t work of generic type value returned at all – any object structure must exist on the client before it can be passed back (that’s what that long Proxy block for a class definition does basically – it creates type definitions for any parameters and return values).

 

 

I have my own JSON parsing code and it works reasonably well against a wide variety of types generically using a mechanism similar to the above but by parsing string values. But the code is pretty messy and it can easily be broken by some funky JSON formatting. It would be much nicer to leave this sort of thing to a  JavaScript parser.

 

OTOH, manually parsing is probably a safer solution. Using the JSCript parser as shown above actually executes code on the server. If you take a JSON input and do that there’s a lot of potential for security issues.

 

Actually it’s surprising that the Jscript Eval works at all under a limited trust environment.

 

Anyway it’s an interesting experiment but for my needs probably a dead end. But these samples might help someone trying to add JavaScript support to a .NET app out or at least get them started.

Make Donation
Posted in .NET  ASP.NET  AJAX  


Feedback for this Post

 
# re: Evaluating JavaScript code from C#
by Steve February 14, 2007 @ 4:24am
Not sure if this helps, but have you looked at Script# ?
# re: Evaluating JavaScript code from C#
by Bertrand Le Roy February 14, 2007 @ 11:40am
Yes, it seems to me like the security implications of doing that are just too scary. Plus, eval is not the fastest thing and I'm pretty sure custom parsing code is a gazillion times faster.
# re: Evaluating JavaScript code from C#
by Rick Strahl February 14, 2007 @ 2:31pm
Steve, yes I've looked at Script# and it's slick, but it doesn't really address this generic execution scenario. Script# is very cool and Nikhil keeps improving it but unfortunately it's not finding an official place in the Microsoft line...

Bertrand - I wonder about the performance execution aspect though. The evaluation in JavaScript natively ought to be reasonably fast. As you probably know parsing JSON string data isn't exactly trivial because of a variety of nesting and decoding issues you have to deal with. So parsing JSON is fairly resource intensive.
# re: Evaluating JavaScript code from C#
by Bertrand Le Roy February 14, 2007 @ 3:35pm
Sure, but parsing the general JavaScript syntax is no trivial task either. I'd think that a specialized parser, if done right will always be faster than a general one. I guess you'd have to benchmark that. Wanna take bets?
# re: Evaluating JavaScript code from C#
by Joe March 05, 2007 @ 4:50pm
Rick,
I used a similar technique in ASP.Net 1.1. When I converted to 2.0 I noticed the VSA library was marked obsolete. So I searched for a way to eval basic javascript expressions. (I was looking for something that would simply return True or False base on whatever I passed in to it.)

We had a problem with the 'Microsoft.JScript.Vsa.VsaEngine' code in ValruleFilters because Microsoft deprecated it and made it obsolete.

They recommended you use the ICodeDomCompiler interface to build code on the fly instead.
I took a look at it and it is very complex.

I came up with a much simpler solution instead.

I built a .dll file using javascript and then compiled it using the javascript compiler which is available in a VS2005 command prompt.

Once we have the .dll we simply add it to the \Support folder and then referenced it in the project which needed to eval javascript stateemnts.

We call it like this:

Dim jScriptEvaluator As New EvalClass
Dim objResult As Object
objResult = jScriptEvaluator.Evaluate(“1==1 && 2==2”)

This is *much* simpler and safer than ICodeDom.
======================================================================
Warning

'Microsoft.JScript.Vsa.VsaEngine' is obsolete:
'Use of this type is not recommended because it is being deprecated in Visual Studio 2005;
there will be no replacement for this feature. Please see the ICodeCompiler documentation for additional help.'

======================================================================

Detailed Steps to create a .dll:

1. Create a file in Notepad with only these contents:

class EvalClass { function Evaluate(expression: String) { return eval(expression); } }

2. Save the file as C:\MyEval.js

3. Open a VS2005 Command Prompt (Start, Programs, VS2005, VS2005 Tools)

4. Type Cd\ to get to C:\

5. Type
jsc /t:library C:\MyEval.js

6. A new file is created named MyEval.dll.

7. Copy MyEval.dll to the project and reference it (also reference Microsoft.Jscript.dll).

8. Then you should be able to call it like this:

Dim jScriptEvaluator As New EvalClass
Dim objResult As Object
objResult = jScriptEvaluator.Evaluate(“1==1 && 2==2”)

objResult is True.
# DotNetSlackers: Evaluating JavaScript code from C#
by DotNetSlackers Latest ASP.NET News April 19, 2007 @ 10:36pm
# First: Principles
by First: Principles April 24, 2007 @ 1:41am
# First: Principles: Javascript testing with NUnit
by First: Principles April 25, 2007 @ 5:50am
# 在C#中解析JavaScript代码 | Zeal Blog - 泽欧里的网络日志
by Zeal Blog - 泽欧里的网络日志 April 29, 2007 @ 11:10pm
# JScriptEvaluate is obsolete!! - ASP.NET Forums
by ASP.NET Forums May 22, 2007 @ 7:44am
# Rick Strahl's Web Log
by Rick Strahl's Web Log June 23, 2007 @ 6:02pm
# DynamicMethod from C# code? - Rick Strahl's Web Log
by Rick Strahl's Web Log July 17, 2007 @ 10:41am
I'm experimenting with DynamicMethod in .NET 2.0 in light of all the good things that apparently have come of it especially in light of the recent release of the Dynamic Language Runtime on CodePlex. I haven't dug into that code (I suspect it won't be light reading &lt;s&gt;), but thought it sure...
# re: Evaluating JavaScript code from C#
by Pao November 14, 2007 @ 7:43am

how can we apply it to javascript confirm() function that will return value upon click 'true/false'.

Many Thanks!
# re: Evaluating JavaScript code from C#
by daniel February 20, 2008 @ 3:42pm
Thanks for the snippet!
# re: Evaluating JavaScript code from C#
by daniel February 20, 2008 @ 4:12pm
There is also a Microsoft.JScript.Import class works just like Eval, for importing namespaces while the engine is running.

thanks!
D
# re: Evaluating JavaScript code from C#
by Mounir March 21, 2008 @ 3:24am
Hi! I want to my script to create a HTMLTableElement which I wanna use it later. So I tried this: Result = EvalJScript("document.createElement(\"TABLE\"); "); But I got this value in Result: "Variable 'document' has not been declared".

How can I create an HTMLElement object using this VsaEngine ??
# re: Evaluating JavaScript code from C#
by Dwipayan Das May 08, 2008 @ 2:47am

Hi

Your article is very much helpful.Before i am using a webbrowser control on a form and executing all the script files.Now i am running it directly.But there i was having a property called webbrowser.objectforscriping.Here what is the equivalent for that thing.How can i run external C# exceute methods from javascript.

window.external was doing for me previously.

Thanks Das
# re: Evaluating JavaScript code from C#
by Lea Hayes October 01, 2008 @ 9:32am
Hi Rick!

This is a fantastic article, it didn't event occur to me that ASP.NET included a server-side version of JavaScript. This is great because I am working on some JSON code atm which is much easier to deal with using JavaScript.

Unfortunately I hit a small snag, upon compilation the compiler reveals that this feature is deprecated. I did some more searching when I came across the following link:

http://www.odetocode.com/Code/80.aspx

This example also uses deprecated code....BUT, only one change is needed to correct this:

Replace this:
ICodeCompiler compiler; // This interface is deprecated!
compiler = new JScriptCodeProvider().CreateCompiler();

With this:
JScriptCodeProvider compiler = new JScriptCodeProvider(); // This one is fine!
# re: Evaluating JavaScript code from C#
by Nilav Ghosh March 04, 2009 @ 10:48am
Hi Rick,
Definitely a good article . was gud learning. However i came up with another way one could take to use Javascript code inside C#.

Microsoft has its own version of JavaScript....JSCRIPT.NET..we know that. Why not just quickly port(its very easy...just add a class name ..add an import System declarative...and make all the functions public) all the Javascript code to the compiled JSCRIPT.NET code, create a .dll library out of it and then reference this library and use the functions. It worked great for me and quick too. Only backdrop is that Visual Studio as off its 2008 ..yes 2008 version too does not support JSCRIPT.NET in its IDE..bad news . So it needs to be compiled from the command line using the jsc compiler. Not a very tough thing though . There is a command line debugger available as well.


Do let me know if anybody has an issue adopting this idea. Will be all too glad to help.
# re: Evaluating JavaScript code from C#
by dada May 22, 2010 @ 10:38pm
There is also a Microsoft.JScript.Import class works just like Eval, for importing namespaces while the engine is running.

thanks!


----------------------
http://www.dazhou.net
# re: Evaluating JavaScript code from C#
by Abhilash October 15, 2011 @ 12:28am
hello rick,

I took a quick look into the namespace Microsoft.JScript namespace. I'm curious to know whether, its possbile to perform a parsing of javascript file using the namespace. Means, is it possible to get the list of functions/methods names and variable names on passing a javascript file to any constructor in this namespace?

Thanks.
# re: Evaluating JavaScript code from C#
by Roland Gueiss July 02, 2012 @ 12:26am
There is another way described here that reuses the underlying script engines installed in any Windows setup: http://stackoverflow.com/questions/4744105/parse-and-execute-js-by-c-sharp/ so it has no dependency on JScript.NET, plus its the exact engine that Internet Explorer uses (the perf is better, especially with the newest Javascript engines), and well, you can also use VBScript :-)
# re: Evaluating JavaScript code from C#
by Richard Ernst April 11, 2014 @ 10:41am
I used the approach mentioned above by "Joe" in his post on March 5, 2007 @ 4:50pm. I am using Visual Studio 2013/.Net 4.0, so I used the .Net 4.0 version of jsc.exe.

It works perfectly for me, and performs roughly 25% faster than the approach referenced by "Lea Hayes" on October 01, 2008 @ 9:32am (http://www.odetocode.com/Code/80.aspx).
 


West Wind  © Rick Strahl, West Wind Technologies, 2005 - 2014