AspNetCoreOData icon indicating copy to clipboard operation
AspNetCoreOData copied to clipboard

Issues with dynamic property

Open sunliangqin opened this issue 3 years ago • 4 comments

  1. Dynamic property doesn't support non-primitive data types We are trying to build an odata data service to enable clients to store arbitrary json data. I define an open data type by adding the following field. It works well with primitive data types like string ect.
public IDictionary<string, object> DynamicProperties { get; set; }

However, when I try to post an item with the following dynamic property.

"SortKey": {
    "Timestamp": "0001-01-01T00:00:00+00:00",
    "KeyValue": 0
}

I got an exception below.

The given untyped value '{"Timestamp":"0001-01-01T00:00:00+00:00","KeyValue":0}' in payload is invalid. Consider using a OData type annotation explicitly.

Is there a way to support arbitrary json data and return them as-is on request?

  1. Filtering dynamic property always return empty result I posted some items with a dynamic property "type": 65. However, I always get empty result with $filter=cast(Type, 'Edm.Int32') eq 65.

I stepped into the source code. It seems like this check statement is causing the problem. It works well if I skip it under debugger. https://github.com/OData/WebApi/blob/13938e80d0754f2e554f70c8e92fba1baeaf8318/src/Microsoft.AspNet.OData.Shared/Query/Expressions/ExpressionBinderBase.cs#L1370 image

Is this an known issue? Any comments are highly appreciated. Thanks!

sunliangqin avatar Jan 29 '21 23:01 sunliangqin

@sunliangqin

  1. if want to use structural type for the dynamic property, please make sure that type in the model. Otherwise, we don't know how to deserialize it. Or if possible, you can put all "json value" into double quoted string.
  2. can $filter work without the "cast"? $filter=Type eq 65? In the payload, you can add "[email protected]": "#int32" to specify the type.

xuzhg avatar Feb 01 '21 22:02 xuzhg

Thanks @xuzhg!

  1. Unfortunately, the OData service we are trying to build serves as a data storage service. We need to allow clients to upload arbitrary json data. So there is no way for us to define types for them ahead of time. And we cannot change the json value to string due to some backward compatible reasons. However, it seems like this can be accomplished by providing a custom implementation of ODataResourceDeserializer & ODataResourceSerializer. Or is this something can be supported natively?

  2. I specified the type using "[email protected]": "Emd.Int32" (#int32 didn't work for me. ModelState.IsValid is false). It worked for me after removing the "cast" in the query. It looks like it should be OK to use an extra cast here. Is this a bug?

sunliangqin avatar Feb 04 '21 10:02 sunliangqin

Hi all, any plan to support non-primitive data types in DynamicProperties?

@sunliangqin did you overcome this limit?

glconti avatar May 13 '22 12:05 glconti

PS: I solved this by implementing a custom ODataResourceSerializer that overrides AppendDynamicProperties (you must register your own ODataSerializerProvider to get this to run for your MyODataEntity):

public class CustomDynamicPropsDataSerializer : ODataResourceSerializer
{
    public CustomDynamicPropsDataSerializer(ODataSerializerProvider serializerProvider)
        : base(serializerProvider)
    {
    }

    public override void AppendDynamicProperties(
         ODataResource resource, 
         SelectExpandNode selectExpandNode, 
         ResourceContext resourceContext)
    {
        if (resourceContext?.ResourceInstance is MyODataEntity entity)
        {
            var properties = new List<ODataProperty>();
            foreach (var item in entity.Properties)
            {
                properties.Add(new ODataProperty
                {
                    Name = item.Key,
                    Value = new ODataUntypedValue
                    {
                        RawValue = JsonConvert.SerializeObject(item.Value)
                    },
                });
            }

            resource.Properties = resource.Properties.Concat(properties);
        }
    }

}

dviry avatar Jun 09 '22 14:06 dviry