3

I'm trying to access an array from C# in Javascript.

That's the JavaScript code:

var testArray = window.external.testfunction();
for(var i = 0; i < testArray.length; i++) {
    alert(testArray[i]);
}

I tested it with following C# object assigned to the ObjectForScripting property:

[ComVisible(true)]
public class TestObject
{
    public string[] testfunction()
    {
        var test = new string[1];
        test[0] = "test";
        return test;
    }
}

Already when trying to access testArray.length it throws an JavaScript error saying "function expected".

So how can I return an array back to the JavaScript code?

The JavaScript code is fix (I cannot modify it). So the function will be called with window.external.testfunction() and as return value the JavaScript code expects an array.

How can I accomplish that from the C# side?

Best regards and thank you for any ideas on that

Andreas

ab-tools
  • 528
  • 5
  • 18
  • The easiest way would be to wrap you C# array into a separate object with `Get`/`Set`/`Length` methods, and return it to JavaScript. This could give you some ideas: http://stackoverflow.com/a/20943173/1768303 – noseratio May 06 '14 at 10:12
  • Hello Noseratio, I don't think that this works, because then JavaScript probably will not be able to access the array elements by using `testArray[i]`, does it? As I wrote I cannot change the JavaScript code itself, I just can work with the C# code. But is there really no way to pass an array as return value of a function to JavaScript? – ab-tools May 06 '14 at 10:16
  • If you can't modify JavaScript, how are you going to access `window.external`? Anyhow, you can always inject some new JavaScript, check the update at the end of my answer. – noseratio May 06 '14 at 10:58
  • Just to answer your question why there are acccess to `window.external` in the JS code already although I can't modify it: this JS code is inside a bigger project which uses some external data already through this `window.external` interface. I just need to simulate or mock this inteface now for testing purpose from the C# side. That's the reason why I can't modify the JS code, but the `window.external` are already in place and cannot be changed as well. – ab-tools May 06 '14 at 12:57

2 Answers2

2

I don't think that this works, because then JavaScript probably will not be able to access the array elements by using testArray[i], does it?

The object I mentioned in the comment would be the easiest way, but you would not be able to access its elements as testArray[i] from JavaScript.

The hard way would be implement a class in C# which simulates JavaScript array object (so it is exposed to JavaScript as COM IDispatchEx object and is accessible as testArray[i]). Such C# class would need to implement IReflect and IExpando managed interfaces. If you want to go this route, I posted some more details here:

Yet another way of doing this. Despite you cannot modify the page's existing JavaScript, you still can inject some new JavaScript code, and do with it whatever you want.

Community
  • 1
  • 1
noseratio
  • 59,932
  • 34
  • 208
  • 486
  • I probably will need to go the IExando way. Therefore I checked your examples and the second link is a really good example to start with IReflect, but I did not find an example (also while searching on Google for it) for an implementation of IExpando. Do you know an example on how to "simulate" the array behavior - so access elements by `testArray[i]` - by using this interface? – ab-tools May 06 '14 at 12:54
  • @ab-tools, `IReflect` might enough for a "fixed" array (i.e., JavaScript can't add new elements, but can read/write existing ones). Keep in mind that element indexes are mapped to properties with names `"0"`, `"1"`, etc. `IExpando` is needed if you want to add new elements to the array. I can't find an example of `IExpando`, but I'm certain I coded in the past and it worked. – noseratio May 06 '14 at 13:02
  • 1
    Hello Noseratio, first thanks for your great support! I definitely do not need to add any new elements here - so IReflect should be enough. But I don't get it to work with the example from your link: what should I use as target object there? Basically I don't have a target object - I just want to simulate the array behavior. It would be great if you could give me some hints here. Thanks again very much for your help in advance! – ab-tools May 06 '14 at 14:08
  • 1
    Still marked your answer as accepted as you gave me the tip (using IReflect) I needed to find the right way. Thanks for that again! – ab-tools May 06 '14 at 15:11
1

I really got it to work now myself with the IReflect interface! :-)

You need to implement the methods GetProperties and InvokeMember yourself: in GetProperties you need to make sure there is a property returned with the name "length" and a property for "0" till the length-1 of the array. In InvokeMember you just check then which method JavaScript wants to call and return the correct result.

The biggest problem I had was that the class PropertyInfo is abstract - so I can't create a new object out of it. So I needed to derive an own class from it and use that to return custom property names.

ab-tools
  • 528
  • 5
  • 18