3

I'm trying to get body from request of an authorization class (AuthorizationHandler), but that body is a Stream and after reading your content, the post request that comes on next can not be executed because Stream content has been disposable.

I'm using this code to get Stream content:

protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, Autorizacao requirement)
{
    var routeValues = context.Resource as AuthorizationFilterContext;
    if (routeValues != null)
    {
        var obj = StreamToObject(routeValues.HttpContext.Request.Body);
        context.Succeed(requirement);
    }
    return Task.FromResult(0);
}

private Object StreamToObject(Stream stream)
{
    try
    {
        string content;
        using (var reader = new StreamReader(stream))
        content = reader.ReadToEnd();
        return Newtonsoft.Json.JsonConvert.DeserializeObject(content);
    }
    catch (Exception e)
    {
        throw e;
    }
}

How i can do to workaround this problem ?

Carlinhos
  • 940
  • 2
  • 10
  • 21
  • Possible duplicate of [Does disposing streamreader close the stream?](https://stackoverflow.com/questions/1065168/does-disposing-streamreader-close-the-stream) – mjwills Jul 24 '17 at 14:14

2 Answers2

4

StreamReader has a special constructor that allow you to pass a boolean as last parameter. It will prevent dispose underlying stream

EDIT: Because ReadToEnd do not restore position in stream you should do it by yourself like this:

var position = stream.Position;
using (var reader = new StreamReader(stream, Encoding.UTF8, false, 8192, true))
    content = reader.ReadToEnd();
stream.Seek(position, SeekOrigin.Begin);


EDIT 2: From MSDN I see that Body has a setter. So you can replace original Body with memory stream:

if (routeValues != null)
{
    var memoryStream = new MemoryStream();
    routeValues.HttpContext.Request.Body.CopyTo(memoryStream);

    // reset position after CopyTo
    memoryStream.Seek(0, SeekOrigin.Begin);
    var obj = StreamToObject(memoryStream);

    // reset position after ReadToEnd
    memoryStream.Seek(0, SeekOrigin.Begin);
    routeValues.HttpContext.Request.Body = memoryStream;
    context.Succeed(requirement);
}
Aleks Andreev
  • 7,016
  • 8
  • 29
  • 37
  • what is the using block for if stream is prevented from being disposed? – dee zg Jul 24 '17 at 14:31
  • @deezg just a coding style habit. Usually I'm surrounded even memory stream into `using` (that have an empty `Dispose`) – Aleks Andreev Jul 24 '17 at 14:50
  • yes, yes, of course, same thing here ;). i wanted to make one other point: it might be a dangerous thing for someone not careful enough because usually reader disposes underlying stream but this way `using` for reader wouldn't dispose the stream so it should be done manually after usage. – dee zg Jul 24 '17 at 15:13
  • I tried to do using your code, but my stream property that i get of AuthorizationFilterContext class cannot get your position property because is throwing a exception "The specified method is not supported". I'm have no idea about what is happening. – Carlinhos Jul 24 '17 at 16:32
  • @Carlinhos it's look like your stream does not support `Seek` method. Could you update a question so I can see how you obtain a `stream` variable? – Aleks Andreev Jul 24 '17 at 16:40
  • @AleksAndreev Updated – Carlinhos Jul 24 '17 at 17:48
0

Maybe not needed any more, but you can set request.EnableRewind() and then do the request.Body.Seek(0, SeekOrigin.Begin);

Work for me

Walter
  • 1
  • 1