Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to POST a POCO with WCF WebApi's HttpClient

I'm using the WCF WebApi stack (Preview 4) via NuGet (pkg version 0.3.0) and cannot seem to figure out how to "POST a POCO" using HttpClient.

Given the following:

Public Class MyInfo
    Public Property MyDate As DateTime
    Public Property MyId As Guid
End Class

...
Dim value = New MyInfo With {.MyDate = Today, .MyId = Guid.NewGuid()}

Using client as New HttpClient(baseUri)
    Using response = client.Post(requestUri, New ObjectContent(Of MyInfo)(value))
        ' Do stuff
    End Using
End Using
...

When the Post method is called, I get the following exception:

The 'XmlSerializer' serializer cannot serialize the type 'MyInfo'.

at Microsoft.ApplicationServer.Http.XmlMediaTypeFormatter.GetSerializerForType(Type type)
at Microsoft.ApplicationServer.Http.XmlMediaTypeFormatter.OnWriteToStream(Type type, Object value, Stream stream, HttpContentHeaders contentHeaders, TransportContext context)
at Microsoft.ApplicationServer.Http.MediaTypeFormatter.WriteToStream(Type type, Object instance, Stream stream, HttpContentHeaders contentHeaders, TransportContext context)
at Microsoft.ApplicationServer.Http.ObjectContent.WriteToStreamInternal(Stream stream, TransportContext context)
at Microsoft.ApplicationServer.Http.ObjectContent.SerializeToStream(Stream stream, TransportContext context)
at System.Net.Http.HttpContent.LoadIntoBuffer(Int32 maxBufferSize)
at System.Net.Http.HttpClientChannel.PrepareWebRequestForContentUpload(HttpWebRequest webRequest, HttpRequestMessage request)
at System.Net.Http.HttpClientChannel.CreateAndPrepareWebRequest(HttpRequestMessage request)
at System.Net.Http.HttpClientChannel.Send(HttpRequestMessage request, CancellationToken cancellationToken)
at System.Net.Http.HttpClient.Send(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationToken cancellationToken)
at System.Net.Http.HttpClient.Send(HttpRequestMessage request)
at System.Net.Http.HttpClient.Post(Uri requestUri, HttpContent content)
at System.Net.Http.HttpClient.Post(String requestUri, HttpContent content)
...

This is using the NuGet 0.3.0 package.

I've tried adding <Serializable()> and even <DataContract()> to MyInfo, but that didn't help. Am I just doing something wrong?

I found this post here on StackOverflow where it looks like someone is doing something similar to what I did above. I've even duplicated his work (guessing that his Machine object was a simple POCO like my MyInfo is) and ran into the same "cannot serialize" exception.

like image 598
ckittel Avatar asked Jul 27 '11 18:07

ckittel


1 Answers

I ended up finding the problem myself. I was missing the media type. I changed the Post method to look like:

Using client as New HttpClient(baseUri)
    Using response = client.Post(requestUri, New ObjectContent(Of MyInfo)(value, "text/xml"))
        ' Do stuff
    End Using
End Using

and it started working. I guess that makes sense. For some reason, I thought that there was some sort of default media type precedence built-in so that you didn't have to go out of your way to specify the media type each time. Maybe there is, but I'm still doing something wrong?

Update:

My original problem actually had nothing to do with the media type, even though that actually did fix/workaround the problem. The problem seems to happen when MyInfo is nested inside of a Module like this.

Module Module1

    Sub Main()
        Dim value = New MyInfo With {.MyDate = Today, .MyId = Guid.NewGuid()}
        Dim payload As HttpContent = New ObjectContent(Of MyInfo)(value)

        Using client as New HttpClient(baseUri)
            Using response = client.Post(requestUri, New ObjectContent(Of MyInfo)(value))
                ' Do stuff
            End Using
        End Using
    End Sub

    Public Class MyInfo
        Public Property MyDate As DateTime
        Public Property MyId As Guid
    End Class

End Module

Once MyInfo moved outside of the Module, the error no longer happens. It's also worth noting that while the media type is no longer required to prevent the exception, the lack of it results in no Content-Type header, which may not fly server-side as the server may not know how to deserialize the message body. In my case, I needed to leave the media type in so that the request would include a Content-Type: application/xml header for the server's sake.

like image 129
ckittel Avatar answered Nov 10 '22 06:11

ckittel