XML / JSON Request being modified with a null object

Topics: Web Api
Jun 22, 2011 at 6:37 PM

Hi all,

I'm noticing a strange behavior when using WCF Web Api to create services with resource methods that accept HttpRequestMessage<T>.  It seems that the request message is being altered at some point in the pipeline, and an null object gets appended to the request somewhere.  Let me explain:

Using the QueryableSample, I changed the signature of the ContactsResource Post method to this:

        [WebInvoke(UriTemplate = "", Method = "POST")]
        public Contact Post(HttpRequestMessage<Contact> request)
        {
            var requestString = request.Content.ReadAsString();
            var contact = request.Content.ReadAs<Contact>();
            if (contact == null)
            {
                throw new HttpResponseException(HttpStatusCode.BadRequest);
            }

            contact.Id = totalContacts++;
            contacts.Add(contact);
            return contact;
        }

I consume the service by using the same code provided in the sample code-hehind of Default.aspx:

        protected void PostNewContact_Click(object sender, EventArgs e)
        {
            string uri = "http://localhost:8300/contacts";
            HttpClient client = this.GetClient(uri);
            var contact = new Contact { Name = this.TextBox3.Text, Id = 5 };
            var request = new HttpRequestMessage(HttpMethod.Post, new Uri(uri));
            request.Content = new ObjectContent<Contact>(contact, "application/xml");
            request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/xml"));
            var response = client.Send(request);
            var receivedContact = response.Content.ReadAs<Contact>();
            this.Result.Text = string.Format(CultureInfo.InvariantCulture, "\r\n Contact Name: {0}, Contact Id: {1}", receivedContact.Name, receivedContact.Id);
        }

Setting a breakpoint in the Post method at this line: var requestString = request.Content.ReadAsString(); reveals that the xml request looks like this:

<?xml version="1.0" encoding="utf-8"?><Contact><Name>Dan</Name><Id>5</Id></Contact><?xml version="1.0" encoding="utf-8"?><Contact p1:nil="true" xmlns:p1="http://www.w3.org/2001/XMLSchema-instance" />

Deserializing will fail at this line: var contact = request.Content.ReadAs<Contact>();

Notice the additional p1:Nil contact.  That is different from what was sent to the service.  Oddly, it seems that somewhere in the pipeline the XML representation of the request is modified.  The same thing occurs for JSON.  When I change the client to use JSON, the request that gets passed to the POST method is:

{"Id":5,"Name":"Dan"}null

Notice that null at the end there too.  In this case, however, no exception gets thrown when calling var contact = request.Content.ReadAs<Contact>(); because the JSON deserialization will still work even with that addional null.

As a workaround, you can call var contact = request.Content.ReadAs() instead of the generic request.Content.ReadAs<T>() and deserialization will succeed.  Anyways, the core issue is that it seems somewhere in the pipeline, the request is being modified.  For testing purposes, I plugged in a custom message handler to see what the message looked like at that point (using message.Content.ReadAsString()), and it did not have the strange null added to it. So, it seems the request gets modified after this stage in the pipeline, or I may be using the framework incorrectly :)





Jul 23, 2011 at 8:45 PM

I ran into this today. ReadAs<T> is an extension method that creates an instance of ObjectContent<T> with the HttpContent and then calls ReadAs() on the new instance. ObjectContent has a private HttpContent property and ObjectContent<T> also has a private HttpContent property. Is this a situation where both properties are being serialized as part of the return?