简体   繁体   中英

How can I access a collection returned from a CSharp COM object in Classic ASP JScript?

Ok, this is pretty niche, but I'm hoping someone out there can help me. Also, I'm comfortable in CSharp, but am inexperienced in JScript and COM.

The problem is this. I'm supporting an application component written in CSharp and exposed as a COM object. It exposes several public methods, which are invoked by it's client applications. The clients are all classic ASP script files written in JScript. I'd like to add a new public method to the COM object which returns a collection of objects.

First, returning a single result object works fine...

I'm able to return a single object and access it's properties. For example, in this C# signature...

ResultObject GetResult();

...ResultObject is a POCO with simple properties and no logic. I'm able to access it's properties with the following JScript:

var oMyObject = Server.CreateObject("MyNamespace.MyObject");
var result = oMyObject.GetResult();
Response.Write("<br /><i>('" + result.Value + "', '" + result.ID + "')</i>");

However, it breaks when I return an array...

When I try and return a simple array of ResultObjects from C#...

ResultObject[] GetResults();

...and access it from JScript...

var oMyObject = Server.CreateObject("MyNamespace.MyObject");
var results = oMyObject.GetResults();
for (var i = 0; i < results.length; i++) {
    Response.Write("<br /><i>('" + results[i].Value + "', '" + results[i].ID + "')</i>");
}

...I get the following error when invoking the script:

Microsoft JScript runtime error '800a138f'

'results.length' is null or not an object

Additionally, trying a JScript "typeof results" give me a type of "unknown".

How can I return a collection (array, IEnumerable, etc.) from a CSharp class exposed as a COM object and access it from classic ASP JScript?

What you can do is return a hand made collection, like this:

[ComVisible(true)] // may be optional depending on your other assembly settings
public class ResultList
{
    private List<Result> _innerList;

    internal ResultList(...parameters...)
    {
        _innerList = ...
    }

    public int Count
    {
        get
        {
            return _innerList.Count;
        }
    }

    public Result this[int index] // will be named "Item" in COM's world
    {
        get
        {
            return _innerList[index];
        }
    }
}

That you can use like this:

var results = oMyObject.GetResults();
for (var i = 0; i < results.Count; i++) {
    Response.Write("<br /><i>('" + results.Item(i).Value + "', '" + results.Item(i).ID + "')</i>");
}

Well, after asking this question, StackOverflow suggested some related questions that collectively got me to the solution.

This answer on a related question showed changes I needed to make in C#. Apparently COM prefers to work with what it calls a SAFEARRAY. Returning a SAFEARRAY was pretty simple. I just changed the return type of my method in C# to return an 'object', and added an attribute to guide COM on how to marshal the return value:

[return: MarshalAs(UnmanagedType.Struct, SafeArraySubType = VarEnum.VT_ARRAY)]
object GetResults();

I then did some fancy casting on my array prior to returning from this C# method:

ResultObject[] retv = //create and populate the return value array
return retv.Cast<object>().ToArray();

This got me to the point where I was returning a COM-friendly SAFEARRAY.

(Note, the "MarshalAs" attribute does not appear to be required. My code behaves without it, but I like the clarifying "documentation" it provides about the return value.)

Then this answer showed a change I needed to make in JScript. It seems JScript doesn't play well with SAFEARRAYs. Fortunately you can easily convert it to a JScript-friendly array with the "toArray()" method:

var results = oMyObject.GetResults().toArray();

Now all is behaving as desired.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM