Passing DateTime from c# to javascript function

Jul 2, 2015 at 11:16 PM
Hi!

I want to pass DateTime from C# code to javascript function and use it as javascript Date object
my sample code :
V8ScriptEngine engine = new V8ScriptEngine();
engine.Execute("function my_func(props){ var m_date  = props[\"my_date\"]; var m_code = props[\"my_code\"];  var yeay = m_date.getFullYear(); }");
PropertyBag properties = new PropertyBag();
HostFunctions hostObj = new HostFunctions();
hostObj.setProperty(properties, "my_code", 20);
hostObj.setProperty(properties, "my_date", DateTime.Now);
dynamic result = engine.Script["my_func"](properties);
An exception was thrown: TypeError: m_date.getFullYear is not a function

How can I fix it ?

kind regard,
Coordinator
Jul 3, 2015 at 3:25 PM
Edited Jul 3, 2015 at 3:35 PM
Greetings!

As you've noticed, ClearScript doesn't automatically convert DateTime instances into JavaScript dates; such conversion is lossy and not always desirable. However, because it's often useful, we recommend the following.

First, here's a general-purpose class for lazily evaluating a JavaScript expression and caching the result:
public class CachedJsValue {
    private class Holder { public object Value; }
    private readonly ConditionalWeakTable<ScriptEngine, Holder> table = new ConditionalWeakTable<ScriptEngine, Holder>();
    private readonly string expression;
    public CachedJsValue(string expression) {
        this.expression = "(" + expression + ").valueOf()";
    }
    public object Get(ScriptEngine engine) {
        var holder = table.GetOrCreateValue(engine);
        if (holder.Value == null)
            Interlocked.CompareExchange(ref holder.Value, engine.Evaluate(expression), null);
        return holder.Value;
    }
    public dynamic GetDynamic(ScriptEngine engine) {
        return Get(engine);
    }
}
And here's a class that uses it to define a ToJsDate extension method for DateTime:
public static class DateTimeScriptExtensions {
    private static readonly CachedJsValue createDateFunc = new CachedJsValue(@"
        function (y, m, d, h, min, s, ms) {
            return new Date(y, m, d, h, min, s, ms);
        }
    "); 
    public static object ToJsDate(this DateTime dt, ScriptEngine engine) {
        return createDateFunc.GetDynamic(engine)(
            dt.Year, dt.Month - 1, dt.Day,
            dt.Hour, dt.Minute, dt.Second, dt.Millisecond
        );
    }
}
Finally, your sample code can look like this (with a few tweaks and recommended simplifications):
var engine = new V8ScriptEngine();
engine.Execute(@"
    function my_func(props) {
        var m_date = props.my_date;
        var m_code = props.my_code;
        var yeay = m_date.getFullYear();
        return yeay;
    }
");
var properties = new PropertyBag();
properties["my_code"] = 20;
properties["my_date"] = DateTime.Now.ToJsDate(engine);
Console.WriteLine(engine.Script.my_func(properties));
Good luck!
Jul 4, 2015 at 8:42 AM
Edited Jul 4, 2015 at 8:50 AM
Hi!

Thank you for the solution,

So, suppose that my fonction return javascript Date object, and I want to convert it to DateTime object (c#) :
var engine = new V8ScriptEngine();
engine.Execute(@"
    function my_func(props) {
                    var m_date = props.my_date;
                    var m_code = props.my_code;
                    var nextMonth = m_date.getMonth() + 1;
                    m_date.setMonth(nextMonth);
                    return  m_date;
                }
");
var properties = new PropertyBag();
properties["my_code"] = 20;
properties["my_date"] = DateTime.Now.ToJsDate(engine);
dynamic result = engine.Script.my_func(properties);
var  nextMonth = new DateTime(result.getFullYear(), result.getMonth() + 1, result.getDate(), result.getHours(), result.getMinutes(), result.getSeconds());
Is this is a good approach? or Is there an alternative way?

thanks in advance!

kind regard,
Coordinator
Jul 4, 2015 at 4:28 PM
Hi again,

Your approach uses several calls into script code to convert a single date. That could perform acceptably, but you might get better performance by minimizing the number of trips across the host-to-script boundary. Consider something like this:
dynamic jsDate = engine.Evaluate("new Date()");
var dt = DateTime.Parse(jsDate.toJSON());
Cheers!