views:

77

answers:

4

I have a very simple WCF Data Services application and I am doing some basic CRUD operations. I have a ChangeInterceptor on the entity set that is changing, but the object in the ChangeInterceptor is the current state in the database, not what is sent in the HTTP PUT. Is there a way to validate the properties of the object before saving it?

Here is my ChangeInterceptor:

[ChangeInterceptor("People")]
public void OnChangePerson(Person personChanging, UpdateOperations updateOperations) {
    switch (updateOperations) {
        case UpdateOperations.Change:
            // personChanging is the database version here, not the changed version.
            break;
        default:
            break;
    }
}

Here is my client-side code (jQuery):

var data = {
    FirstName: "NewFN",
    LastName: "NewLN"
};
$.ajax({
    type: "PUT",
    url: serviceUrl + "/People(" + personID + ")",
    contentType: "application/json",
    dataType: "json",
    data: JSON.stringify(data),
    success: function (data) {
        alert("Success!");
    },
    error: function (error) {
        alert("An error occured");
    }
});

Here is the JSON being sent to the server: alt text

Here is the ChangeInterceptor when the message is received: alt text

I have uploaded the code for this project here: http://andyjmay.com/test/2921612/ODataTest.zip

+1  A: 

WCF got some nice extension you can write like MessageInspector and ParameterInspector. I'm sure one of them can help you validate stuff before the server even starts to work with tthe request.

Chen Kinnrot
A: 

Hmm... you say personChanging is the database version, it should definitely be the updated version.

My tests (and people on the product team) tell me it should be the version that came over the wire. Could something else be going wrong?

For example could your property be Firstname instead of FirstName?

Alex James
According to this (msdn.microsoft.com/en-us/library/dd744842.aspx) you are correct, that parameter should be the one sent. However, it is not. Also, the property names are correct, and the Update works, I just can't validate it. I have uploaded my test project here: http://andyjmay.com/test/2921612/ODataTest.zip
Andy May
A: 

If the service is EF based and the request is PUT, then the old value will be provided (this has to do with the way the EF provider is implemented and might be a bug, we will look into that some more). You can workaround this by sending a MERGE request instead. I verified, that in that case it works as expected (you get the new values). MERGE has a little different semantics, but it might work for you. PUT overwrites the entity, so if you didn't send a value for a given property it will be reset to its default value. MERGE only modifies the existing entity with the values from the payload, so if some property is not in the payload its value will be left untouched.

Vitek Karas MSFT
+1  A: 

Hi Andy,
I downloaded your sample , reproed your issue and was able to see the latest updated value using this work-around for now.
While I investigate this internally,Can you change your code to use a Merge verb instead of a PUT ?
With this change, you should now be able to see the latest entity values being passed in to the ChangeInterceptors when you update the values via the jQuery client.

$.ajax({
beforeSend: function (xhrObj) {
xhrObj.setRequestHeader("X-Http-Method", "MERGE");
},
type: "POST",
url: serviceUrl + "/People(" + personID + ")",
contentType: "application/json",
dataType: "json",
data: JSON.stringify(data),
success: function (data) {
GetAllPeople();
},
error: function (error) {
alert(error);
}
});

Phani Raj
Thank you very much! Is this an issue with WCF Data Services and EF, or is this expected behavior? I've just starting using WCF Data Services and I'd like to follow best practices if possible.
Andy May
Hi Andy, This is a bug in the WCF Data Services server runtime.We seem to be passing in the stale value to the User runtime and internally using the latest values sent by the client.If you want to validate the values for a PUT too, consider overriding the SaveChanges method on the ObjectContext and doing your validation in there. Here is the MSDN documentation for this method : http://msdn.microsoft.com/en-us/library/bb336792.aspx
Phani Raj