Question

I made object using ExpandoObject class and I want to perform spring.net expression on that object, but then I got following error:

'Name' node cannot be resolved for the specified context [System.Dynamic.ExpandoObject].

Code looks like:

  dynamic expandObject = new ExpandoObject();
  expandObject.Name = "Los";
  var value = (string)ExpressionEvaluator.GetValue(expandObject, "Name");

I think that spring expression doesn't work with dynamic object, but maybe you now why that happend and any workaround(I tried to convert ExpandoObject on IDictionary list and then execute spring expression but this doesn't work as weel)?

Was it helpful?

Solution

I downloaded Spring.Net source code, and the first thing I notcied is that spring.net core library is made in .Net framework 2.0, because of that spring.net in current version(1.3.2) can't work with System.Dynamic.ExpandoObject(added in .net framework 4.0).
As we now System.Dynamic.ExpandoObject is an object whose member can be dynamically added and removed at run time, added properties and methods are hold in Dictionary list. Therfore I modified source code of spring.net core to support System.Dynamic.ExpandoObject and now everything's works perfectly.


What have I changed?
1. I Upgraded Spring.Net library to .NET framework 4.0
2. I Modified InitializeNode() method in Spring.Expressions.PropertyOrFieldNode class:

private void InitializeNode(object context)
    {
        Type contextType = (context == null || context is Type ? context as Type : context.GetType());

        if (accessor == null || accessor.RequiresRefresh(contextType))
        {
            memberName = this.getText();

            // clear cached member info if context type has changed (for example, when ASP.NET page is recompiled)
            if (accessor != null && accessor.RequiresRefresh(contextType))
            {
                accessor = null;
            }

            // initialize this node if necessary
            if (contextType != null && accessor == null)
            {//below is new IF;)
                if (contextType == typeof(System.Dynamic.ExpandoObject))
                {
                    accessor = new ExpandoObjectValueAccessor(memberName);
                }
                // try to initialize node as enum value first
                else if (contextType.IsEnum)
                {
                    try
                    {
                        accessor = new EnumValueAccessor(Enum.Parse(contextType, memberName, true));
                    }
                    catch (ArgumentException)
                    {
                        // ArgumentException will be thrown if specified member name is not a valid
                        // enum value for the context type. We should just ignore it and continue processing,
                        // because the specified member could be a property of a Type class (i.e. EnumType.FullName)
                    }
                }

                // then try to initialize node as property or field value
                if (accessor == null)
                {
                    // check the context type first
                    accessor = GetPropertyOrFieldAccessor(contextType, memberName, BINDING_FLAGS);

                    // if not found, probe the Type type
                    if (accessor == null && context is Type)
                    {
                        accessor = GetPropertyOrFieldAccessor(typeof(Type), memberName, BINDING_FLAGS);
                    }
                }
            }

            // if there is still no match, try to initialize node as type accessor
            if (accessor == null)
            {
                try
                {
                    accessor = new TypeValueAccessor(TypeResolutionUtils.ResolveType(memberName));
                }
                catch (TypeLoadException)
                {
                    if (context == null)
                    {
                        throw new NullValueInNestedPathException("Cannot initialize property or field node '" +
                                                                 memberName +
                                                                 "' because the specified context is null.");
                    }
                    else
                    {
                        throw new InvalidPropertyException(contextType, memberName,
                                                           "'" + memberName +
                                                           "' node cannot be resolved for the specified context [" +
                                                           context + "].");
                    }
                }
            }
        }
    }


2. I Added my custom ExpandoObjectValueAccessor

private class ExpandoObjectValueAccessor : BaseValueAccessor
    {
        private string memberName;

        public ExpandoObjectValueAccessor(string memberName)
        {
            this.memberName = memberName;
        }

        public override object Get(object context)
        {
            var dictionary = context as IDictionary<string, object>;

            object value;
            if (dictionary.TryGetValue(memberName, out value))
            {
                return value;
            }
            throw new InvalidPropertyException(typeof(System.Dynamic.ExpandoObject), memberName,
                                               "'" + memberName +
                                               "' node cannot be resolved for the specified context [" +
                                               context + "].");
        }

        public override void Set(object context, object value)
        {
            throw new NotSupportedException("Cannot set the value of an expando object.");
        }
    }

EDIT: Certainly you don't have to upgrade spring.net core library to .net framework 4.0 - I did it because I dislike comapring object type by magic strings and I prefer use typeof()

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top