KevinDockx / JsonPatch

JSON Patch (JsonPatchDocument) RFC 6902 implementation for .NET
MIT License
173 stars 29 forks source link

Is it possible to create a patch document using reflection #84

Closed noufionline closed 5 years ago

noufionline commented 6 years ago

Hi @KevinDockx ,

I am using an open source tool called Trackable Entities, which has a TrackableCollection implementation which gives me the DTO with a collection of Modified Properties.

 public List<string> ModifiedProperties{get;set;}

I want to make a patch document for all the modified properties using reflection. Is it possible?

KevinDockx commented 6 years ago

Sure :) In your case you could run through that ModifiedProperties list, use reflection to get the actual value of those properties on your DTO, and add a replace operation for each change.

noufionline commented 6 years ago

Thanks, @KevinDockx. I have another issue as well. JsonPatchDocument is updating all the values in the child collection items instead of only the changed one. It works perfectly with the Parent object where the actual Apply operation is done. But the child items it replaces every single property with the default value if not in patch document

KevinDockx commented 6 years ago

Hmm, that's strange... do you have a bit of sample code I can use to check?

Anil86 commented 6 years ago

How to get Replace method's path argument using reflection?

Replace method's signature:

    public JsonPatchDocument<TModel> Replace<TProp>(Expression<Func<TModel, TProp>> path, TProp value)

Adding operations to patchDoc:

    var patchDoc = new JsonPatchDocument<PointOfInterest>();

    foreach (string updatedPropertyName in ModifiedProperties)
    {
        patchDoc.Replace(path using reflection, value using reflection);
    }

Model:

    public class PointOfInterest
    {
        public string Name {set; get;}
        public string Description {set; get;}
    }
Anil86 commented 6 years ago

I used following helper function to obtain changed property's path & value:

    // Finds changed property's path & value from property's name
    // w/ the help of reflection
    (Expression<Func<TModel, object>> path, object value) FindOperationArguments<TModel>(TModel model,
                string propertyName)
    {
            // Get info about changed property
            PropertyInfo propertyInfo = typeof(TModel).GetProperty(propertyName,
                    BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);

            // Creates Expression<Func<TModel, object>> for obtaining path
            ParameterExpression parameter = Expression.Parameter(typeof(TModel), "p");
            MemberExpression property = Expression.Property(parameter, propertyInfo);
            Expression<Func<TModel, object>> path = Expression.Lambda<Func<TModel, object>>(property, parameter);

            object value = propertyInfo.GetValue(model);   // Gets changed property's value

            return (path, value);
    }