Is it possible to expose a .NET object to JavaScript which has a method returning an IEnumerable?

385 views Asked by At

I'm trying to create a .NET class that will be exposed to JavaScript via the Jurassic JavaScript engine. The class represents an HTTP response object. Since an HTTP response may have multiple headers with the same name, I would like to include a method that returns an IEnumerable of the headers with a particular name.

This is what I have so far:

public class JsResponseInstance : ObjectInstance
{
    private IDictionary<string, IList<string>> _headers;

    public JsResponseInstance(ObjectInstance prototype)
        : base(prototype)
    {
        this.PopulateFunctions();
        _headers = new Dictionary<string, IList<string>>();
    }

    [JSFunction(Name = "addHeader")]
    public virtual void addHeader(string name, string value)
    {
        IList<string> vals;
        bool exists = _headers.TryGetValue(name, out vals);
        if (!exists)
        {
            vals = new List<string>();
            _headers[name] = vals;
        }
        vals.Add(value);
    }

    [JSFunction(Name = "getHeaders")]
    public virtual IList<string> getHeaders(string name)
    {
        IList<string> vals;
        bool exists = _headers.TryGetValue(name, out vals);
        if (!exists)
        {
            return new List<string>();
        }
        return vals;
    }
}

When I test the getHeaders method I get a JavascriptException: Unsupported type: System.Collections.Generic.IList'1[System.String]

I've tried changing the return type of the getHeaders method from IList to string[] and also adding the optional IsEnumerable property to the JSFunction attribute decorating the method. Neither change made a difference, I was still seeing the same exception.

Is there any way of returning an IEnumerable from a method in a .NET class that is exposed to JavaScript?

1

There are 1 answers

0
Simon Elms On BEST ANSWER

Paul Bartrum, the maintainer of Jurassic, answered this question on GitHub.

He stated that the method has to return a type derived from ObjectInstance. Since we need an enumerable, that return type should be an ArrayInstance.

The final working .NET code is:

[JSFunction(Name = "getHeaders")]
public virtual ArrayInstance getHeaders(string name)
{
    IList<string> vals;
    bool exists = _headers.TryGetValue(name, out vals);
    if (!exists)
    {
        return this.Engine.Array.New();
    }
    return this.Engine.Array.New(vals.ToArray());
}