private async Task <bool> SyncToTeamsImplementation(Guid appId) { // switch context to appcatalog var appcatalogUri = _context.Web.GetAppCatalog(); using (var context = _context.Clone(appcatalogUri)) { var returnValue = false; context.Web.EnsureProperty(w => w.Url); var list = context.Web.GetListByUrl("appcatalog"); var query = new CamlQuery { 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(); if (items.Count > 0) { #pragma warning disable CA2000 // Dispose objects before losing scope var httpClient = PnPHttpClient.Instance.GetHttpClient(context); #pragma warning restore CA2000 // Dispose objects before losing scope var requestUrl = $"{context.Web.Url}/_api/web/tenantappcatalog/SyncSolutionToTeams(id={items[0].Id})"; using (var request = new HttpRequestMessage(HttpMethod.Post, requestUrl)) { request.Headers.Add("accept", "application/json;odata=nometadata"); await PnPHttpClient.AuthenticateRequestAsync(request, context).ConfigureAwait(false); // Perform actual post operation HttpResponseMessage response = await httpClient.SendAsync(request, new CancellationToken()); if (response.IsSuccessStatusCode) { // If value empty, URL is taken var responseString = await response.Content.ReadAsStringAsync(); if (responseString != null) { try { returnValue = true; } catch { } } } else { // Something went wrong... throw new Exception(await response.Content.ReadAsStringAsync()); } } } return(await Task.Run(() => returnValue)); } }
internal static async Task <string> ExecutePostAsync(this Web web, string endpoint, string payload, string cultureLanguageName = null) { string returnObject = null; web.EnsureProperty(w => w.Url); #pragma warning disable CA2000 // Dispose objects before losing scope var httpClient = PnPHttpClient.Instance.GetHttpClient(context: web.Context as ClientContext); #pragma warning restore CA2000 // Dispose objects before losing scope var requestUrl = $"{web.Url}{endpoint}"; using (HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, requestUrl)) { request.Headers.Add("accept", "application/json;odata=nometadata"); await PnPHttpClient.AuthenticateRequestAsync(request, web.Context as ClientContext).ConfigureAwait(false); if (!string.IsNullOrWhiteSpace(cultureLanguageName)) { request.Headers.Add("Accept-Language", cultureLanguageName); } if (!string.IsNullOrEmpty(payload)) { var requestBody = new StringContent(payload); MediaTypeHeaderValue sharePointJsonMediaType = MediaTypeHeaderValue.Parse("application/json;odata=nometadata;charset=utf-8"); 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 { returnObject = responseString; } catch { } } } else { // Something went wrong... throw new Exception(await response.Content.ReadAsStringAsync()); } } return(await Task.Run(() => returnObject)); }
/// <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; context.Web.EnsureProperty(w => w.Url); #pragma warning disable CA2000 // Dispose objects before losing scope var httpClient = PnPHttpClient.Instance.GetHttpClient(context); #pragma warning restore CA2000 // Dispose objects before losing scope // 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}"; // Always make a POST request using (HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, requestUrl)) { request.Headers.Add("ACCEPT", "application/json; odata.metadata=minimal"); request.Headers.Add("ODATA-VERSION", "4.0"); await PnPHttpClient.AuthenticateRequestAsync(request, context).ConfigureAwait(false); 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)); }
private static async Task <AppMetadata> GetAppMetaData(AppCatalogScope scope, ClientContext context, string id) { AppMetadata returnValue = null; int retryCount = 0; int waitTime = 10; // seconds #pragma warning disable CA2000 // Dispose objects before losing scope var httpClient = PnPHttpClient.Instance.GetHttpClient(context); #pragma warning restore CA2000 // Dispose objects before losing scope var metadataRequestUrl = $"{context.Web.Url}/_api/web/{(scope == AppCatalogScope.Tenant ? "tenant" : "sitecollection")}appcatalog/AvailableApps/GetById('{id}')"; using (var metadataRequest = new HttpRequestMessage(HttpMethod.Get, metadataRequestUrl)) { metadataRequest.Headers.Add("accept", "application/json;odata=nometadata"); await PnPHttpClient.AuthenticateRequestAsync(metadataRequest, context).ConfigureAwait(false); while (returnValue == null && retryCount < 5) { // 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) { returnValue = JsonSerializer.Deserialize <AppMetadata>(metadataResponseString); } } else if (metadataResponse.StatusCode != HttpStatusCode.NotFound) { // Something went wrong... throw new Exception(await metadataResponse.Content.ReadAsStringAsync()); } if (returnValue == null) { // try again retryCount++; await Task.Delay(waitTime * 1000); // wait 10 seconds } } return(returnValue); } }
/// <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; context.Web.EnsureProperty(p => p.Url); #pragma warning disable CA2000 // Dispose objects before losing scope var httpClient = PnPHttpClient.Instance.GetHttpClient(context); #pragma warning restore CA2000 // Dispose objects before losing scope 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; using (var request = new HttpRequestMessage(HttpMethod.Post, requestUrl)) { request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); await PnPHttpClient.AuthenticateRequestAsync(request, context).ConfigureAwait(false); 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> /// 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; context.Web.EnsureProperty(p => p.Url); #pragma warning disable CA2000 // Dispose objects before losing scope var httpClient = PnPHttpClient.Instance.GetHttpClient(context); #pragma warning restore CA2000 // Dispose objects before losing scope string identifierUrl = GetResourceIdentifier(resourceType, webUrl, resourceId); if (string.IsNullOrEmpty(identifierUrl)) { throw new Exception("Identifier of the resource cannot be determined"); } string requestUrl = identifierUrl + "/" + SubscriptionsUrlPart; using (var request = new HttpRequestMessage(HttpMethod.Get, requestUrl)) { request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); await PnPHttpClient.AuthenticateRequestAsync(request, context).ConfigureAwait(false); 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)); }
/// <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(); context.Web.EnsureProperty(p => p.Url); #pragma warning disable CA2000 // Dispose objects before losing scope var httpClient = PnPHttpClient.Instance.GetHttpClient(context); #pragma warning restore CA2000 // Dispose objects before losing scope 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); using (var request = new HttpRequestMessage(HttpMethod.Delete, requestUrl)) { request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); await PnPHttpClient.AuthenticateRequestAsync(request, context).ConfigureAwait(false); HttpResponseMessage response = await httpClient.SendAsync(request, new System.Threading.CancellationToken()); if (response.StatusCode != HttpStatusCode.NoContent) { // oops...something went wrong, maybe the web hook does not exist? throw new Exception(await response.Content.ReadAsStringAsync()); } else { return(true); } } }
public static void RegisterPnPHttpClientMock(bool runAsIntegration = false, [System.Runtime.CompilerServices.CallerFilePath] string mockFolderPath = null, [System.Runtime.CompilerServices.CallerMemberName] string mockFileName = null) { string mockFilePath = mockFolderPath.Replace(".cs", $"\\{mockFileName}-http.json"); PnPHttpClient client = PnPHttpClient.Instance; var serviceCollection = new ServiceCollection(); serviceCollection.AddTransient <MockHttpHandler>((IServiceProvider provider) => { return(new MockHttpHandler(mockFilePath)); }); serviceCollection.AddTransient <StoreResponseToAFile>((IServiceProvider provider) => { return(new StoreResponseToAFile(mockFilePath)); }); if (runAsIntegration || RunInIntegrationAll) { serviceCollection.AddHttpClient("PnPHttpClient", config => { }).AddHttpMessageHandler <StoreResponseToAFile>() .ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler() { UseCookies = false }); } else { serviceCollection.AddHttpClient("PnPHttpClient", config => { }).AddHttpMessageHandler <MockHttpHandler>(); } client.SetPrivate("serviceProvider", serviceCollection.BuildServiceProvider()); }
protected override void ExecuteCmdlet() { if (Url.StartsWith("/")) { // prefix the url with the current web url Url = UrlUtility.Combine(ClientContext.Url, Url); } var method = new HttpMethod(Method.ToString()); var httpClient = PnPHttpClient.Instance.GetHttpClient(ClientContext); var requestUrl = Url; using (HttpRequestMessage request = new HttpRequestMessage(method, requestUrl)) { request.Headers.Add("accept", "application/json;odata=nometadata"); if (Method == HttpRequestMethod.Merge) { request.Headers.Add("X-HTTP-Method", "MERGE"); } if (Method == HttpRequestMethod.Merge || Method == HttpRequestMethod.Delete) { request.Headers.Add("IF-MATCH", "*"); } PnPHttpClient.AuthenticateRequestAsync(request, ClientContext).GetAwaiter().GetResult(); if (Method == HttpRequestMethod.Post || Method == HttpRequestMethod.Merge || Method == HttpRequestMethod.Put || Method == HttpRequestMethod.Patch) { if (string.IsNullOrEmpty(ContentType)) { ContentType = "application/json"; } var contentString = Content is string?Content.ToString() : JsonSerializer.Serialize(Content); request.Content = new StringContent(contentString, System.Text.Encoding.UTF8); request.Content.Headers.ContentType = MediaTypeHeaderValue.Parse(ContentType); } HttpResponseMessage response = httpClient.SendAsync(request, new System.Threading.CancellationToken()).Result; if (response.IsSuccessStatusCode) { var responseString = response.Content.ReadAsStringAsync().GetAwaiter().GetResult(); if (responseString != null) { if (!Raw) { var jsonElement = JsonSerializer.Deserialize <JsonElement>(responseString); string nextLink = string.Empty; if (jsonElement.TryGetProperty("odata.nextLink", out JsonElement nextLinkProperty)) { nextLink = nextLinkProperty.ToString(); } if (jsonElement.TryGetProperty("value", out JsonElement valueProperty)) { var formattedObject = ConvertToPSObject(valueProperty, "value"); if (!string.IsNullOrEmpty(nextLink)) { formattedObject.Properties.Add(new PSNoteProperty("odata.nextLink", nextLink)); } WriteObject(formattedObject, true); } else { WriteObject(ConvertToPSObject(jsonElement, null), true); } } else { WriteObject(responseString); } } } else { // Something went wrong... throw new Exception(response.Content.ReadAsStringAsync().GetAwaiter().GetResult()); } } }
private async Task <AppMetadata> BaseAddRequest(byte[] file, string filename, bool overwrite, int timeoutSeconds, AppCatalogScope scope) { AppMetadata returnValue = null; var isCloned = false; var context = _context; if (scope == AppCatalogScope.Tenant) { // switch context to appcatalog var appcatalogUri = _context.Web.GetAppCatalog(); #pragma warning disable CA2000 // Dispose objects before losing scope context = context.Clone(appcatalogUri); #pragma warning restore CA2000 // Dispose objects before losing scope isCloned = true; } context.Web.EnsureProperty(w => w.Url); #pragma warning disable CA2000 // Dispose objects before losing scope var httpClient = PnPHttpClient.Instance.GetHttpClient(context); #pragma warning restore CA2000 // Dispose objects before losing scope string requestUrl = $"{context.Web.Url}/_api/web/{(scope == AppCatalogScope.Tenant ? "tenant" : "sitecollection")}appcatalog/Add(overwrite={(overwrite.ToString().ToLower())}, url='{filename}')"; var requestDigest = string.Empty; using (var request = new HttpRequestMessage(HttpMethod.Post, requestUrl)) { request.Headers.Add("accept", "application/json;odata=nometadata"); await PnPHttpClient.AuthenticateRequestAsync(request, context).ConfigureAwait(false); 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 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, id); } } } } else { // Something went wrong... throw new Exception(await response.Content.ReadAsStringAsync()); } } if (isCloned) { context.Dispose(); } return(await Task.Run(() => returnValue)); }
private async Task <bool> BaseRequest(Guid id, AppManagerAction action, bool switchToAppCatalogContext, Dictionary <string, object> postObject, AppCatalogScope scope, int timeoutSeconds = 200) { var isCloned = false; var context = _context; if (switchToAppCatalogContext == true && scope == AppCatalogScope.Tenant) { // switch context to appcatalog var appcatalogUri = _context.Web.GetAppCatalog(); #pragma warning disable CA2000 // Dispose objects before losing scope context = context.Clone(appcatalogUri); #pragma warning restore CA2000 // Dispose objects before losing scope isCloned = true; } var returnValue = false; context.Web.EnsureProperty(w => w.Url); #pragma warning disable CA2000 // Dispose objects before losing scope var httpClient = PnPHttpClient.Instance.GetHttpClient(context); #pragma warning restore CA2000 // Dispose objects before losing scope httpClient.Timeout = new TimeSpan(0, 0, timeoutSeconds); var method = action.ToString(); var requestUrl = $"{context.Web.Url}/_api/web/{(scope == AppCatalogScope.Tenant ? "tenant" : "sitecollection")}appcatalog/AvailableApps/GetByID('{id}')/{method}"; using (var request = new HttpRequestMessage(HttpMethod.Post, requestUrl)) { request.Headers.Add("accept", "application/json;odata=nometadata"); await PnPHttpClient.AuthenticateRequestAsync(request, context).ConfigureAwait(false); if (postObject != null) { var jsonBody = JsonSerializer.Serialize(postObject); var requestBody = new StringContent(jsonBody); if (MediaTypeHeaderValue.TryParse("application/json;odata=nometadata;charset=utf-8", out MediaTypeHeaderValue sharePointJsonMediaType)) { requestBody.Headers.ContentType = sharePointJsonMediaType; } request.Content = requestBody; } // Perform actual post operation HttpResponseMessage response = await httpClient.SendAsync(request, new CancellationToken()); if (response.IsSuccessStatusCode) { // If value empty, URL is taken var responseString = await response.Content.ReadAsStringAsync(); if (responseString != null) { try { returnValue = true; } catch { } } } else { // Something went wrong... throw new Exception(await response.Content.ReadAsStringAsync()); } } if (isCloned) { context.Dispose(); } 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; _context.Web.EnsureProperty(w => w.Url); #pragma warning disable CA2000 // Dispose objects before losing scope var httpClient = PnPHttpClient.Instance.GetHttpClient(_context); #pragma warning restore CA2000 // Dispose objects before losing scope 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}')"; } using (HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, requestUrl)) { request.Headers.Add("accept", "application/json;odata=nometadata"); PnPHttpClient.AuthenticateRequestAsync(request, _context).GetAwaiter().GetResult(); // Perform actual post operation HttpResponseMessage response = await httpClient.SendAsync(request, new 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> /// This helper method makes an HTTP request and eventually returns a result /// </summary> /// <param name="httpMethod">The HTTP method for the request</param> /// <param name="requestUrl">The URL of the request</param> /// <param name="responseHeaders">The response headers of the HTTP request (output argument)</param> /// <param name="accessToken">The OAuth 2.0 Access Token for the request, if authorization is required</param> /// <param name="accept">The content type of the accepted response</param> /// <param name="content">The content of the request</param> /// <param name="contentType">The content type of the request</param> /// <param name="referer">The URL Referer for the request</param> /// <param name="resultPredicate">The predicate to retrieve the result, if any</param> /// <param name="requestHeaders">A collection of any custom request headers</param> /// <param name="cookies">Any request cookies values</param> /// <param name="retryCount">Number of times to retry the request</param> /// <param name="delay">Milliseconds to wait before retrying the request. The delay will be increased (doubled) every retry</param> /// <param name="userAgent">UserAgent string value to insert for this request. You can define this value in your app's config file using key="SharePointPnPUserAgent" value="PnPRocks"</param> /// <param name="spContext">An optional SharePoint client context</param> /// <typeparam name="TResult">The type of the result, if any</typeparam> /// <returns>The value of the result, if any</returns> internal static TResult MakeHttpRequest <TResult>( string httpMethod, string requestUrl, out HttpResponseHeaders responseHeaders, string accessToken = null, string accept = null, object content = null, string contentType = null, string referer = null, Func <HttpResponseMessage, TResult> resultPredicate = null, Dictionary <string, string> requestHeaders = null, Dictionary <string, string> cookies = null, int retryCount = 1, int delay = 500, string userAgent = null, ClientContext spContext = null) { //HttpClient client = HttpHelper.httpClient; HttpClient client; // Define whether to use the default HttpClient object if (spContext != null) { #pragma warning disable CA2000 // Dispose objects before losing scope client = PnPHttpClient.Instance.GetHttpClient(spContext); #pragma warning restore CA2000 // Dispose objects before losing scope } else { client = PnPHttpClient.Instance.GetHttpClient(); } // Prepare the variable to hold the result, if any TResult result = default; responseHeaders = null; if (!string.IsNullOrEmpty(referer)) { client.DefaultRequestHeaders.Referrer = new Uri(referer); } // If there is an accept argument, set the corresponding HTTP header if (!string.IsNullOrEmpty(accept)) { client.DefaultRequestHeaders.Accept.Clear(); client.DefaultRequestHeaders.Accept.Add( new MediaTypeWithQualityHeaderValue(accept)); } // Process any additional custom request headers if (requestHeaders != null) { foreach (var requestHeader in requestHeaders) { client.DefaultRequestHeaders.Add(requestHeader.Key, requestHeader.Value); } } // Prepare the content of the request, if any HttpContent requestContent = null; System.IO.Stream streamContent = content as System.IO.Stream; if (streamContent != null) { requestContent = new StreamContent(streamContent); requestContent.Headers.ContentType = new MediaTypeHeaderValue(contentType); } else if (content != null) { var jsonString = content is string ?content.ToString() : JsonConvert.SerializeObject(content, Formatting.None, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore, ContractResolver = new ODataBindJsonResolver(), }); requestContent = new StringContent(jsonString, Encoding.UTF8, contentType); } // Prepare the HTTP request message with the proper HTTP method using (HttpRequestMessage request = new HttpRequestMessage(new HttpMethod(httpMethod), requestUrl)) { // Set the request content, if any if (requestContent != null) { request.Content = requestContent; } if (spContext != null) { PnPHttpClient.AuthenticateRequestAsync(request, spContext).GetAwaiter().GetResult(); } else { PnPHttpClient.AuthenticateRequest(request, accessToken); } // Fire the HTTP request HttpResponseMessage response = client.SendAsync(request).Result; if (response.IsSuccessStatusCode) { // If the response is Success and there is a // predicate to retrieve the result, invoke it if (resultPredicate != null) { result = resultPredicate(response); } // Get any response header and put it in the answer responseHeaders = response.Headers; } else { throw new ApplicationException( string.Format("Exception while invoking endpoint {0}.", requestUrl), new Exception(response.Content.ReadAsStringAsync().Result)); } } return(result); }
/// <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(); context.Web.EnsureProperty(p => p.Url); #pragma warning disable CA2000 // Dispose objects before losing scope var httpClient = PnPHttpClient.Instance.GetHttpClient(context); #pragma warning restore CA2000 // Dispose objects before losing scope 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); using (var request = new HttpRequestMessage(new HttpMethod("PATCH"), requestUrl)) { request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); await PnPHttpClient.AuthenticateRequestAsync(request, context).ConfigureAwait(false); WebhookSubscription webhookSubscription; if (string.IsNullOrEmpty(webHookEndPoint)) { webhookSubscription = new WebhookSubscription() { ExpirationDateTime = expirationDateTime }; } else { webhookSubscription = new WebhookSubscription() { NotificationUrl = webHookEndPoint, ExpirationDateTime = expirationDateTime }; } request.Content = new StringContent(JsonConvert.SerializeObject(webhookSubscription), Encoding.UTF8, "application/json"); HttpResponseMessage response = await httpClient.SendAsync(request, new System.Threading.CancellationToken()); if (response.StatusCode != HttpStatusCode.NoContent) { // oops...something went wrong, maybe the web hook does not exist? throw new Exception(await response.Content.ReadAsStringAsync()); } else { return(true); } } }