Get Help:Ask a Question in our Forums|Report a Bug|More Help Resources
Last post Jan 25, 2013 05:59 AM by Snixtor
Jan 05, 2013 11:37 PM|LINK
When using HttpClient, is there any way to get the Content-Length header set correctly when using ObjectContent<T>? The implementation of TryComputeLength returns -1 and false.
protected override bool TryComputeLength(out long length)
length = -1L;
When using the ProgressMessageHandler and ObjectContent together, the TotalBytes is 0 on the HttpProgressEventArgs event args which means I cannot display progress correctly on my UI.
Jan 25, 2013 03:59 AM|LINK
That's not the only issue I've encountered with use of ObjectContent<T> and ProgressMessageHandler. I'm bundling ObjectContent<T> together with StreamContent into a MultipartContent. In that case the progress reports happen way in advance of the
actual transfer. For example, I upload a 2mb file and according to ProgressMessageHandler it finishes in a couple of seconds. I think wait another 30 seconds for it to actually finish.
Jan 25, 2013 05:59 AM|LINK
And hey, wouldn't you know it, fixing your problem also fixed mine.
First off, to anyone out there trying to figure out what Web API is doing,
get yourself a copy of the source code.
OK, as you've identified, TryComputeLength on ObjectContent never even tries to compute the length. I guess part of the reason is that it doesn't know the length upfront. Look at the implementation on StreamContent for example (I couldn't find the source
code for this so had to decompile instead), and provided the Stream you've provided it is seekable, it already knows the content length, it's just content.Length (where content is a Stream).
ObjectContent though, has an associated MediaTypeFormatter. The content is an object, it's length depends on the configuration of that formatter and possibly the context that formatter is used in. Serialisation being as it is, you don't know the
length until you've done the serialisation. Now, its implementation of SerializeToStreamAsync uses the formatter to write directly to the output stream. It does it once, and once only. From a performance perspective, this is probably the best approach,
but unfortunately means we don't know the content length until we've already sent it, or at least filled up the send buffer.
That's the problem as I see it, and my speculation of why the problem exists. Here's the fix.
I solved this by using a StreamContent instead of ObjectContent, and buffered the serialised object to pre-determine its length. Something like this:
var client = GetHttpClient("http://localhost:58362/");
var objectBuffer = new MemoryStream();
var formatter = new System.Net.Http.Formatting.JsonMediaTypeFormatter();
var objectToUpload = new MyObjectType()
Hello = "World";
formatter.WriteToStreamAsync(typeof(MyObjectType), objectToUpload, objectBuffer, null, null).Wait();
var uploadContent = new StreamContent(objectBuffer);
uploadContent .Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/json");
var upload = client.PostAsync("api/uploadcontroller", uploadContent);