JavaScript Interop Recipes
The following recipes represent common tasks when mixing Volta and JavaScript code.
Object Sharing between JavaScript and .NET
Objective
We need to share objects between JavaScript and .NET. JSON is the prevalent interchange
format for JavaScript applications.
Rationale
We need to bring into .NET objects that originate in JavaScript. Sometimes this
is the result of service invocation. Other times this is the result of tier splitting,
when a part of the application runs in the browser and another on the CLR.
Recipe
-
The typed access assumes that you created a WeatherService and WeatherObservation
classes
-
The structure of the WeatherObservation class parallels that of the of
the JSON string returned by the service. For example
JSON:
{"weatherObservation":{"stationName":"Redmond,
Roberts Field Airport","datetime":"2007-08-27 13:56:00"}}
C#:
public class
WeatherObservation
{
[Import]
public extern
String datetime
{
get;
}
[Import]
public extern
String stationName
{
get;
}
}}
The WeatherService class is what provides WeatherObservations:
public class
WeatherService
{
[Import]
public extern
WeatherObservation weatherObservation
{
get;
}
}
For typed access you can only use properties, not fields.
For untyped access (possible only for subclasses of JavaScriptObject) you access the properties by key.
Invoking JavaScript Functions from Volta Code
Objective
- We have existing JavaScript libraries such as Virtual Earth and we want to write
new applications that use them from managed code.
- We have existing managed code that calls unmanaged code and we want to use it in
Volta applications.
Rationale
The Microsoft development stack comprising the .NET languages, .NET libraries, Visual
Studio IDE and other tools is a powerful high-end development platform, by contrast
to the relatively primitive JavaScript development experience. We want to help developers
graduate upwards from total dependence on JavaScript as a complete platform by making
it easy for them to leverage the power of .NET without giving up the ubiquitous
reach of the browser.
The Recipe
Volta makes it trivial to call JavaScript from .NET languages. Simply annotate a
class or an extern method with an Import custom attribute that names or defines
the JavaScript implementation.
Here’s an example from the Virtual Earth library. The first line of code declares
a .NET constructor whose implementation is supplied as an inline function. This
function simply bridges .NET namespaces to JavaScript prefixes. The second line
of code declares a .NET event handler that maps to a JavaScript event handler with
a slightly different name. In both cases we use the extern modifier so we
don’t have native implementations, by design.
namespace Microsoft.LiveLabs.Volta.VirtualEarth
{
[Import(ScriptMemberNameCasing
= Casing.Pascal, PassInstanceAsArgument = false)]
public class
Map
{
private static
int s_counter;
[Import("function(id) { return new VEMap(id);
}")]
public extern Map(string id);
//
[Import("onLoadMap",PassInstanceAsArgument
= true)]
public extern
event HtmlEventHandler MapLoaded;
//
}
}
Consequences
If needed, we can customize the mapping via optional parameters. For instance, we
can rename the function or reorder the parameters.
Once imported, a class or method is a first-class citizen of .NET and enjoys all
the benefits of IntelliSense and compile-time type checking.
Detail Highlights
- By default the compiler automatically generates the name of the JavaScript function
or property method through camel-casing the name of the corresponding .NET element.
If we need a different JavaScript name, override the default by specifying the desired
name name as the first argument of the Import custom attribute.
- By default, Volta passes an object instance as the first argument of the JavaScript
function. We can override this default in the Import arguments.
- The Volta.JavaScript namespace declares .NET functions and properties for
standard JavaScript globals, like Global.Eval.
Invoking Volta code from JavaScript
Objective
Traditionally we’ve used JavaScript to build browser-based applications. However
we reached a glass ceiling due to a combination of language features, available
libraries, and/or IDE support. We’d like to leverage Volta when developing in JavaScript.
Rationale
When developing in JavaScript we don’t have access to the .NET libraries. In addition,
since the language is dynamically-typed we give up features like IntelliSense or
compile-time error checking and reporting.
Recipe
Volta makes it easy to integrate the .NET and JavaScript worlds. We carve out the
code that is tedious to write in JavaScript, write it using a .NET language and
libraries, and use Volta to invoke it from the JavaScript program.
Consider the following code fragment where we implement the ComputeVelocity method
in C#. We use the Export custom attribute to mark this method as something that
we want to expose to JavaScript programs. Once Volta compiles this code we could
call this method from JavaScript code, and thus are able to tackle problems that
are too complicated to be solved in JavaScript.
[Export]
public static
double ComputeVelocity()
{
// computation goes here
}
Detail Highlights
- Only static methods can be exported to JavaScript.
- By default the compiler automatically generates the name of the function or property
method through camel casing the name of the corresponding C# element. If you need
a different name you can override it by specifying the name as the argument.
- The Volta compiler doesn't guarantee that the uniqueness of the generated JavaScript
name.