Skip to content

Sites.PostAsync returns null object #3030

@jimmywim

Description

@jimmywim

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 the Uri of 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 the Uri of 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 GraphServiceClient in 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

Metadata

Metadata

Assignees

No one assigned

    Labels

    status:waiting-for-triageAn issue that is yet to be reviewed or assignedtype:bugA broken experience

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions