This project has moved and is read-only. For the latest updates, please go here.

Host Function that returns dynamic object

Sep 19, 2016 at 3:36 PM
Dear,

I am trying to access properties from a dynamic object that is returned from a c# call.
Example JS:
var xml = api.MyHostFunction();
var productId = xml.ProductId;
This is the prototype for MyHostFunction():
dynamic MyHostFunction();
ClearScript is throwing an exception when trying to access the ProductId property.
Debugging I can see that the property actually exists and can be accessed from any Host code. But its not possible to access it from JS:

TypeError: Cannot read property 'ProductId' of undefined

Am I doing anything wrong or ClearScript does not support this yet?

Thank you!
Sep 19, 2016 at 3:44 PM
Hello!

What kind of object does MyHostFunction actually return? Also, are you using V8 or JScript?

Thanks!
Sep 19, 2016 at 4:00 PM
Hi!

Thank you for the prompt reply.

The object is typeof(dynamic).
That function makes a call to my WebServer and retrieves a XML document. This XML document can be a lot of different things, so to ease parsing, I am converting it to a dynamic object as described here: https://www.captechconsulting.com/blogs/fluent-xml-parsing-using-cs-dynamic-type-part-1
Then, my JS code should be able to access the XML document elements and attributes as dynamic C# properties.

Basically it is an object that inherits from the DynamicObject class.

I am running V8 engine.
Sep 19, 2016 at 4:17 PM
Hi again,

For this to work, your object must implement GetDynamicMemberNames in addition to TryGetMember et al.

Good luck!
Sep 19, 2016 at 6:37 PM
Great!

Implementing this method worked.
I will paste it here for future reference:
public class DynamicXml : DynamicObject, IEnumerable
    {
        private readonly List<XElement> _elements;

        public DynamicXml(string text)
        {
            var doc = XDocument.Parse(text);
            _elements = new List<XElement> { doc.Root };
        }

        protected DynamicXml(XElement element)
        {
            _elements = new List<XElement> { element };
        }

        protected DynamicXml(IEnumerable<XElement> elements)
        {
            _elements = new List<XElement>(elements);
        }

        public override bool TryGetMember(GetMemberBinder binder, out object result)
        {
            result = null;
            var attr = _elements[0].Attribute(XName.Get(binder.Name));
            if (attr != null)
                result = attr.Value;
            else
            {
                var items = _elements.Descendants(XName.Get(binder.Name));
                if (items == null || items.Count() == 0) 
                    return false;
                result = new DynamicXml(items);
            }
            return true;
        }

        public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result)
        {
            int ndx = (int)indexes[0];
            result = new DynamicXml(_elements[ndx]);
            return true;
        }

        public override IEnumerable<string> GetDynamicMemberNames()
        {
            List<String> memberNames = new List<String>();
            foreach (XAttribute attr in _elements[0].Attributes())
            {
                memberNames.Add(attr.Name.LocalName);
            }
            foreach (XElement child in _elements[0].Descendants())
            {
                memberNames.Add(child.Name.LocalName);
            }
            return memberNames;
        }

        public IEnumerator GetEnumerator()
        {
            foreach (var element in _elements)
                yield return new DynamicXml(element);
        }
    }