/// <summary> /// Updates the expiration datetime (and notification URL) of an existing SharePoint web hook /// </summary> /// <param name="webUrl">Url of the site holding resource with the webhook</param> /// <param name="resourceType">The type of Hookable SharePoint resource</param> /// <param name="resourceId">Id of the resource (e.g. list id)</param> /// <param name="subscriptionId">Id of the web hook subscription that we need to delete</param> /// <param name="webHookEndPoint">Url of the web hook service endpoint (the one that will be called during an event)</param> /// <param name="expirationDateTime">New web hook expiration date</param> /// <param name="accessToken">Access token to authenticate against SharePoint</param> /// <param name="context">ClientContext instance to use for authentication</param> /// <exception cref="ArgumentOutOfRangeException">Thrown when expiration date is out of valid range.</exception> /// <returns>true if succesful, exception in case something went wrong</returns> public static async Task <bool> UpdateWebhookSubscriptionAsync(string webUrl, WebHookResourceType resourceType, string resourceId, string subscriptionId, string webHookEndPoint, DateTime expirationDateTime, string accessToken, ClientContext context) { if (!ValidateExpirationDateTime(expirationDateTime)) { throw new ArgumentOutOfRangeException(nameof(expirationDateTime), "The specified expiration date is invalid. Should be greater than today and within 6 months"); } await new SynchronizationContextRemover(); using (var handler = new HttpClientHandler()) { context.Web.EnsureProperty(p => p.Url); if (String.IsNullOrEmpty(accessToken)) { handler.SetAuthenticationCookies(context); } using (var httpClient = new PnPHttpProvider(handler)) { string identifierUrl = GetResourceIdentifier(resourceType, webUrl, resourceId); if (string.IsNullOrEmpty(identifierUrl)) { throw new Exception("Identifier of the resource cannot be determined"); } string requestUrl = string.Format("{0}/{1}('{2}')", identifierUrl, SubscriptionsUrlPart, subscriptionId); HttpRequestMessage request = new HttpRequestMessage(new HttpMethod("PATCH"), requestUrl); request.Headers.Add("X-RequestDigest", await context.GetRequestDigest()); request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); if (!string.IsNullOrEmpty(accessToken)) { request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken); } request.Content = new StringContent(JsonConvert.SerializeObject( new WebhookSubscription() { NotificationUrl = webHookEndPoint, ExpirationDateTime = expirationDateTime }), Encoding.UTF8, "application/json"); HttpResponseMessage response = await httpClient.SendAsync(request, new System.Threading.CancellationToken()); if (response.StatusCode != System.Net.HttpStatusCode.NoContent) { // oops...something went wrong, maybe the web hook does not exist? throw new Exception(await response.Content.ReadAsStringAsync()); } else { return(true); } } } }
/// <summary> /// Add a Webhook subscription to a SharePoint resource /// </summary> /// <param name="webUrl">Url of the site holding the list</param> /// <param name="resourceType">The type of Hookable SharePoint resource</param> /// <param name="accessToken">Access token to authenticate against SharePoint</param> /// <param name="context">ClientContext instance to use for authentication</param> /// <param name="subscription">The Webhook subscription to add</param> /// <exception cref="ArgumentOutOfRangeException">Thrown when expiration date is out of valid range.</exception> /// <returns>The added subscription object</returns> public static async Task <WebhookSubscription> AddWebhookSubscriptionAsync(string webUrl, WebHookResourceType resourceType, string accessToken, ClientContext context, WebhookSubscription subscription) { if (!ValidateExpirationDateTime(subscription.ExpirationDateTime)) { throw new ArgumentOutOfRangeException(nameof(subscription.ExpirationDateTime), "The specified expiration date is invalid. Should be greater than today and within 6 months"); } await new SynchronizationContextRemover(); string responseString = null; using (var handler = new HttpClientHandler()) { context.Web.EnsureProperty(p => p.Url); if (String.IsNullOrEmpty(accessToken)) { handler.SetAuthenticationCookies(context); } using (var httpClient = new PnPHttpProvider(handler)) { string identifierUrl = GetResourceIdentifier(resourceType, webUrl, subscription.Resource); if (string.IsNullOrEmpty(identifierUrl)) { throw new Exception("Identifier of the resource cannot be determined"); } string requestUrl = identifierUrl + "/" + SubscriptionsUrlPart; HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, requestUrl); request.Headers.Add("X-RequestDigest", await context.GetRequestDigest()); request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); if (!string.IsNullOrEmpty(accessToken)) { request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken); } request.Content = new StringContent(JsonConvert.SerializeObject(subscription), Encoding.UTF8, "application/json"); HttpResponseMessage response = await httpClient.SendAsync(request, new System.Threading.CancellationToken()); if (response.IsSuccessStatusCode) { responseString = await response.Content.ReadAsStringAsync(); } else { // Something went wrong... throw new Exception(await response.Content.ReadAsStringAsync()); } } } return(JsonConvert.DeserializeObject <WebhookSubscription>(responseString)); }
/// <summary> /// Returns the request digest from the current session/site /// </summary> /// <param name="context"></param> /// <returns></returns> public static async Task <string> GetRequestDigest(this ClientContext context) { await new SynchronizationContextRemover(); //InitializeSecurity(context); using (var handler = new HttpClientHandler()) { string responseString = string.Empty; var accessToken = context.GetAccessToken(); context.Web.EnsureProperty(w => w.Url); if (String.IsNullOrEmpty(accessToken)) { handler.SetAuthenticationCookies(context); } using (var httpClient = new PnPHttpProvider(handler)) { string requestUrl = String.Format("{0}/_api/contextinfo", context.Web.Url); HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, requestUrl); request.Headers.Add("accept", "application/json;odata=verbose"); if (!string.IsNullOrEmpty(accessToken)) { request.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", accessToken); } else { if (context.Credentials is NetworkCredential networkCredential) { handler.Credentials = networkCredential; } } HttpResponseMessage response = await httpClient.SendAsync(request); if (response.IsSuccessStatusCode) { responseString = await response.Content.ReadAsStringAsync(); } else { throw new Exception(await response.Content.ReadAsStringAsync()); } } var contextInformation = JsonConvert.DeserializeObject <dynamic>(responseString); string formDigestValue = contextInformation.d.GetContextWebInformation.FormDigestValue; return(await Task.Run(() => formDigestValue)); } }
/// <summary> /// Checks if a given alias is already in use or not /// </summary> /// <param name="context">Context to operate against</param> /// <param name="alias">Alias to check</param> /// <returns>True if in use, false otherwise</returns> public static async Task <Dictionary <string, string> > GetGroupInfo(ClientContext context, string alias) { await new SynchronizationContextRemover(); Dictionary <string, string> siteInfo = new Dictionary <string, string>(); var accessToken = context.GetAccessToken(); using (var handler = new HttpClientHandler()) { context.Web.EnsureProperty(w => w.Url); if (String.IsNullOrEmpty(accessToken)) { handler.SetAuthenticationCookies(context); } using (var httpClient = new HttpClient(handler)) { string requestUrl = String.Format("{0}/_api/SP.Directory.DirectorySession/Group(alias='{1}')", context.Web.Url, alias); HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, requestUrl); request.Headers.Add("accept", "application/json;odata.metadata=minimal"); httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); request.Headers.Add("odata-version", "4.0"); if (!string.IsNullOrEmpty(accessToken)) { request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken); } // Perform actual GET request HttpResponseMessage response = await httpClient.SendAsync(request); if (response.StatusCode == System.Net.HttpStatusCode.NotFound) { siteInfo = null; } else if (response.StatusCode == System.Net.HttpStatusCode.OK) { var responseString = await response.Content.ReadAsStringAsync(); siteInfo = JsonConvert.DeserializeObject <Dictionary <string, string> >(responseString); } else { // Something went wrong... throw new Exception(await response.Content.ReadAsStringAsync()); } } return(await Task.Run(() => siteInfo)); } }
/// <summary> /// Checks if a given alias is already in use or not /// </summary> /// <param name="context">Context to operate against</param> /// <param name="alias">Alias to check</param> /// <returns>True if in use, false otherwise</returns> public static async Task <bool> AliasExistsAsync(ClientContext context, string alias) { await new SynchronizationContextRemover(); bool aliasExists = true; var accessToken = context.GetAccessToken(); using (var handler = new HttpClientHandler()) { context.Web.EnsureProperty(w => w.Url); if (String.IsNullOrEmpty(accessToken)) { handler.SetAuthenticationCookies(context); } using (var httpClient = new HttpClient(handler)) { string requestUrl = String.Format("{0}/_api/SP.Directory.DirectorySession/Group(alias='{1}')", context.Web.Url, alias); HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, requestUrl); request.Headers.Add("accept", "application/json;odata.metadata=none"); httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); request.Headers.Add("odata-version", "4.0"); if (!string.IsNullOrEmpty(accessToken)) { request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken); } // Perform actual GET request HttpResponseMessage response = await httpClient.SendAsync(request); if (response.StatusCode == System.Net.HttpStatusCode.NotFound) { aliasExists = false; // If value empty, URL is taken } else if (response.StatusCode == System.Net.HttpStatusCode.OK) { aliasExists = true; } else { // Something went wrong... throw new Exception(await response.Content.ReadAsStringAsync()); } } return(await Task.Run(() => aliasExists)); } }
/// <summary> /// Deletes an existing SharePoint web hook /// </summary> /// <param name="webUrl">Url of the site holding resource with the webhook</param> /// <param name="resourceType">The type of Hookable SharePoint resource</param> /// <param name="resourceId">Id of the resource (e.g. list id)</param> /// <param name="subscriptionId">Id of the web hook subscription that we need to delete</param> /// <param name="accessToken">Access token to authenticate against SharePoint</param> /// <param name="context">ClientContext instance to use for authentication</param> /// <returns>true if succesful, exception in case something went wrong</returns> public static async Task <bool> RemoveWebhookSubscriptionAsync(string webUrl, WebHookResourceType resourceType, string resourceId, string subscriptionId, string accessToken, ClientContext context) { await new SynchronizationContextRemover(); using (var handler = new HttpClientHandler()) { context.Web.EnsureProperty(p => p.Url); if (String.IsNullOrEmpty(accessToken)) { handler.SetAuthenticationCookies(context); } using (var httpClient = new PnPHttpProvider(handler)) { string identifierUrl = GetResourceIdentifier(resourceType, webUrl, resourceId); if (string.IsNullOrEmpty(identifierUrl)) { throw new Exception("Identifier of the resource cannot be determined"); } string requestUrl = string.Format("{0}/{1}('{2}')", identifierUrl, SubscriptionsUrlPart, subscriptionId); HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Delete, requestUrl); request.Headers.Add("X-RequestDigest", await context.GetRequestDigest()); request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); if (!string.IsNullOrEmpty(accessToken)) { request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken); } HttpResponseMessage response = await httpClient.SendAsync(request, new System.Threading.CancellationToken()); if (response.StatusCode != System.Net.HttpStatusCode.NoContent) { // oops...something went wrong, maybe the web hook does not exist? throw new Exception(await response.Content.ReadAsStringAsync()); } else { return(true); } } } }
/// <summary> /// Get all webhook subscriptions on a given SharePoint resource /// </summary> /// <param name="webUrl">Url of the site holding the resource</param> /// <param name="resourceType">The type of SharePoint resource</param> /// <param name="resourceId">The Unique Identifier of the resource</param> /// <param name="accessToken">Access token to authenticate against SharePoint</param> /// <param name="context">ClientContext instance to use for authentication</param> /// <returns>Collection of <see cref="WebhookSubscription"/> instances, one per returned web hook</returns> public static async Task <ResponseModel <WebhookSubscription> > GetWebhooksSubscriptionsAsync(string webUrl, WebHookResourceType resourceType, string resourceId, string accessToken, ClientContext context) { await new SynchronizationContextRemover(); string responseString = null; using (var handler = new HttpClientHandler()) { context.Web.EnsureProperty(p => p.Url); if (String.IsNullOrEmpty(accessToken)) { handler.SetAuthenticationCookies(context); } using (var httpClient = new PnPHttpProvider(handler)) { string identifierUrl = GetResourceIdentifier(resourceType, webUrl, resourceId); if (string.IsNullOrEmpty(identifierUrl)) { throw new Exception("Identifier of the resource cannot be determined"); } string requestUrl = identifierUrl + "/" + SubscriptionsUrlPart; HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, requestUrl); request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); if (accessToken != null) { request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken); } HttpResponseMessage response = await httpClient.SendAsync(request, new System.Threading.CancellationToken()); if (response.IsSuccessStatusCode) { responseString = await response.Content.ReadAsStringAsync(); } else { // oops...something went wrong throw new Exception(await response.Content.ReadAsStringAsync()); } } } return(JsonConvert.DeserializeObject <ResponseModel <WebhookSubscription> >(responseString)); }
private static async Task <string> GetValidSiteUrlFromAliasAsync(ClientContext context, string alias) { string responseString = null; var accessToken = context.GetAccessToken(); using (var handler = new HttpClientHandler()) { context.Web.EnsureProperty(w => w.Url); if (String.IsNullOrEmpty(accessToken)) { handler.SetAuthenticationCookies(context); } using (var httpClient = new HttpClient(handler)) { string requestUrl = String.Format("{0}/_api/GroupSiteManager/GetValidSiteUrlFromAlias?alias='{1}'", context.Web.Url, alias); HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, requestUrl); request.Headers.Add("accept", "application/json;odata.metadata=minimal"); httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); request.Headers.Add("odata-version", "4.0"); if (!string.IsNullOrEmpty(accessToken)) { request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken); } // Perform actual GET request HttpResponseMessage response = await httpClient.SendAsync(request); if (response.IsSuccessStatusCode) { // If value empty, URL is taken responseString = await response.Content.ReadAsStringAsync(); } else { // Something went wrong... throw new Exception(await response.Content.ReadAsStringAsync()); } } return(await Task.Run(() => responseString)); } }
public static async Task <bool> SetGroupImage(ClientContext context, byte[] file, string mimeType) { var accessToken = context.GetAccessToken(); var returnValue = false; using (var handler = new HttpClientHandler()) { context.Web.EnsureProperty(w => w.Url); // we're not in app-only or user + app context, so let's fall back to cookie based auth if (String.IsNullOrEmpty(accessToken)) { handler.SetAuthenticationCookies(context); } using (var httpClient = new PnPHttpProvider(handler)) { string requestUrl = $"{context.Web.Url}/_api/groupservice/setgroupimage"; var requestDigest = await context.GetRequestDigest(); HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, requestUrl); request.Headers.Add("accept", "application/json;odata=verbose"); if (!string.IsNullOrEmpty(accessToken)) { request.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", accessToken); } request.Headers.Add("X-RequestDigest", requestDigest); request.Headers.Add("binaryStringRequestBody", "true"); request.Content = new ByteArrayContent(file); request.Content.Headers.ContentType = new MediaTypeHeaderValue(mimeType); httpClient.Timeout = new TimeSpan(0, 0, 200); // Perform actual post operation HttpResponseMessage response = await httpClient.SendAsync(request, new System.Threading.CancellationToken()); returnValue = response.IsSuccessStatusCode; } } return(await Task.Run(() => returnValue)); }
private async Task <AppMetadata> BaseAddRequest(byte[] file, string filename, bool overwrite = false, bool appCatalog = true) { AppMetadata returnValue = null; var context = _context; if (appCatalog == true) { // switch context to appcatalog var appcatalogUri = _context.Web.GetAppCatalog(); context = context.Clone(appcatalogUri); } var accessToken = context.GetAccessToken(); using (var handler = new HttpClientHandler()) { context.Web.EnsureProperty(w => w.Url); // we're not in app-only or user + app context, so let's fall back to cookie based auth if (String.IsNullOrEmpty(accessToken)) { handler.SetAuthenticationCookies(context); } using (var httpClient = new PnPHttpProvider(handler)) { string requestUrl = $"{context.Web.Url}/_api/web/tenantappcatalog/Add(overwrite={(overwrite.ToString().ToLower())}, url='{filename}')"; var requestDigest = await context.GetRequestDigest(); HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, requestUrl); request.Headers.Add("accept", "application/json;odata=verbose"); if (!string.IsNullOrEmpty(accessToken)) { request.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", accessToken); } request.Headers.Add("X-RequestDigest", requestDigest); request.Headers.Add("binaryStringRequestBody", "true"); request.Content = new ByteArrayContent(file); // Perform actual post operation HttpResponseMessage response = await httpClient.SendAsync(request, new System.Threading.CancellationToken()); if (response.IsSuccessStatusCode) { // If value empty, URL is taken var responseString = await response.Content.ReadAsStringAsync(); if (responseString != null) { var responseJson = JObject.Parse(responseString); var id = responseJson["d"]["UniqueId"].ToString(); var metadataRequestUrl = $"{context.Web.Url}/_api/web/tenantappcatalog/AvailableApps/GetById('{id}')"; HttpRequestMessage metadataRequest = new HttpRequestMessage(HttpMethod.Post, metadataRequestUrl); metadataRequest.Headers.Add("accept", "application/json;odata=verbose"); if (!string.IsNullOrEmpty(accessToken)) { metadataRequest.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", accessToken); } metadataRequest.Headers.Add("X-RequestDigest", requestDigest); // Perform actual post operation HttpResponseMessage metadataResponse = await httpClient.SendAsync(metadataRequest, new System.Threading.CancellationToken()); if (metadataResponse.IsSuccessStatusCode) { // If value empty, URL is taken var metadataResponseString = await metadataResponse.Content.ReadAsStringAsync(); if (metadataResponseString != null) { var metadataResponseJson = JObject.Parse(metadataResponseString); var returnedAddins = metadataResponseJson["d"]; returnValue = JsonConvert.DeserializeObject <AppMetadata>(returnedAddins.ToString()); } } else { // Something went wrong... throw new Exception(await metadataResponse.Content.ReadAsStringAsync()); } } } else { // Something went wrong... throw new Exception(await response.Content.ReadAsStringAsync()); } } } return(await Task.Run(() => returnValue)); }
private async Task <bool> BaseRequest(Guid id, string method, bool appCatalog = false, Dictionary <string, object> postObject = null) { var context = _context; if (appCatalog == true) { // switch context to appcatalog var appcatalogUri = _context.Web.GetAppCatalog(); context = context.Clone(appcatalogUri); } var returnValue = false; var accessToken = context.GetAccessToken(); using (var handler = new HttpClientHandler()) { context.Web.EnsureProperty(w => w.Url); // we're not in app-only or user + app context, so let's fall back to cookie based auth if (String.IsNullOrEmpty(accessToken)) { handler.SetAuthenticationCookies(context); } using (var httpClient = new PnPHttpProvider(handler)) { string requestUrl = $"{context.Web.Url}/_api/web/tenantappcatalog/AvailableApps/GetByID('{id}')/{method}"; HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, requestUrl); request.Headers.Add("accept", "application/json;odata=nometadata"); if (!string.IsNullOrEmpty(accessToken)) { request.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", accessToken); } request.Headers.Add("X-RequestDigest", await context.GetRequestDigest()); if (postObject != null) { var jsonBody = JsonConvert.SerializeObject(postObject); var requestBody = new StringContent(jsonBody); MediaTypeHeaderValue sharePointJsonMediaType; MediaTypeHeaderValue.TryParse("application/json;odata=nometadata;charset=utf-8", out sharePointJsonMediaType); requestBody.Headers.ContentType = sharePointJsonMediaType; request.Content = requestBody; } // Perform actual post operation HttpResponseMessage response = await httpClient.SendAsync(request, new System.Threading.CancellationToken()); if (response.IsSuccessStatusCode) { // If value empty, URL is taken var responseString = await response.Content.ReadAsStringAsync(); if (responseString != null) { try { var responseJson = JObject.Parse(responseString); returnValue = true; } catch { } } } else { // Something went wrong... throw new Exception(await response.Content.ReadAsStringAsync()); } } } return(await Task.Run(() => returnValue)); }
/// <summary> /// Returns an available app /// </summary> /// <param name="id">The unique id of the app. Notice that this is not the product id as listed in the app catalog.</param> /// <returns></returns> private async Task <dynamic> BaseGetAvailableAsync(Guid id) { dynamic addins = null; var accessToken = _context.GetAccessToken(); using (var handler = new HttpClientHandler()) { _context.Web.EnsureProperty(w => w.Url); // we're not in app-only or user + app context, so let's fall back to cookie based auth if (String.IsNullOrEmpty(accessToken)) { handler.SetAuthenticationCookies(_context); } using (var httpClient = new PnPHttpProvider(handler)) { string requestUrl = $"{_context.Web.Url}/_api/web/tenantappcatalog/AvailableApps"; if (Guid.Empty != id) { requestUrl = $"{_context.Web.Url}/_api/web/tenantappcatalog/AvailableApps/GetById('{id}')"; } HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, requestUrl); request.Headers.Add("accept", "application/json;odata=verbose"); if (!string.IsNullOrEmpty(accessToken)) { request.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", accessToken); } request.Headers.Add("X-RequestDigest", await _context.GetRequestDigest()); // Perform actual post operation HttpResponseMessage response = await httpClient.SendAsync(request, new System.Threading.CancellationToken()); if (response.IsSuccessStatusCode) { // If value empty, URL is taken var responseString = await response.Content.ReadAsStringAsync(); if (responseString != null) { try { if (Guid.Empty == id) { var responseJson = JObject.Parse(responseString); var returnedAddins = responseJson["d"]["results"] as JArray; addins = JsonConvert.DeserializeObject <List <AppMetadata> >(returnedAddins.ToString()); } else { var responseJson = JObject.Parse(responseString); var returnedAddins = responseJson["d"]; addins = JsonConvert.DeserializeObject <AppMetadata>(returnedAddins.ToString()); } } catch { } } } else { // Something went wrong... throw new Exception(await response.Content.ReadAsStringAsync()); } } } return(await Task.Run(() => addins)); }
/// <summary> /// Creates a new Communication Site Collection /// </summary> /// <param name="clientContext">ClientContext object of a regular site</param> /// <param name="siteCollectionCreationInformation">information about the site to create</param> /// <returns>ClientContext object for the created site collection</returns> public static async Task <ClientContext> CreateAsync(ClientContext clientContext, CommunicationSiteCollectionCreationInformation siteCollectionCreationInformation) { await new SynchronizationContextRemover(); ClientContext responseContext = null; var accessToken = clientContext.GetAccessToken(); using (var handler = new HttpClientHandler()) { clientContext.Web.EnsureProperty(w => w.Url); // we're not in app-only or user + app context, so let's fall back to cookie based auth if (String.IsNullOrEmpty(accessToken)) { handler.SetAuthenticationCookies(clientContext); } using (var httpClient = new PnPHttpProvider(handler)) { string requestUrl = $"{clientContext.Web.Url}/_api/SPSiteManager/Create"; // string requestUrl = String.Format("{0}/_api/sitepages/communicationsite/create", clientContext.Web.Url); var siteDesignId = GetSiteDesignId(siteCollectionCreationInformation); Dictionary <string, object> payload = new Dictionary <string, object>(); payload.Add("__metadata", new { type = "Microsoft.SharePoint.Portal.SPSiteCreationRequest" }); payload.Add("Title", siteCollectionCreationInformation.Title); payload.Add("Lcid", siteCollectionCreationInformation.Lcid); payload.Add("ShareByEmailEnabled", siteCollectionCreationInformation.ShareByEmailEnabled); payload.Add("Url", siteCollectionCreationInformation.Url); // Deprecated // payload.Add("AllowFileSharingForGuestUsers", siteCollectionCreationInformation.AllowFileSharingForGuestUsers); if (siteDesignId != Guid.Empty) { payload.Add("SiteDesignId", siteDesignId); } payload.Add("Classification", siteCollectionCreationInformation.Classification == null ? "" : siteCollectionCreationInformation.Classification); payload.Add("Description", siteCollectionCreationInformation.Description == null ? "" : siteCollectionCreationInformation.Description); payload.Add("WebTemplate", "SITEPAGEPUBLISHING#0"); payload.Add("WebTemplateExtensionId", Guid.Empty); var body = new { request = payload }; // Serialize request object to JSON var jsonBody = JsonConvert.SerializeObject(body); var requestBody = new StringContent(jsonBody); // Build Http request HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, requestUrl); request.Content = requestBody; request.Headers.Add("accept", "application/json;odata=verbose"); MediaTypeHeaderValue sharePointJsonMediaType = null; MediaTypeHeaderValue.TryParse("application/json;odata=verbose;charset=utf-8", out sharePointJsonMediaType); requestBody.Headers.ContentType = sharePointJsonMediaType; if (!string.IsNullOrEmpty(accessToken)) { request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken); } requestBody.Headers.Add("X-RequestDigest", await clientContext.GetRequestDigest()); // Perform actual post operation HttpResponseMessage response = await httpClient.SendAsync(request, new System.Threading.CancellationToken()); if (response.IsSuccessStatusCode) { // If value empty, URL is taken var responseString = await response.Content.ReadAsStringAsync(); if (responseString != null) { try { var responseJson = JObject.Parse(responseString); #if !NETSTANDARD2_0 if (Convert.ToInt32(responseJson["d"]["Create"]["SiteStatus"]) == 2) #else if (responseJson["d"]["Create"]["SiteStatus"].Value <int>() == 2) #endif { responseContext = clientContext.Clone(responseJson["d"]["Create"]["SiteUrl"].ToString()); } else { throw new Exception(responseString); } } catch (Exception) { throw; } } } else { // Something went wrong... throw new Exception(await response.Content.ReadAsStringAsync()); } } return(await Task.Run(() => responseContext)); } }
/// <summary> /// Groupifies a classic team site by creating a group for it and connecting the site with the newly created group /// </summary> /// <param name="clientContext">ClientContext object of a regular site</param> /// <param name="siteCollectionGroupifyInformation">information about the site to create</param> /// <returns>ClientContext object for the created site collection</returns> public static async Task <ClientContext> GroupifyAsync(ClientContext clientContext, TeamSiteCollectionGroupifyInformation siteCollectionGroupifyInformation) { if (siteCollectionGroupifyInformation == null) { throw new ArgumentException("Missing value for siteCollectionGroupifyInformation", "sitecollectionGroupifyInformation"); } if (!string.IsNullOrEmpty(siteCollectionGroupifyInformation.Alias) && siteCollectionGroupifyInformation.Alias.Contains(" ")) { throw new ArgumentException("Alias cannot contain spaces", "Alias"); } if (string.IsNullOrEmpty(siteCollectionGroupifyInformation.DisplayName)) { throw new ArgumentException("DisplayName is required", "DisplayName"); } await new SynchronizationContextRemover(); ClientContext responseContext = null; var accessToken = clientContext.GetAccessToken(); if (clientContext.IsAppOnly()) { throw new Exception("App-Only is currently not supported."); } using (var handler = new HttpClientHandler()) { clientContext.Web.EnsureProperty(w => w.Url); // we're not in app-only or user + app context, so let's fall back to cookie based auth if (String.IsNullOrEmpty(accessToken)) { handler.SetAuthenticationCookies(clientContext); } using (var httpClient = new PnPHttpProvider(handler)) { string requestUrl = String.Format("{0}/_api/GroupSiteManager/CreateGroupForSite", clientContext.Web.Url); Dictionary <string, object> payload = new Dictionary <string, object>(); payload.Add("displayName", siteCollectionGroupifyInformation.DisplayName); payload.Add("alias", siteCollectionGroupifyInformation.Alias); payload.Add("isPublic", siteCollectionGroupifyInformation.IsPublic); var optionalParams = new Dictionary <string, object>(); optionalParams.Add("Description", siteCollectionGroupifyInformation.Description != null ? siteCollectionGroupifyInformation.Description : ""); // Handle groupify options var creationOptionsValues = new List <string>(); if (siteCollectionGroupifyInformation.KeepOldHomePage) { creationOptionsValues.Add("SharePointKeepOldHomepage"); } var creationOptions = new Dictionary <string, object>(); creationOptions.Add("results", creationOptionsValues.ToArray()); optionalParams.Add("CreationOptions", creationOptions); optionalParams.Add("Classification", siteCollectionGroupifyInformation.Classification != null ? siteCollectionGroupifyInformation.Classification : ""); payload.Add("optionalParams", optionalParams); var body = payload; // Serialize request object to JSON var jsonBody = JsonConvert.SerializeObject(body); var requestBody = new StringContent(jsonBody); // Build Http request HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, requestUrl); request.Content = requestBody; request.Headers.Add("accept", "application/json;odata=verbose"); MediaTypeHeaderValue sharePointJsonMediaType = null; MediaTypeHeaderValue.TryParse("application/json;odata=verbose;charset=utf-8", out sharePointJsonMediaType); requestBody.Headers.ContentType = sharePointJsonMediaType; if (!string.IsNullOrEmpty(accessToken)) { request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken); } requestBody.Headers.Add("X-RequestDigest", await clientContext.GetRequestDigest()); // Perform actual post operation HttpResponseMessage response = await httpClient.SendAsync(request, new System.Threading.CancellationToken()); if (response.IsSuccessStatusCode) { // If value empty, URL is taken var responseString = await response.Content.ReadAsStringAsync(); var responseJson = JObject.Parse(responseString); // SiteStatus 1 = Provisioning, SiteStatus 2 = Ready if (Convert.ToInt32(responseJson["d"]["CreateGroupForSite"]["SiteStatus"]) == 2 || Convert.ToInt32(responseJson["d"]["CreateGroupForSite"]["SiteStatus"]) == 1) { responseContext = clientContext; } else { throw new Exception(responseString); } } else { // Something went wrong... throw new Exception(await response.Content.ReadAsStringAsync()); } } return(await Task.Run(() => responseContext)); } }
private async Task <AppMetadata> BaseAddRequest(byte[] file, string filename, bool overwrite, int timeoutSeconds, AppCatalogScope scope) { AppMetadata returnValue = null; var context = _context; if (scope == AppCatalogScope.Tenant) { // switch context to appcatalog var appcatalogUri = _context.Web.GetAppCatalog(); context = context.Clone(appcatalogUri); } var accessToken = context.GetAccessToken(); using (var handler = new HttpClientHandler()) { context.Web.EnsureProperty(w => w.Url); // we're not in app-only or user + app context, so let's fall back to cookie based auth if (String.IsNullOrEmpty(accessToken)) { handler.SetAuthenticationCookies(context); } using (var httpClient = new PnPHttpProvider(handler)) { string requestUrl = $"{context.Web.Url}/_api/web/{(scope == AppCatalogScope.Tenant ? "tenant" : "sitecollection")}appcatalog/Add(overwrite={(overwrite.ToString().ToLower())}, url='{filename}')"; var requestDigest = await context.GetRequestDigestAsync(); HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, requestUrl); request.Headers.Add("accept", "application/json;odata=nometadata"); if (!string.IsNullOrEmpty(accessToken)) { request.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", accessToken); } else { if (context.Credentials is NetworkCredential networkCredential) { handler.Credentials = networkCredential; } } request.Headers.Add("X-RequestDigest", requestDigest); request.Headers.Add("binaryStringRequestBody", "true"); request.Content = new ByteArrayContent(file); httpClient.Timeout = new TimeSpan(0, 0, timeoutSeconds); // Perform actual post operation HttpResponseMessage response = await httpClient.SendAsync(request, new System.Threading.CancellationToken()); if (response.IsSuccessStatusCode) { // If value empty, URL is taken var responseString = await response.Content.ReadAsStringAsync(); if (responseString != null) { using (var jsonDocument = JsonDocument.Parse(responseString)) { if (jsonDocument.RootElement.TryGetProperty("UniqueId", out JsonElement uniqueIdElement)) { var id = uniqueIdElement.GetString(); returnValue = await GetAppMetaData(scope, context, accessToken, httpClient, requestDigest, id); } } } } else { // Something went wrong... throw new Exception(await response.Content.ReadAsStringAsync()); } } } return(await Task.Run(() => returnValue)); }
/// <summary> /// Returns an available app /// </summary> /// <param name="id">The unique id of the app. Notice that this is not the product id as listed in the app catalog.</param> /// <param name="title">The title of the app.</param> /// <param name="scope">Specifies the app catalog to work with. Defaults to Tenant</param> /// <returns></returns> private async Task <dynamic> BaseGetAvailableAsync(AppCatalogScope scope, Guid id = default(Guid), string title = "") { dynamic addins = null; var accessToken = _context.GetAccessToken(); using (var handler = new HttpClientHandler()) { _context.Web.EnsureProperty(w => w.Url); // we're not in app-only or user + app context, so let's fall back to cookie based auth if (String.IsNullOrEmpty(accessToken)) { handler.SetAuthenticationCookies(_context); } using (var httpClient = new PnPHttpProvider(handler)) { string requestUrl = $"{_context.Web.Url}/_api/web/{(scope == AppCatalogScope.Tenant ? "tenant" : "sitecollection")}appcatalog/AvailableApps"; if (Guid.Empty != id) { requestUrl = $"{_context.Web.Url}/_api/web/{(scope == AppCatalogScope.Tenant ? "tenant" : "sitecollection")}appcatalog/AvailableApps/GetById('{id}')"; } HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, requestUrl); request.Headers.Add("accept", "application/json;odata=nometadata"); if (!string.IsNullOrEmpty(accessToken)) { request.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", accessToken); } else { if (_context.Credentials is NetworkCredential networkCredential) { handler.Credentials = networkCredential; } } request.Headers.Add("X-RequestDigest", await _context.GetRequestDigestAsync()); // Perform actual post operation HttpResponseMessage response = await httpClient.SendAsync(request, new System.Threading.CancellationToken()); if (response.IsSuccessStatusCode) { // If value empty, URL is taken var responseString = await response.Content.ReadAsStringAsync(); if (responseString != null) { try { if (Guid.Empty == id && string.IsNullOrEmpty(title)) { var resultCollection = JsonSerializer.Deserialize <ResultCollection <AppMetadata> >(responseString, new JsonSerializerOptions() { IgnoreNullValues = true }); if (resultCollection.Items != null && resultCollection.Items.Any()) { addins = resultCollection.Items; } } else if (!String.IsNullOrEmpty(title)) { var resultCollection = JsonSerializer.Deserialize <ResultCollection <AppMetadata> >(responseString, new JsonSerializerOptions() { IgnoreNullValues = true }); if (resultCollection.Items != null && resultCollection.Items.Any()) { addins = resultCollection.Items.FirstOrDefault(a => a.Title.Equals(title)); } } else { addins = JsonSerializer.Deserialize <AppMetadata>(responseString); } } catch { } } } else { // Something went wrong... throw new Exception(await response.Content.ReadAsStringAsync()); } } } return(await Task.Run(() => addins)); }
/// <summary> /// Creates a new Modern Team Site Collection /// </summary> /// <param name="clientContext">ClientContext object of a regular site</param> /// <param name="siteCollectionCreationInformation">information about the site to create</param> /// <param name="delayAfterCreation">Defines the number of seconds to wait after creation</param> /// <returns>ClientContext object for the created site collection</returns> public static async Task <ClientContext> CreateAsync(ClientContext clientContext, TeamSiteCollectionCreationInformation siteCollectionCreationInformation, Int32 delayAfterCreation = 0) { if (siteCollectionCreationInformation.Alias.Contains(" ")) { throw new ArgumentException("Alias cannot contain spaces", "Alias"); } await new SynchronizationContextRemover(); ClientContext responseContext = null; if (clientContext.IsAppOnly()) { throw new Exception("App-Only is currently not supported."); } var accessToken = clientContext.GetAccessToken(); using (var handler = new HttpClientHandler()) { clientContext.Web.EnsureProperty(w => w.Url); // we're not in app-only or user + app context, so let's fall back to cookie based auth if (String.IsNullOrEmpty(accessToken)) { handler.SetAuthenticationCookies(clientContext); } using (var httpClient = new PnPHttpProvider(handler)) { string requestUrl = String.Format("{0}/_api/GroupSiteManager/CreateGroupEx", clientContext.Web.Url); Dictionary <string, object> payload = new Dictionary <string, object>(); payload.Add("displayName", siteCollectionCreationInformation.DisplayName); payload.Add("alias", siteCollectionCreationInformation.Alias); payload.Add("isPublic", siteCollectionCreationInformation.IsPublic); var optionalParams = new Dictionary <string, object>(); optionalParams.Add("Description", siteCollectionCreationInformation.Description ?? ""); optionalParams.Add("Classification", siteCollectionCreationInformation.Classification ?? ""); var creationOptionsValues = new List <string>(); if (siteCollectionCreationInformation.Lcid != 0) { creationOptionsValues.Add($"SPSiteLanguage:{siteCollectionCreationInformation.Lcid}"); } creationOptionsValues.Add($"HubSiteId:{siteCollectionCreationInformation.HubSiteId}"); optionalParams.Add("CreationOptions", creationOptionsValues); if (siteCollectionCreationInformation.Owners != null && siteCollectionCreationInformation.Owners.Length > 0) { optionalParams.Add("Owners", siteCollectionCreationInformation.Owners); } payload.Add("optionalParams", optionalParams); var body = payload; // Serialize request object to JSON var jsonBody = JsonConvert.SerializeObject(body); var requestBody = new StringContent(jsonBody); // Build Http request HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, requestUrl); request.Content = requestBody; request.Headers.Add("accept", "application/json;odata.metadata=none"); request.Headers.Add("odata-version", "4.0"); MediaTypeHeaderValue sharePointJsonMediaType = null; MediaTypeHeaderValue.TryParse("application/json;odata.metadata=none;charset=utf-8", out sharePointJsonMediaType); requestBody.Headers.ContentType = sharePointJsonMediaType; if (!string.IsNullOrEmpty(accessToken)) { request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken); } requestBody.Headers.Add("X-RequestDigest", await clientContext.GetRequestDigest()); // Perform actual post operation HttpResponseMessage response = await httpClient.SendAsync(request, new System.Threading.CancellationToken()); if (response.IsSuccessStatusCode) { // If value empty, URL is taken var responseString = await response.Content.ReadAsStringAsync(); var responseJson = JObject.Parse(responseString); #if !NETSTANDARD2_0 if (Convert.ToInt32(responseJson["SiteStatus"]) == 2) #else if (responseJson["SiteStatus"].Value <int>() == 2) #endif { responseContext = clientContext.Clone(responseJson["SiteUrl"].ToString()); } else { throw new Exception(responseString); } // If there is a delay, let's wait if (delayAfterCreation > 0) { System.Threading.Thread.Sleep(TimeSpan.FromSeconds(delayAfterCreation)); } } else { // Something went wrong... throw new Exception(await response.Content.ReadAsStringAsync()); } } return(await Task.Run(() => responseContext)); } }
private async Task <bool> SyncToTeamsImplementation(Guid appId) { var context = _context; // switch context to appcatalog var appcatalogUri = _context.Web.GetAppCatalog(); context = context.Clone(appcatalogUri); var returnValue = false; var accessToken = context.GetAccessToken(); using (var handler = new HttpClientHandler()) { context.Web.EnsureProperty(w => w.Url); // find the app by id var list = context.Web.GetListByUrl("appcatalog"); var query = new CamlQuery(); query.ViewXml = $"<View><Query><Where><Contains><FieldRef Name='UniqueId'/><Value Type='Text'>{appId}</Value></Contains></Where></Query></View>"; var items = list.GetItems(query); context.Load(items); context.ExecuteQueryRetry(); // we're not in app-only or user + app context, so let's fall back to cookie based auth if (String.IsNullOrEmpty(accessToken)) { handler.SetAuthenticationCookies(context); } if (items.Count > 0) { using (var httpClient = new PnPHttpProvider(handler)) { var requestUrl = $"{context.Web.Url}/_api/web/tenantappcatalog/SyncSolutionToTeams(id={items[0].Id})"; HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, requestUrl); request.Headers.Add("accept", "application/json;odata=nometadata"); if (!string.IsNullOrEmpty(accessToken)) { request.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", accessToken); } else { if (context.Credentials is NetworkCredential networkCredential) { handler.Credentials = networkCredential; } } request.Headers.Add("X-RequestDigest", await context.GetRequestDigest()); // Perform actual post operation HttpResponseMessage response = await httpClient.SendAsync(request, new System.Threading.CancellationToken()); if (response.IsSuccessStatusCode) { // If value empty, URL is taken var responseString = await response.Content.ReadAsStringAsync(); if (responseString != null) { try { var responseJson = JObject.Parse(responseString); returnValue = true; } catch { } } } else { // Something went wrong... throw new Exception(await response.Content.ReadAsStringAsync()); } } } } return(await Task.Run(() => returnValue)); }
/// <summary> /// Creates a new Modern Team Site Collection /// </summary> /// <param name="clientContext">ClientContext object of a regular site</param> /// <param name="siteCollectionCreationInformation">information about the site to create</param> /// <returns>ClientContext object for the created site collection</returns> public static async Task <ClientContext> CreateAsync(ClientContext clientContext, TeamSiteCollectionCreationInformation siteCollectionCreationInformation) { ClientContext responseContext = null; var accessToken = clientContext.GetAccessToken(); if (!string.IsNullOrEmpty(accessToken)) { throw new Exception("App-Only is currently not supported."); } using (var handler = new HttpClientHandler()) { clientContext.Web.EnsureProperty(w => w.Url); // we're not in app-only or user + app context, so let's fall back to cookie based auth if (String.IsNullOrEmpty(accessToken)) { handler.SetAuthenticationCookies(clientContext); } using (var httpClient = new PnPHttpProvider(handler)) { string requestUrl = String.Format("{0}/_api/GroupSiteManager/CreateGroupEx", clientContext.Web.Url); Dictionary <string, object> payload = new Dictionary <string, object>(); payload.Add("displayName", siteCollectionCreationInformation.DisplayName); payload.Add("alias", siteCollectionCreationInformation.Alias); payload.Add("isPublic", siteCollectionCreationInformation.IsPublic); var optionalParams = new Dictionary <string, object>(); optionalParams.Add("Description", siteCollectionCreationInformation.Description != null ? siteCollectionCreationInformation.Description : ""); optionalParams.Add("CreationOptions", new { results = new object[0], Classification = siteCollectionCreationInformation.Classification != null ? siteCollectionCreationInformation.Classification : "" }); payload.Add("optionalParams", optionalParams); var body = payload; // Serialize request object to JSON var jsonBody = JsonConvert.SerializeObject(body); var requestBody = new StringContent(jsonBody); // Build Http request HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, requestUrl); request.Content = requestBody; request.Headers.Add("accept", "application/json;odata=verbose"); MediaTypeHeaderValue sharePointJsonMediaType = null; MediaTypeHeaderValue.TryParse("application/json;odata=verbose;charset=utf-8", out sharePointJsonMediaType); requestBody.Headers.ContentType = sharePointJsonMediaType; if (!string.IsNullOrEmpty(accessToken)) { request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken); } requestBody.Headers.Add("X-RequestDigest", await clientContext.GetRequestDigest()); // Perform actual post operation HttpResponseMessage response = await httpClient.SendAsync(request, new System.Threading.CancellationToken()); if (response.IsSuccessStatusCode) { // If value empty, URL is taken var responseString = await response.Content.ReadAsStringAsync(); var responseJson = JObject.Parse(responseString); if (Convert.ToInt32(responseJson["d"]["CreateGroupEx"]["SiteStatus"]) == 2) { responseContext = clientContext.Clone(responseJson["d"]["CreateGroupEx"]["SiteUrl"].ToString()); } else { throw new Exception(responseString); } } else { // Something went wrong... throw new Exception(await response.Content.ReadAsStringAsync()); } } return(await Task.Run(() => responseContext)); } }
/// <summary> /// Internal private method to process an HTTP request toward the ThemeManager REST APIs /// </summary> /// <param name="context">The current ClientContext of CSOM</param> /// <param name="action">The action to perform</param> /// <param name="postObject">The body of the request</param> /// <param name="accessToken">An optional Access Token for OAuth authorization</param> /// <returns>A boolean declaring whether the operation was successful</returns> private static async Task <bool> BaseRequest(ClientContext context, ThemeAction action, Object postObject, String accessToken = null) { var result = false; // If we don't have the access token if (String.IsNullOrEmpty(accessToken)) { // Try to get one from the current context accessToken = context.GetAccessToken(); } using (var handler = new HttpClientHandler()) { context.Web.EnsureProperty(w => w.Url); // We're not in app-only or user + app context, so let's fall back to cookie based auth if (String.IsNullOrEmpty(accessToken)) { handler.SetAuthenticationCookies(context); } using (var httpClient = new PnPHttpProvider(handler)) { // Reference here: https://docs.microsoft.com/en-us/sharepoint/dev/declarative-customization/site-theming/sharepoint-site-theming-rest-api string requestUrl = $"{context.Web.Url}/_api/thememanager/{action.ToString()}"; // Always make a POST request HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, requestUrl); request.Headers.Add("ACCEPT", "application/json; odata.metadata=minimal"); if (!string.IsNullOrEmpty(accessToken)) { request.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", accessToken); } request.Headers.Add("X-RequestDigest", await context.GetRequestDigestAsync()); request.Headers.Add("ODATA-VERSION", "4.0"); if (postObject != null) { var jsonBody = JsonConvert.SerializeObject(postObject); var requestBody = new StringContent(jsonBody); MediaTypeHeaderValue sharePointJsonMediaType; MediaTypeHeaderValue.TryParse("application/json;charset=utf-8", out sharePointJsonMediaType); requestBody.Headers.ContentType = sharePointJsonMediaType; request.Content = requestBody; } // Perform actual post operation HttpResponseMessage response = await httpClient.SendAsync(request, new System.Threading.CancellationToken()); if (response.IsSuccessStatusCode) { // If value empty, URL is taken var responseString = await response.Content.ReadAsStringAsync(); if (responseString != null) { try { var responseJson = JObject.Parse(responseString); result = true; } catch { } } } else { // Something went wrong... throw new Exception(await response.Content.ReadAsStringAsync()); } } } return(await Task.Run(() => result)); }
/// <summary> /// Creates a new Modern Team Site Collection /// </summary> /// <param name="clientContext">ClientContext object of a regular site</param> /// <param name="siteCollectionCreationInformation">information about the site to create</param> /// <param name="delayAfterCreation">Defines the number of seconds to wait after creation</param> /// <param name="maxRetryCount">Maximum number of retries for a pending site provisioning. Default 12 retries.</param> /// <param name="retryDelay">Delay between retries for a pending site provisioning. Default 10 seconds.</param> /// <returns>ClientContext object for the created site collection</returns> public static async Task <ClientContext> CreateAsync(ClientContext clientContext, TeamSiteCollectionCreationInformation siteCollectionCreationInformation, Int32 delayAfterCreation = 0, Int32 maxRetryCount = 12, // Maximum number of retries (12 x 10 sec = 120 sec = 2 mins) Int32 retryDelay = 1000 * 10 // Wait time default to 10sec ) { if (siteCollectionCreationInformation.Alias.Contains(" ")) { throw new ArgumentException("Alias cannot contain spaces", "Alias"); } await new SynchronizationContextRemover(); ClientContext responseContext = null; if (clientContext.IsAppOnly()) { throw new Exception("App-Only is currently not supported."); } var accessToken = clientContext.GetAccessToken(); using (var handler = new HttpClientHandler()) { clientContext.Web.EnsureProperty(w => w.Url); // we're not in app-only or user + app context, so let's fall back to cookie based auth if (String.IsNullOrEmpty(accessToken)) { handler.SetAuthenticationCookies(clientContext); } using (var httpClient = new PnPHttpProvider(handler)) { string requestUrl = String.Format("{0}/_api/GroupSiteManager/CreateGroupEx", clientContext.Web.Url); Dictionary <string, object> payload = new Dictionary <string, object>(); payload.Add("displayName", siteCollectionCreationInformation.DisplayName); payload.Add("alias", siteCollectionCreationInformation.Alias); payload.Add("isPublic", siteCollectionCreationInformation.IsPublic); var optionalParams = new Dictionary <string, object>(); optionalParams.Add("Description", siteCollectionCreationInformation.Description ?? ""); optionalParams.Add("Classification", siteCollectionCreationInformation.Classification ?? ""); var creationOptionsValues = new List <string>(); if (siteCollectionCreationInformation.Lcid != 0) { creationOptionsValues.Add($"SPSiteLanguage:{siteCollectionCreationInformation.Lcid}"); } creationOptionsValues.Add($"HubSiteId:{siteCollectionCreationInformation.HubSiteId}"); optionalParams.Add("CreationOptions", creationOptionsValues); if (siteCollectionCreationInformation.Owners != null && siteCollectionCreationInformation.Owners.Length > 0) { optionalParams.Add("Owners", siteCollectionCreationInformation.Owners); } payload.Add("optionalParams", optionalParams); var body = payload; // Serialize request object to JSON var jsonBody = JsonConvert.SerializeObject(body); var requestBody = new StringContent(jsonBody); // Build Http request HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, requestUrl); request.Content = requestBody; request.Headers.Add("accept", "application/json;odata.metadata=none"); request.Headers.Add("odata-version", "4.0"); MediaTypeHeaderValue sharePointJsonMediaType = null; MediaTypeHeaderValue.TryParse("application/json;odata.metadata=none;charset=utf-8", out sharePointJsonMediaType); requestBody.Headers.ContentType = sharePointJsonMediaType; if (!string.IsNullOrEmpty(accessToken)) { request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken); } requestBody.Headers.Add("X-RequestDigest", await clientContext.GetRequestDigest()); // Perform actual post operation HttpResponseMessage response = await httpClient.SendAsync(request, new System.Threading.CancellationToken()); if (response.IsSuccessStatusCode) { // If value empty, URL is taken var responseString = await response.Content.ReadAsStringAsync(); var responseJson = JObject.Parse(responseString); #if !NETSTANDARD2_0 if (Convert.ToInt32(responseJson["SiteStatus"]) == 2) #else if (responseJson["SiteStatus"].Value <int>() == 2) #endif { responseContext = clientContext.Clone(responseJson["SiteUrl"].ToString()); } else { /* * BEGIN : Changes to address the SiteStatus=Provisioning scenario */ if (Convert.ToInt32(responseJson["SiteStatus"]) == 1 && string.IsNullOrWhiteSpace(Convert.ToString(responseJson["ErrorMessage"]))) { var spOperationsMaxRetryCount = maxRetryCount; var spOperationsRetryWait = retryDelay; var siteCreated = false; var siteUrl = string.Empty; var retryAttempt = 1; do { if (retryAttempt > 1) { System.Threading.Thread.Sleep(retryAttempt * spOperationsRetryWait); } try { var groupId = responseJson["GroupId"].ToString(); var siteStatusRequestUrl = $"{clientContext.Web.Url}/_api/groupsitemanager/GetSiteStatus('{groupId}')"; var siteStatusRequest = new HttpRequestMessage(HttpMethod.Get, siteStatusRequestUrl); siteStatusRequest.Headers.Add("accept", "application/json;odata=verbose"); if (!string.IsNullOrEmpty(accessToken)) { siteStatusRequest.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken); } siteStatusRequest.Headers.Add("X-RequestDigest", await clientContext.GetRequestDigest()); var siteStatusResponse = await httpClient.SendAsync(siteStatusRequest, new System.Threading.CancellationToken()); var siteStatusResponseString = await siteStatusResponse.Content.ReadAsStringAsync(); var siteStatusResponseJson = JObject.Parse(siteStatusResponseString); if (siteStatusResponse.IsSuccessStatusCode) { var siteStatus = Convert.ToInt32(siteStatusResponseJson["d"]["GetSiteStatus"]["SiteStatus"].ToString()); if (siteStatus == 2) { siteCreated = true; siteUrl = siteStatusResponseJson["d"]["GetSiteStatus"]["SiteUrl"].ToString(); } } } catch (Exception) { // Just skip it and retry after a delay } retryAttempt++; }while (!siteCreated && retryAttempt <= spOperationsMaxRetryCount); if (siteCreated) { responseContext = clientContext.Clone(siteUrl); } else { throw new Exception("OfficeDevPnP.Core.Sites.SiteCollection.CreateAsync: Could not create team site."); } } else { throw new Exception(responseString); } /* * END : Changes to address the SiteStatus=Provisioning scenario */ } // If there is a delay, let's wait if (delayAfterCreation > 0) { System.Threading.Thread.Sleep(TimeSpan.FromSeconds(delayAfterCreation)); } } else { // Something went wrong... throw new Exception(await response.Content.ReadAsStringAsync()); } } return(await Task.Run(() => responseContext)); } }
private static async Task <ClientContext> CreateAsync(ClientContext clientContext, string owner, Dictionary <string, object> payload, Int32 delayAfterCreation = 0, Int32 maxRetryCount = 12, // Maximum number of retries (12 x 10 sec = 120 sec = 2 mins) Int32 retryDelay = 1000 * 10 // Wait time default to 10sec ) { await new SynchronizationContextRemover(); ClientContext responseContext = null; if (clientContext.IsAppOnly() && string.IsNullOrEmpty(owner)) { throw new Exception("You need to set the owner in App-only context"); } var accessToken = clientContext.GetAccessToken(); using (var handler = new HttpClientHandler()) { clientContext.Web.EnsureProperty(w => w.Url); // we're not in app-only or user + app context, so let's fall back to cookie based auth if (String.IsNullOrEmpty(accessToken)) { handler.SetAuthenticationCookies(clientContext); } using (var httpClient = new PnPHttpProvider(handler)) { string requestUrl = $"{clientContext.Web.Url}/_api/SPSiteManager/Create"; var body = new { request = payload }; // Serialize request object to JSON var jsonBody = JsonConvert.SerializeObject(body); var requestBody = new StringContent(jsonBody); // Build Http request HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, requestUrl); request.Content = requestBody; request.Headers.Add("accept", "application/json;odata.metadata=none"); request.Headers.Add("odata-version", "4.0"); MediaTypeHeaderValue sharePointJsonMediaType = null; MediaTypeHeaderValue.TryParse("application/json;odata.metadata=none;charset=utf-8", out sharePointJsonMediaType); requestBody.Headers.ContentType = sharePointJsonMediaType; if (!string.IsNullOrEmpty(accessToken)) { request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken); } requestBody.Headers.Add("X-RequestDigest", await clientContext.GetRequestDigest()); // Perform actual post operation HttpResponseMessage response = await httpClient.SendAsync(request, new System.Threading.CancellationToken()); if (response.IsSuccessStatusCode) { // If value empty, URL is taken var responseString = await response.Content.ReadAsStringAsync(); if (responseString != null) { try { var responseJson = JObject.Parse(responseString); #if !NETSTANDARD2_0 if (Convert.ToInt32(responseJson["SiteStatus"]) == 2) #else if (responseJson["SiteStatus"].Value <int>() == 2) #endif { responseContext = clientContext.Clone(responseJson["SiteUrl"].ToString()); } else { /* * BEGIN : Changes to address the SiteStatus=Provisioning scenario */ if (Convert.ToInt32(responseJson["SiteStatus"]) == 1) { var spOperationsMaxRetryCount = maxRetryCount; var spOperationsRetryWait = retryDelay; var siteCreated = false; var siteUrl = string.Empty; var retryAttempt = 1; do { if (retryAttempt > 1) { System.Threading.Thread.Sleep(retryAttempt * spOperationsRetryWait); } try { var urlToCheck = HttpUtility.UrlEncode(payload["Url"].ToString()); var siteStatusRequestUrl = $"{clientContext.Web.Url}/_api/SPSiteManager/status?url='{urlToCheck}'"; var siteStatusRequest = new HttpRequestMessage(HttpMethod.Get, siteStatusRequestUrl); siteStatusRequest.Headers.Add("accept", "application/json;odata=verbose"); if (!string.IsNullOrEmpty(accessToken)) { siteStatusRequest.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken); } siteStatusRequest.Headers.Add("X-RequestDigest", await clientContext.GetRequestDigest()); var siteStatusResponse = await httpClient.SendAsync(siteStatusRequest, new System.Threading.CancellationToken()); var siteStatusResponseString = await siteStatusResponse.Content.ReadAsStringAsync(); var siteStatusResponseJson = JObject.Parse(siteStatusResponseString); if (siteStatusResponse.IsSuccessStatusCode) { var siteStatus = Convert.ToInt32(siteStatusResponseJson["d"]["Status"]["SiteStatus"].ToString()); if (siteStatus == 2) { siteCreated = true; siteUrl = siteStatusResponseJson["d"]["Status"]["SiteUrl"].ToString(); } } } catch (Exception) { // Just skip it and retry after a delay } retryAttempt++; }while (!siteCreated && retryAttempt <= spOperationsMaxRetryCount); if (siteCreated) { responseContext = clientContext.Clone(siteUrl); } else { throw new Exception($"OfficeDevPnP.Core.Sites.SiteCollection.CreateAsync: Could not create {payload["WebTemplate"].ToString()} site."); } } else { throw new Exception(responseString); } /* * END : Changes to address the SiteStatus=Provisioning scenario */ } } catch (Exception) { throw; } } // If there is a delay, let's wait if (delayAfterCreation > 0) { System.Threading.Thread.Sleep(TimeSpan.FromSeconds(delayAfterCreation)); } } else { // Something went wrong... throw new Exception(await response.Content.ReadAsStringAsync()); } } return(await Task.Run(() => responseContext)); } }
/// <summary> /// Executes a REST Get request. /// </summary> /// <param name="web">The current web to execute the request against</param> /// <param name="endpoint">The full endpoint url, exluding the URL of the web, e.g. /_api/web/lists</param> /// <returns></returns> internal static async Task <string> ExecuteGetAsync(this Web web, string endpoint) { string returnObject = null; var accessToken = web.Context.GetAccessToken(); using (var handler = new HttpClientHandler()) { web.EnsureProperty(w => w.Url); // we're not in app-only or user + app context, so let's fall back to cookie based auth if (String.IsNullOrEmpty(accessToken)) { handler.SetAuthenticationCookies(web.Context as ClientContext); } using (var httpClient = new PnPHttpProvider(handler)) { var requestUrl = $"{web.Url}{endpoint}"; HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, requestUrl); request.Headers.Add("accept", "application/json;odata=nometadata"); if (!string.IsNullOrEmpty(accessToken)) { request.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", accessToken); } else { if (web.Context.Credentials is NetworkCredential networkCredential) { handler.Credentials = networkCredential; } } var requestDigest = await(web.Context as ClientContext).GetRequestDigestAsync().ConfigureAwait(false); request.Headers.Add("X-RequestDigest", requestDigest); // Perform actual post operation HttpResponseMessage response = await httpClient.SendAsync(request, new System.Threading.CancellationToken()); if (response.IsSuccessStatusCode) { // If value empty, URL is taken var responseString = await response.Content.ReadAsStringAsync(); if (responseString != null) { try { returnObject = responseString; } catch { } } } else { // Something went wrong... throw new Exception(await response.Content.ReadAsStringAsync()); } } } return(await Task.Run(() => returnObject)); }
/// <summary> /// Requests the request digest from the current session/site /// </summary> /// <param name="context">The current ClientContext with Site-Collection-Admin-Level credentials.</param> /// <returns>The Request Digest as string.</returns> private async Task <string> BaseGetRequestDigest(ClientContext context) { //await new SynchronizationContextRemover(); JObject requestDigest = null; string requestDigestString = null; using (var handler = new HttpClientHandler()) { var accessToken = context.GetAccessToken(); context.Web.EnsureProperty(w => w.Url); if (String.IsNullOrEmpty(accessToken)) { handler.SetAuthenticationCookies(context); } using (var httpClient = new PnPHttpProvider(handler)) { string requestUrl = String.Format("{0}/_api/contextinfo", context.Web.Url); HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, requestUrl); request.Headers.Add("accept", "application/json;odata=verbose"); if (!string.IsNullOrEmpty(accessToken)) { request.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", accessToken); } else { if (context.Credentials is NetworkCredential networkCredential) { handler.Credentials = networkCredential; } } HttpResponseMessage response = await httpClient.SendAsync(request); if (response.IsSuccessStatusCode) { var responseString = await response.Content.ReadAsStringAsync(); if (responseString != null) { try { var resultCollection = Newtonsoft.Json.JsonConvert.DeserializeObject(responseString); requestDigest = resultCollection as JObject; requestDigestString = requestDigest?.First.First.First.First.Value <string>("FormDigestValue"); } catch { } } } else { var errorSb = new System.Text.StringBuilder(); errorSb.AppendLine(await response.Content.ReadAsStringAsync()); if (response.Headers.Contains("SPRequestGuid")) { var values = response.Headers.GetValues("SPRequestGuid"); if (values != null) { var spRequestGuid = values.FirstOrDefault(); errorSb.AppendLine($"ServerErrorTraceCorrelationId: {spRequestGuid}"); } } throw new Exception(errorSb.ToString()); } } return(await Task.Run(() => requestDigestString)); } }