microsoftgraph / msgraph-sdk-dotnet-core

The core Microsoft Graph client library for .Net. (Microsoft.Graph.Core)
Other
150 stars 50 forks source link

Unable to get Streams using batched requests, Length always zero #945

Open greynoO opened 2 days ago

greynoO commented 2 days ago

Describe the bug

When using BatchRequestContentCollection(or BatchRequestContent) to request a stream content it only returns an empty stream (Length = 0). This happens regardless of whether there is a single or multiple requests in the collection.

var batchRequestContentCollection = new BatchRequestContentCollection(_graphClient);
var driveItemRequest = _graphClient.Drives[driveId].Items[driveItemId].Content.ToGetRequestInformation();
var requestId = await batchRequestContentCollection.AddBatchRequestStepAsync(driveItemRequest);
var batchResponse = await _graphClient.Batch.PostAsync(batchRequestContentCollection);
var stream = await batchResponse.GetResponseStreamByIdAsync(requestId);

I also tried to just use GetResponseByIdAsync, Header information says

Content-Type: application/octet-stream
Content-Length: 0

This does not occur when doing a single request without batching:

var stream = await _graphClient.Drives[driveId].Items[driveItemId].Content.GetAsync();

The stream gets returned correctly then.

Expected behavior

Batched requests should return stream content correctly.

How to reproduce

var batchRequestContentCollection = new BatchRequestContentCollection(_graphClient);
var driveItemRequest = _graphClient.Drives[driveId].Items[driveItemId].Content.ToGetRequestInformation();
var requestId = await batchRequestContentCollection.AddBatchRequestStepAsync(driveItemRequest);
var batchResponse = await _graphClient.Batch.PostAsync(batchRequestContentCollection);
var stream = await batchResponse.GetResponseStreamByIdAsync(requestId);

SDK Version

3.2.1

Latest version known to work for scenario above?

don't know

Configuration

greynoO commented 2 days ago

Info: It works when building the batched request manually with HttpClient.

var batchRequests = new List<object>();

var url = $"/drives/{item.DriveId}/items/{item.DriveItemId}/content";
var requestId = Guid.NewGuid().ToString();

batchRequests.Add(new
{
    id = requestId,
    method = "GET",
    url = url
});

var batchRequestBody = new
{
    requests = batchRequests
};

var batchResponse = await _httpClient.PostAsync(
    "$batch",
    new StringContent(
        System.Text.Json.JsonSerializer.Serialize(batchRequestBody),
        Encoding.UTF8,
        "application/json"
    )
);

So there might be something wrong with BatchRequestContent?

The /content call returns a 302 status with a Location header to the actual file.

{"responses": [{"id":"<someId>","status":302,"headers":{"Location":"<uri>","Cache-Control":"no-store, no-cache","Content-Type":"application/octet-stream"},"body":""}]}

I guess that only the empty body is evaluated?