C# graph SDK - 序列化批量请求的结果
C# graph SDK - serializing the results of a batch request
我正在构建一个从 AAD 中的多个用户获取日历信息的程序。
我想尽可能高效地执行此操作,因此我开始研究 Microsoft 图形批处理功能。
我能够成功执行批处理查询,但在序列化结果时遇到问题:
//1. construct a Batch request
var batchRequestContent = new BatchRequestContent();
var step = 1;
foreach (var userEmail in userEmails)
{
var requestUrl = graphServiceClient
.Users[userEmail]
.Calendar.Events
.Request(new List<QueryOption>
{
new QueryOption("startDateTime", start.ToString("o")),
new QueryOption("endDateTime", end.ToString("o"))
});
var request = new HttpRequestMessage(HttpMethod.Get, requestUrl.RequestUrl);
var requestStep = new BatchRequestStep(step.ToString(), request);
batchRequestContent.AddBatchRequestStep(requestStep);
step++;
}
//2. Submit request
var batchRequest = new HttpRequestMessage(HttpMethod.Post, "https://graph.microsoft.com/v1.0/$batch")
{
Content = batchRequestContent
};
await graphServiceClient.AuthenticationProvider.AuthenticateRequestAsync(batchRequest);
var httpClient = new HttpClient();
var batchResponse = await httpClient.SendAsync(batchRequest);
//3. Process response
var batchResponseContent = new BatchResponseContent(batchResponse);
var responses = await batchResponseContent.GetResponsesAsync();
var responseHandler = new ResponseHandler(graphServiceClient.HttpProvider.Serializer);
foreach (var response in responses)
{
if (response.Value.IsSuccessStatusCode)
{
var responsestring = await response.Value.Content.ReadAsStringAsync();
var responseEvent = //?
}
}
以上都有效,但如何将此结果序列化为强类型事件列表?
编辑
我尝试像这样使用 ResponseHandler 反序列化:
var batchResponseContent = new BatchResponseContent(batchResponse);
var responses = await batchResponseContent.GetResponsesAsync();
var responseHandler = new ResponseHandler(new Serializer());
foreach (var response in responses)
{
if (response.Value.IsSuccessStatusCode)
{
var events = responseHandler.HandleResponse<ICalendarEventsCollectionPage>(response.Value);
//...
}
}
但这会出错并抛出以下异常:
Newtonsoft.Json.JsonSerializationException: Cannot populate JSON object onto type 'Microsoft.Graph.CalendarEventsCollectionPage'. Path '['@odata.context']', line 2, position 19.
@odata.context 似乎是导致错误的原因,请参阅下图了解我从上述请求中获得的实际响应:
由于在提供的示例中每个查询的响应都应为 collection of Event
resource type,以下示例演示了如何反序列化它:
//...
var batchResponseContent = new BatchResponseContent(batchResponse);
var responses = await batchResponseContent.GetResponsesAsync();
foreach (var response in responses)
{
if (response.Value.IsSuccessStatusCode)
{
var content = await response.Value.Content.ReadAsStringAsync();
var events = JsonConvert.DeserializeObject<List<Microsoft.Graph.Event>>(JObject.Parse(content)["value"].ToString());
//...
}
}
您可以使用 ResponseHandler 的标准响应处理 class
var batchResponseContent = new BatchResponseContent(batchResponse);
var responses = await batchResponseContent.GetResponsesAsync();
var responseHandler = new ResponseHandler(new Serializer());
foreach (var response in responses)
{
if (response.Value.IsSuccessStatusCode)
{
var events = responseHandler.HandleResponse<ICalendarEventsCollectionPage>(response.Value);
//...
}
}
并且有一种更简单的方法来创建原始请求...
var request = graphServiceClient
.Users[userEmail]
.Calendar.Events
.Request(new List<QueryOption>
{
new QueryOption("startDateTime", start.ToString("o")),
new QueryOption("endDateTime", end.ToString("o"))
}).GetHttpRequestMessage();
如果有人想要我使用的完整解决方案,我会像这样发出批量请求,它们现在工作正常。客户端库中存在序列化问题,但自从我问了这个问题后问题就解决了 (https://github.com/microsoftgraph/msgraph-sdk-dotnet/issues/587)
//You need these packages/namespaces
//<PackageReference Include="Microsoft.Extensions.Configuration" Version="2.2.0" />
//<PackageReference Include="Microsoft.Graph" Version="1.20.0" />
//<PackageReference Include="Microsoft.Graph.Auth" Version="1.0.0-preview.0" />
//<PackageReference Include="Microsoft.Graph.Core" Version="1.19.0-preview.3" />
//<PackageReference Include="Microsoft.Identity.Client" Version="4.3.0" />
//using Microsoft.Graph;
//using Microsoft.Graph.Extensions;
//using Microsoft.Graph.Auth;
//using Microsoft.Identity.Client;
var confidentialClientApplication = ConfidentialClientApplicationBuilder
.Create("YOUR CLIENT ID")
.WithTenantId("YOUR TENANT ID")
.WithClientSecret("YOUR CLIENT SECRET")
.Build();
var forUser = "YOUR USER'S EMAIL ADDRESS";
var authenticationProvider = new ClientCredentialProvider(confidentialClientApplication);
var graphServiceClient = new GraphServiceClient(authenticationProvider);
var eventRequest = graphServiceClient.Users[forUser].Calendar.CalendarView.Request(
new List<QueryOption>
{
new QueryOption("startDateTime", DateTime.UtcNow.Date.AddMonths(-3).ToString("O")),
new QueryOption("endDateTime", DateTime.UtcNow.Date.ToString("O"))
}
);
var batchRequestContent = new BatchRequestContent();
var reqId = batchRequestContent.AddBatchRequestStep(eventRequest);
// add second, 3rd request here
var returnedResponse = await graphServiceClient.Batch.Request().PostAsync(batchRequestContent);
var batchEvts = await returnedResponse.GetResponseByIdAsync<CalendarEventsCollectionResponse>(reqId);
// read second, 3rd responses here
我正在构建一个从 AAD 中的多个用户获取日历信息的程序。 我想尽可能高效地执行此操作,因此我开始研究 Microsoft 图形批处理功能。 我能够成功执行批处理查询,但在序列化结果时遇到问题:
//1. construct a Batch request
var batchRequestContent = new BatchRequestContent();
var step = 1;
foreach (var userEmail in userEmails)
{
var requestUrl = graphServiceClient
.Users[userEmail]
.Calendar.Events
.Request(new List<QueryOption>
{
new QueryOption("startDateTime", start.ToString("o")),
new QueryOption("endDateTime", end.ToString("o"))
});
var request = new HttpRequestMessage(HttpMethod.Get, requestUrl.RequestUrl);
var requestStep = new BatchRequestStep(step.ToString(), request);
batchRequestContent.AddBatchRequestStep(requestStep);
step++;
}
//2. Submit request
var batchRequest = new HttpRequestMessage(HttpMethod.Post, "https://graph.microsoft.com/v1.0/$batch")
{
Content = batchRequestContent
};
await graphServiceClient.AuthenticationProvider.AuthenticateRequestAsync(batchRequest);
var httpClient = new HttpClient();
var batchResponse = await httpClient.SendAsync(batchRequest);
//3. Process response
var batchResponseContent = new BatchResponseContent(batchResponse);
var responses = await batchResponseContent.GetResponsesAsync();
var responseHandler = new ResponseHandler(graphServiceClient.HttpProvider.Serializer);
foreach (var response in responses)
{
if (response.Value.IsSuccessStatusCode)
{
var responsestring = await response.Value.Content.ReadAsStringAsync();
var responseEvent = //?
}
}
以上都有效,但如何将此结果序列化为强类型事件列表?
编辑 我尝试像这样使用 ResponseHandler 反序列化:
var batchResponseContent = new BatchResponseContent(batchResponse);
var responses = await batchResponseContent.GetResponsesAsync();
var responseHandler = new ResponseHandler(new Serializer());
foreach (var response in responses)
{
if (response.Value.IsSuccessStatusCode)
{
var events = responseHandler.HandleResponse<ICalendarEventsCollectionPage>(response.Value);
//...
}
}
但这会出错并抛出以下异常:
Newtonsoft.Json.JsonSerializationException: Cannot populate JSON object onto type 'Microsoft.Graph.CalendarEventsCollectionPage'. Path '['@odata.context']', line 2, position 19.
@odata.context 似乎是导致错误的原因,请参阅下图了解我从上述请求中获得的实际响应:
由于在提供的示例中每个查询的响应都应为 collection of Event
resource type,以下示例演示了如何反序列化它:
//...
var batchResponseContent = new BatchResponseContent(batchResponse);
var responses = await batchResponseContent.GetResponsesAsync();
foreach (var response in responses)
{
if (response.Value.IsSuccessStatusCode)
{
var content = await response.Value.Content.ReadAsStringAsync();
var events = JsonConvert.DeserializeObject<List<Microsoft.Graph.Event>>(JObject.Parse(content)["value"].ToString());
//...
}
}
您可以使用 ResponseHandler 的标准响应处理 class
var batchResponseContent = new BatchResponseContent(batchResponse);
var responses = await batchResponseContent.GetResponsesAsync();
var responseHandler = new ResponseHandler(new Serializer());
foreach (var response in responses)
{
if (response.Value.IsSuccessStatusCode)
{
var events = responseHandler.HandleResponse<ICalendarEventsCollectionPage>(response.Value);
//...
}
}
并且有一种更简单的方法来创建原始请求...
var request = graphServiceClient
.Users[userEmail]
.Calendar.Events
.Request(new List<QueryOption>
{
new QueryOption("startDateTime", start.ToString("o")),
new QueryOption("endDateTime", end.ToString("o"))
}).GetHttpRequestMessage();
如果有人想要我使用的完整解决方案,我会像这样发出批量请求,它们现在工作正常。客户端库中存在序列化问题,但自从我问了这个问题后问题就解决了 (https://github.com/microsoftgraph/msgraph-sdk-dotnet/issues/587)
//You need these packages/namespaces
//<PackageReference Include="Microsoft.Extensions.Configuration" Version="2.2.0" />
//<PackageReference Include="Microsoft.Graph" Version="1.20.0" />
//<PackageReference Include="Microsoft.Graph.Auth" Version="1.0.0-preview.0" />
//<PackageReference Include="Microsoft.Graph.Core" Version="1.19.0-preview.3" />
//<PackageReference Include="Microsoft.Identity.Client" Version="4.3.0" />
//using Microsoft.Graph;
//using Microsoft.Graph.Extensions;
//using Microsoft.Graph.Auth;
//using Microsoft.Identity.Client;
var confidentialClientApplication = ConfidentialClientApplicationBuilder
.Create("YOUR CLIENT ID")
.WithTenantId("YOUR TENANT ID")
.WithClientSecret("YOUR CLIENT SECRET")
.Build();
var forUser = "YOUR USER'S EMAIL ADDRESS";
var authenticationProvider = new ClientCredentialProvider(confidentialClientApplication);
var graphServiceClient = new GraphServiceClient(authenticationProvider);
var eventRequest = graphServiceClient.Users[forUser].Calendar.CalendarView.Request(
new List<QueryOption>
{
new QueryOption("startDateTime", DateTime.UtcNow.Date.AddMonths(-3).ToString("O")),
new QueryOption("endDateTime", DateTime.UtcNow.Date.ToString("O"))
}
);
var batchRequestContent = new BatchRequestContent();
var reqId = batchRequestContent.AddBatchRequestStep(eventRequest);
// add second, 3rd request here
var returnedResponse = await graphServiceClient.Batch.Request().PostAsync(batchRequestContent);
var batchEvts = await returnedResponse.GetResponseByIdAsync<CalendarEventsCollectionResponse>(reqId);
// read second, 3rd responses here