Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

asp.net mvc web api partial update with OData Patch

I am using HttpPatch to partially update an object. To get that working I am using Delta and Patch method from OData (mentioned here: What's the currently recommended way of performing partial updates with Web API?). Everything seems to be working fine but noticed that mapper is case sensitive; when the following object is passed the properties are getting updated values:

{
  "Title" : "New title goes here",
  "ShortDescription" : "New text goes here"
}

But when I pass the same object with lower or camel-case properties, Patch doesn't work - new value is not going through, so it looks like there is a problem with deserialisation and properties mapping, ie: "shortDescription" to "ShortDescription".

Is there a config section that will ignore case sensitivity using Patch?

FYI:

On output I have camel-case properties (following REST best practices) using the following formatter:

//formatting
JsonSerializerSettings jss = new JsonSerializerSettings();
jss.ContractResolver = new CamelCasePropertyNamesContractResolver();
config.Formatters.JsonFormatter.SerializerSettings = jss;

//sample output
{
  "title" : "First",
  "shortDescription" : "First post!"
}

My model classes however are follwing C#/.NET formatting conventions:

public class Entry {
  public string Title { get; set;}
  public string ShortDescription { get; set;}
  //rest of the code omitted
}
like image 517
303 Avatar asked Oct 22 '13 09:10

303


1 Answers

Short answer, No there is no config option to undo the case sensitiveness (as far as i know)

Long answer: I had the same problem as you today, and this is how i worked around it.
I found it incredibly annoying that it had to be case sensitive, thus i decided to do away with the whole oData part, since it is a huge library that we are abusing....

An example of this implementation can be found at my github github

I decided to implement my own patch method, since that is the muscle that we are actually lacking. I created the following abstract class:

public abstract class MyModel
{
    public void Patch(Object u)
    {
        var props = from p in this.GetType().GetProperties()
                    let attr = p.GetCustomAttribute(typeof(NotPatchableAttribute))
                    where attr == null
                    select p;
        foreach (var prop in props)
        {
            var val = prop.GetValue(this, null);
            if (val != null)
                prop.SetValue(u, val);
        }
    }
}

Then i make all my model classes inherit from *MyModel*. note the line where i use *let*, i will excplain that later. So now you can remove the Delta from you controller action, and just make it Entry again, as with the put method. e.g.

public IHttpActionResult PatchUser(int id, Entry newEntry)

You can still use the patch method the way you used to:

var entry = dbContext.Entries.SingleOrDefault(p => p.ID == id);
newEntry.Patch(entry);
dbContext.SaveChanges();

Now, let's get back to the line

let attr = p.GetCustomAttribute(typeof(NotPatchableAttribute))

I found it a security risk that just any property would be able to be updated with a patch request. For example, you might now want the an ID to be changeble by the patch. I created a custom attribute to decorate my properties with. the NotPatchable attribute:

public class NotPatchableAttribute : Attribute {}

You can use it just like any other attribute:

public class User : MyModel
{
    [NotPatchable]
    public int ID { get; set; }
    [NotPatchable]
    public bool Deleted { get; set; }
    public string FirstName { get; set; }
}

This in this call the Deleted and ID properties cannot be changed though the patch method.

I hope this solve it for you as well. Do not hesitate to leave a comment if you have any questions.

I added a screenshot of me inspecting the props in a new mvc 5 project. As you can see the Result view is populated with the Title and ShortDescription.

Example of inspecting the props

like image 54
rik.vanmechelen Avatar answered Sep 24 '22 20:09

rik.vanmechelen