microsoftgraph / microsoftgraph/msgraph-sdk-dotnet
Sites.PostAsync returns null object
Nobody has claimed this yet.
- Dominant language
- C#
- Stars
- 789
- Forks
- 264
- Avg merge
- 15h 17m
- Merged PRs (30d)
- 3
Description
Describe the bug
Wanting to create a SharePoint site using Sites.PostAsync(), and waiting for the site to provision.
According to the Beta docs, this should return a site object, but it's null which makes sense as the site is created asynchronously. But the response contains a Location header which we can use to get the status of the site creation.
Unfortunately, the current iteration of the SDK (5.125.0-preview) doesn't allow access to this Location header.
Is there some funky thing we can do to the GraphServiceClient instance to get the Location header?
Expected behavior
The SDK to either:
- Return a Tuple of the
Site?and theUriof the Location header, so that we can proceed to repeatedly ping this every 5 seconds or so until the site is created or otherwise errors. - Add property to the returned
Site?instance, perhaps extended with a property that has theUriof the Location header.
How to reproduce
var site = await _delegatedGraphService.Sites.PostAsync(new GraphBeta.Models.Site
{
Name = "My Newly Created Site",
DisplayName = "My Newly Created Site",
Description = "My Newly Created Site",
WebUrl = "https://tenant.sharepoint.com/sites/MyNewSite",
Locale = "en-US",
Template = SiteTemplateType.Sitepagepublishing
});
// This object instance is always null, but the site will be available after a few seconds
var siteId = site.Id;
SDK Version
5.125.0-preview
Latest version known to work for scenario above?
No response
Known Workarounds
I managed to get a very clunky workaround in place.
- Create a custom
DelegatingHandler, this will test the response for a Location header and put its value into a public string property. - Instantiate an instance of this custom handler, and have it's instance publicly available in the class that is using
GraphServiceClient - Create an instance of
GraphServiceClientin a way that allows the use of the custom Delegating handler
When I make a request to Sites.PostAsync(), I then inspect the public string property of the custom DelegatingHandler to see if it's non-null - and consume that. I then use regex to extract just the operationId value.
public class CustomGraphDelegatingHandler : DelegatingHandler
{
/// <summary>
/// The value of the "Location" header from this request
/// </summary>
public string LocationHeader { get; set; } = string.Empty;
/// <inheritdoc/>
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
LocationHeader = string.Empty;
var response = await base.SendAsync(request, cancellationToken);
if (response.Headers.TryGetValues("Location", out var values))
{
LocationHeader = values.First();
}
return response;
}
}
And then in the class that is setting up GraphServiceClient
this.customHandler = new CustomGraphDelegatingHandler ();
var handlers = GraphClientFactory.CreateDefaultHandlers();
handlers.Add(this.customHandler);
var http = GraphClientFactory.Create(handlers);
graphServiceClient = new GraphBeta.GraphServiceClient(http, authProvider, graphEndpoint);
Thus, after making the call to Sites.PostAsync, I get the "Location" property out of this.customHandler, if it's there, use regex to pull out operationId, then issue a call to GetOperationStatusWithOperationId to check the status for "succeeded". If it's "Failed" I throw an exception, if it's anything else I sleep with Task.Delay(5000); then try again.
Pretty messy. Would be nice if there was a quicker way to get to the response object from the call, though.
Debug output
No response
Configuration
No response
Other information
No response
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by tracing Sites.PostAsync through the SDK response handling and compare it with the custom CustomGraphDelegatingHandler and GraphClientFactory setup described here. The change is done when callers can access the Location header from site creation and use it with GetOperationStatusWithOperationId to observe completion or failure.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- csharp
- Domain
- api
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 38/100