I'm trying to implement this code example, but get a HttpRequestException
- "Error while copying content to a stream." when the ReadAsStringAsync()
method is called. The inner exception is "Cannot access a disposed object." I'm using Fiddler to make the request. I don't understand. Can someone explain why I'm getting this exception and offer a solution?
Web Api Method:
public async Task<HttpResponseMessage> Post(HttpRequestMessage request)
{
try
{
var jsonString = await request.Content.ReadAsStringAsync();
}
catch (Exception ex)
{
throw;
}
return new HttpResponseMessage(HttpStatusCode.Created);
}
Fiddler (POST):
User-Agent: Fiddler
Host: localhost:23567
Content-Length: 18
Content-Type: application/json; charset=utf-8
Body{"Test":1}
Edit:
I have a clue, but need verification. On the Web Api controller, I have an ActionFilterAttribute
and in its OnActionExecuting
override, there's this line:
public override async void OnActionExecuting(HttpActionContext actionContext)
{
// omitted code
actionContext.Request.Content.ReadAsStreamAsync();
}
Could it be that because the Content is read here, it's not available again? If so, how can I make it available in the method? Is the Content here the same as the HttpRequestMessage? This may contain an answer.
Just a guess, should post as comment but I want include a code snippet:
Maybe you call Post
function inside a using
block, but don't use await
.
using (HttpRequestMessage request = ...)
{
// Maybe you use this:
Post(request);
// Instead of this
var response = await Post(request);
}
Or you don't dispose old connects properly.
Also, try add HttpVersion.Version10
to your request, which change header request from Connection: keep-alive
to Connection: close
, which can cause exception in some case you reuse a host (Search for more info)
request.Version = HttpVersion.Version10;
var jsonString = await request.Content.ReadAsStringAsync();
Because the controller's ActionFilterAttribute's
OnActionExecuting
method is calling ReadAsStreamAsync
, the Content can't be read again. I changed ReadAsStreamAsync
to ReadAsStringAsync
and the request's Content is available in the controller. Apparantly, ReadAsStringAsync buffers the Content so it's still available. This link provided the answer.
I hope this (late) post will help someone someday...
In short: the accepted answer suggests to read the entire file as string (and not as stream) in order to bypass a read problem
BUT... reading a file as a string is not such a great idea
I figured out that replacing MultipartFormDataStreamProvider with MultipartMemoryStreamProvider works great - and let you read your uploaded file as desired
My code (at least the relevant parts of it)
[HttpPost]
[Route("upload/file")] // you may replace this route to suit your api service
public async Task<IHttpActionResult> Upload()
{
if (!Request.Content.IsMimeMultipartContent("form-data"))
{
return BadRequest("Unsupported media type");
}
try
{
var provider = new MultipartMemoryStreamProvider();
await Request.Content.ReadAsMultipartAsync(provider);
if (provider.Contents.Count == 0) return InternalServerError(new Exception("Upload failed"));
var file = provider.Contents[0]; // if you handle more then 1 file you can loop provider.Contents
var buffer = await file.ReadAsByteArrayAsync();
// .. do whatever needed here
return Ok();
}
catch (Exception ex)
{
return BadRequest(ex.GetBaseException().Message);
}
}
I resolved with this, my problem was that the response was in gzip:
var handler = new HttpClientHandler();
if (handler.SupportsAutomaticDecompression)
{
handler.AutomaticDecompression = DecompressionMethods.GZip |
DecompressionMethods.Deflate;
}
client = new HttpClient(handler);
var content = new FormUrlEncodedContent(valoresPost);
var response = await client.PostAsync(url, content);
var contenidoPdf = await response.Content.ReadAsByteArrayAsync();
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With