/// <inheritdoc/> public string GetSasUrlForBlob(Uri blobUri, TimeSpan ttl, StorageClientProviderContext context) { _ = blobUri ?? throw new ArgumentNullException(nameof(blobUri)); _ = context ?? throw new ArgumentNullException(nameof(context)); try { var blobUriBuilder = new BlobUriBuilder(blobUri); // Create a SAS token that's valid for the TimeSpan, plus a back-off start for clock skew. var timeRange = StorageHelpers.CreateTimeRangeForUrl(ttl); BlobSasBuilder sasBuilder = new BlobSasBuilder { BlobContainerName = blobUriBuilder.BlobContainerName, BlobName = blobUriBuilder.BlobName, Resource = "b", // "b" is for blob StartsOn = timeRange.StartTime, ExpiresOn = timeRange.EndTime, }.UnescapeTargetPath(); // Important adjustment(s) for SAS computation sasBuilder.SetPermissions(BlobSasPermissions.Read); // read permissions only for the SAS. var sleeve = _blobBaseClientProvider.GetBlobClientSleeveForUri(blobUri, context); var userDelegation = sleeve.Service.GetUserDelegationKey(sasBuilder.StartsOn, sasBuilder.ExpiresOn)?.Value; if (userDelegation == null) { var msg = $@"Unable to get a user delegation key from the Storage service for blob {blobUri}"; _log.LogEvent(LogEventIds.StorageServiceMissingConnectionString, msg); throw new GridwichStorageServiceException(blobUri, msg, LogEventIds.StorageServiceMissingConnectionString, context.ClientRequestIdAsJObject); } var sasToken = sasBuilder.ToSasQueryParameters(userDelegation, blobUriBuilder.AccountName); blobUriBuilder.Sas = sasToken; // Construct the full URI, including the SAS token. AbsoluteUri (vs. ToString) is to ensure the %HH escaping is used. return(blobUriBuilder.ToUri().AbsoluteUri); } catch (RequestFailedException e) { var msg = $@"Unable to get a user delegation key from the Storage service for blob {blobUri}"; _log.LogEvent(LogEventIds.StorageServiceMissingConnectionString, msg); throw new GridwichStorageServiceException(blobUri, msg, LogEventIds.StorageServiceMissingConnectionString, context.ClientRequestIdAsJObject, e); } catch (Exception e) { _log.LogExceptionObject(LogEventIds.FailedToCreateBlobSasUriInStorageService, e, blobUri); throw new GridwichStorageServiceException(blobUri, "Failed to generate the SAS url.", LogEventIds.FailedToCreateBlobSasUriInStorageService, context.ClientRequestIdAsJObject, e); } }
private void InitializeSDKs() { var apiKey = _settingsProvider.GetAppSettingsValue(EnvKey); if (string.IsNullOrWhiteSpace(apiKey)) { var message = $"{EnvKey}: is null or empty"; _log.LogEvent(LogEventIds.CloudPortApiError, message); throw new ArgumentNullException(LogEventIds.CloudPortApiError.Name, message); } Telestream.Cloud.Stores.Client.Configuration storesConfiguration = new Telestream.Cloud.Stores.Client.Configuration(); storesConfiguration.ApiKey.Add("X-Api-Key", apiKey); CloudPortStoresApi = new StoresApi(storesConfiguration); // Notifications are not being used just yet, but we include them now for future possibilies. Telestream.Cloud.Notifications.Client.Configuration notificationsConfiguration = new Telestream.Cloud.Notifications.Client.Configuration(); notificationsConfiguration.ApiKey.Add("X-Api-Key", apiKey); CloudPortNotificationsApi = new NotificationsApi(notificationsConfiguration); Telestream.Cloud.VantageCloudPort.Client.Configuration cloudPortConfiguration = new Telestream.Cloud.VantageCloudPort.Client.Configuration(); cloudPortConfiguration.ApiKey.Add("X-Api-Key", apiKey); CloudPortApi = new Telestream.Cloud.VantageCloudPort.Api.VantageCloudPortApi(cloudPortConfiguration); Telestream.Cloud.Flip.Client.Configuration flipConfiguration = new Telestream.Cloud.Flip.Client.Configuration(); flipConfiguration.ApiKey.Add("X-Api-Key", apiKey); FlipApi = new FlipApi(flipConfiguration); }
public IActionResult Run( [HttpTrigger(AuthorizationLevel.Function, "get", Route = null)] HttpRequest req) { var errorMessage = string.Empty; using var mediaInfoLib = _mediaInfoProvider.GetMediaInfoLib(StorageClientProviderContext.None); string libraryVersion = mediaInfoLib?.GetOption("Info_Version", "0.7.0.0;MediaInfoDLL_Example_CS;0.7.0.0"); if (string.IsNullOrEmpty(libraryVersion)) { if (!string.IsNullOrEmpty(errorMessage)) { return(new NotFoundObjectResult(errorMessage)); } libraryVersion = $"MediaInfo.Dll: this version of the DLL is not compatible. {req?.Host}"; _logger.LogEvent(LogEventIds.MediaInfoIncompatibleDllVersion, libraryVersion); return(new NotFoundObjectResult($"{libraryVersion}")); } _logger.LogEvent(out var telemetryLink, LogEventIds.MediaInfoCompatibleDllVersion, libraryVersion); return(new ContentResult { Content = $"<HTML><BODY>{libraryVersion} {req?.Host} <a href=\"{telemetryLink}\">Link to telemetry</a></BODY></HTML>", ContentType = @"text/html", StatusCode = StatusCodes.Status200OK }); }
/// <summary> /// Initializes a new instance of the <see cref="MediaServicesV3ContentKeyPolicyService"/> class. /// </summary> /// <param name="settingsProvider">Settings provider.</param> /// <param name="log">Log provider.</param> /// <param name="identity">Identity provider.</param> public MediaServicesV3ContentKeyPolicyService(ISettingsProvider settingsProvider, IObjectLogger <MediaServicesV3ContentKeyPolicyService> log) { _log = log ?? throw new ArgumentNullException(nameof(log)); _ = settingsProvider ?? throw new ArgumentNullException(nameof(settingsProvider)); _amsDrmOpenIdConnectDiscoveryDocument = settingsProvider.GetAppSettingsValue("AmsDrmOpenIdConnectDiscoveryDocument"); _amsDrmFairPlayPfxPassword = settingsProvider.GetAppSettingsValue("AmsDrmFairPlayPfxPassword"); _amsDrmFairPlayAskHex = settingsProvider.GetAppSettingsValue("AmsDrmFairPlayAskHex"); _amsDrmFairPlayCertificateB64 = settingsProvider.GetAppSettingsValue("AmsDrmFairPlayCertificateB64"); if (string.IsNullOrEmpty(_amsDrmOpenIdConnectDiscoveryDocument)) { const string Message = "AmsDrmOpenIdConnectDiscoveryDocument is null or empty."; _log.LogEvent(LogEventIds.MediaServicesV3ConfigurationError, Message); throw new ArgumentException(Message); } if (string.IsNullOrEmpty(_amsDrmFairPlayPfxPassword)) { const string Message = "AmsDrmFairPlayPfxPassword is null or empty."; _log.LogEvent(LogEventIds.MediaServicesV3ConfigurationError, Message); throw new ArgumentException(Message); } if (string.IsNullOrEmpty(_amsDrmFairPlayAskHex)) { const string Message = "AmsDrmFairPlayAskHex is null or empty."; _log.LogEvent(LogEventIds.MediaServicesV3ConfigurationError, Message); throw new ArgumentException(Message); } if (string.IsNullOrEmpty(_amsDrmFairPlayCertificateB64)) { const string Message = "AmsDrmFairPlayCertificateB64 is null or empty."; _log.LogEvent(LogEventIds.MediaServicesV3ConfigurationError, Message); throw new ArgumentException(Message); } }
public async Task <IActionResult> Run( [HttpTrigger(AuthorizationLevel.Function, "post", Route = null)] HttpRequest req, CancellationToken cancellationToken) { if (cancellationToken.IsCancellationRequested) { _logger.LogEvent(LogEventIds.FunctionAppShuttingDown, LogEventIds.FunctionAppShuttingDown.Name); throw new OperationCanceledException("Function invoked with a canceled cancellation token."); } if (req == null) { _logger.LogEvent(LogEventIds.EventGridFunctionGotNullHttpRequest, string.Empty); return(new BadRequestObjectResult(LogEventIds.EventGridFunctionGotNullHttpRequest.Name)); } if (req.Body == null) { _logger.LogEvent(LogEventIds.EventGridFunctionGotNullHttpRequestBody, string.Empty); return(new BadRequestObjectResult(LogEventIds.EventGridFunctionGotNullHttpRequestBody.Name)); } string requestBody = string.Empty; try { using var sr = new StreamReader(req.Body); requestBody = await sr.ReadToEndAsync().ConfigureAwait(true); } catch (Exception e) when( e is ArgumentException || e is ArgumentOutOfRangeException || e is ObjectDisposedException || e is InvalidOperationException) { // TODO: Tests for these expection types _logger.LogEventObject(LogEventIds.EventGridFunctionExceptionReadingHttpRequestBody, e); string msg = $"{LogEventIds.EventGridFunctionExceptionReadingHttpRequestBody} {e.Message}"; return(new BadRequestObjectResult(msg)); } if (string.IsNullOrEmpty(requestBody)) { _logger.LogEvent(LogEventIds.EventGridFunctionGotEmptyBody, string.Empty); return(new BadRequestObjectResult(LogEventIds.EventGridFunctionGotEmptyBody.Name)); } List <EventGridEvent> eventGridEvents; try { eventGridEvents = JsonConvert.DeserializeObject <List <EventGridEvent> >(requestBody); } catch (JsonException e) { _logger.LogEventObject(LogEventIds.EventGridFunctionGotUnparsableBody, e); string msg = $"{LogEventIds.EventGridFunctionGotUnparsableBody} {e.Message}"; return(new BadRequestObjectResult(msg)); } if (eventGridEvents.Count == 0) { _logger.LogEvent(LogEventIds.EventGridFunctionGotEmptyArrayAsBody, string.Empty); return(new BadRequestObjectResult(LogEventIds.EventGridFunctionGotEmptyArrayAsBody.Name)); } try { cancellationToken.Register(() => { _logger.LogEvent(LogEventIds.FunctionAppShuttingDown, LogEventIds.FunctionAppShuttingDown.Name); }); return((IActionResult)await _eventDispatcher.DispatchEventGridEvents(eventGridEvents).ConfigureAwait(true)); } catch (OperationCanceledException oce) { _logger.LogEventObject(LogEventIds.OperationCancelException, oce); throw; } }
/// <summary> /// EncodeCreateAsync does the heavy lifting to encode and process a video asset in Azure Media Services V3. /// </summary> /// <param name="encodeCreateDTO">Data payload for creating an AMS V3 encode.</param> /// <returns>Returns true if encode request was successful, otherwise false.</returns> public async Task <ServiceOperationResultEncodeDispatched> EncodeCreateAsync(RequestMediaServicesV3EncodeCreateDTO encodeCreateDTO) { _ = encodeCreateDTO ?? throw new ArgumentNullException(nameof(encodeCreateDTO)); // 1. Get or create the transform // 2. Create input asset // 3. Create output asset // 4. Call the encode // 5. Confirm success to base class var operationContext = encodeCreateDTO.OperationContext; // 1. Get or create the transform try { if (string.IsNullOrWhiteSpace(encodeCreateDTO.TransformName)) { throw new ArgumentOutOfRangeException(nameof(encodeCreateDTO), "TransformName can not be null or whitespace"); } } catch (Exception e) { throw new GridwichEncodeCreateDataException("Invalid inputs found in EncodeCreateDTO.", encodeCreateDTO.OperationContext, e, LogEventIds.MediaServicesV3EncodeCreateDtoError); } try { await _amsV3Service.CreateTransformIfNotExistByNameAsync(encodeCreateDTO.TransformName, operationContext).ConfigureAwait(false); } catch (Exception e) { throw new GridwichMediaServicesV3CreateTransformException($"Error creating AMS V3 Transform: {encodeCreateDTO.TransformName}", LogEventIds.MediaServicesV3TransformError, operationContext, e); } // 2. Create input asset var sourceUris = Enumerable.Empty <Uri>(); try { sourceUris = encodeCreateDTO.Inputs.Select(u => new Uri(u.BlobUri, UriKind.Absolute)); if (!sourceUris.Any() || sourceUris.Count() != encodeCreateDTO.Inputs.Count()) { throw new ArgumentException("Could not parse Inputs.", nameof(encodeCreateDTO)); } // Check that all the blobs actually exist. // Create a new muted context for these operations, based on the Op context if available. var internalCorrelator = (operationContext != null) ? operationContext.DeepClone() as JObject : new JObject(); internalCorrelator.Add("~AMS-V3-Encode", $"G:{Guid.NewGuid()}"); var context = new StorageClientProviderContext(internalCorrelator, muted: true); foreach (var blobUri in sourceUris) { var exists = await _storageService.GetBlobExistsAsync(blobUri, context).ConfigureAwait(false); if (!exists) { _log.LogEventObject(LogEventIds.MediaServicesV3AttemptToUseNonexistentBlob, blobUri); throw new GridwichMediaServicesV3Exception($"Attempt to use nonexistent blob as input: {blobUri}", LogEventIds.MediaServicesV3AttemptToUseNonexistentBlob, context.ClientRequestIdAsJObject); } } } catch (Exception e) when(!(e is GridwichMediaServicesV3Exception)) { throw new GridwichEncodeCreateDataException("Invalid inputs found in EncodeCreateDTO.", encodeCreateDTO.OperationContext, e, LogEventIds.MediaServicesV3EncodeCreateDtoError); } string inputAssetName = null; try { inputAssetName = await _amsV3Service.CreateOrUpdateAssetForContainerAsync(sourceUris).ConfigureAwait(false); } catch (Exception e) { throw new GridwichMediaServicesV3CreateAssetException("Error creating/getting AMS V3 Asset.", LogEventIds.MediaServicesV3InputAssetError, operationContext, e); } // 4. Create output asset. Uri outputUri = null; try { outputUri = new Uri(encodeCreateDTO.OutputContainer, UriKind.Absolute); } catch (Exception e) { throw new GridwichEncodeInvalidOutputContainerException($"Invalid output container specified: {encodeCreateDTO.OutputContainer}", operationContext, e, LogEventIds.MediaServicesV3OutputError); } string outputAssetName = null; try { outputAssetName = await _amsV3Service.CreateOrUpdateAssetForContainerAsync(Enumerable.Empty <Uri>().Append(outputUri)).ConfigureAwait(false); } catch (Exception e) { throw new GridwichMediaServicesV3CreateAssetException($"Error creating/getting AMS V3 output Asset: {outputUri}.", LogEventIds.MediaServicesV3OutputError, operationContext, e); } // 5. Execute Encode var uniqueness = Guid.NewGuid().ToString("N", CultureInfo.InvariantCulture).Substring(0, 11); var jobName = outputAssetName + "-" + uniqueness; try { await _amsV3Service.CreateJobAsync(encodeCreateDTO.TransformName, inputAssetName, outputAssetName, jobName, encodeCreateDTO.TimeBasedEncode, new Dictionary <string, string>() { { "mediaServicesV3EncoderSpecificData", JsonConvert.SerializeObject(encodeCreateDTO) }, { "inputAssetName", inputAssetName }, { "outputAssetContainer", encodeCreateDTO.OutputContainer }, { "outputAssetName", outputAssetName }, { "operationContext", encodeCreateDTO.OperationContext.ToString() } }, operationContext).ConfigureAwait(false); } catch (Exception e) { throw new GridwichEncodeCreateJobException($"Error creating AMS V3 job: {jobName}", operationContext, e, LogEventIds.MediaServicesV3CreateJobApiError); } // 6. Confirm success to base class _log.LogEvent(LogEventIds.MediaServicesV3JobSubmitCalled, $"AMS V3 job successfully logged: {jobName}"); return(new ServiceOperationResultEncodeDispatched( workflowJobName: jobName, null, encodeCreateDTO.OperationContext)); }
/// <inheritdoc/> public async Task <string> SubmitMesJobAsync(string inputAssetId, string preset, Uri outputContainer, Uri callbackEndpoint, IDictionary <string, string> correlationData) { if (string.IsNullOrWhiteSpace(inputAssetId)) { throw new ArgumentException($@"{nameof(inputAssetId)} is invalid", nameof(inputAssetId)); } if (string.IsNullOrWhiteSpace(preset)) { throw new ArgumentException($@"{nameof(preset)} is invalid", nameof(preset)); } _ = outputContainer ?? throw new ArgumentNullException(nameof(outputContainer)); _ = callbackEndpoint ?? throw new ArgumentNullException(nameof(callbackEndpoint)); _ = correlationData ?? throw new ArgumentNullException(nameof(correlationData)); string outputAssetName; string outputAssetStorageAccountName; string jobName; try { var outputContainerUriBuilder = new BlobUriBuilder(outputContainer); outputAssetStorageAccountName = outputContainerUriBuilder.AccountName; outputAssetName = GetOutputAssetName(outputAssetStorageAccountName, outputContainerUriBuilder); jobName = GenerateJobName(outputAssetName); } catch (Exception e) { _log.LogExceptionObject(LogEventIds.MediaServicesV2FailedToParseOutputContainer, e, outputContainer); throw new GridwichEncodeCreateJobException($"Could not define output asset name or job name from {outputContainer}.", null, e, LogEventIds.MediaServicesV2FailedToParseOutputContainer); } string processorId; try { processorId = await _mediaServicesV2RestWrapper.GetLatestMediaProcessorAsync("Media Encoder Standard").ConfigureAwait(false); } catch (Exception e) { _log.LogExceptionObject(LogEventIds.MediaServicesV2FailedToGetProcessor, e, outputContainer); throw new GridwichEncodeCreateJobException($"Could not get media processor.", null, e, LogEventIds.MediaServicesV2FailedToGetProcessor); } string base64UrlEncodedCorrelationDataJsonString; try { var correlationDataJsonString = JsonConvert.SerializeObject(correlationData); base64UrlEncodedCorrelationDataJsonString = Base64UrlEncoder.Encode(correlationDataJsonString); if (base64UrlEncodedCorrelationDataJsonString.Length > 4000) { const string ErrorMsg = "UrlEncoded and serialized correlationData is larger than 4000"; _log.LogEvent(LogEventIds.MediaServicesV2CorrelationDataError, ErrorMsg, correlationData); throw new ArgumentException(ErrorMsg, nameof(correlationData)); } } catch (Exception e) { _log.LogExceptionObject(LogEventIds.MediaServicesV2CorrelationDataError, e, correlationData); throw new GridwichEncodeCreateJobException($"Could not convert correlationData.", null, e, LogEventIds.MediaServicesV2CorrelationDataError); } string notificationEndPointId; try { notificationEndPointId = await _mediaServicesV2RestWrapper.GetOrCreateNotificationEndPointAsync("AmsV2Callback", callbackEndpoint).ConfigureAwait(false); } catch (Exception e) { _log.LogExceptionObject(LogEventIds.MediaServicesV2SpecificDataError, e, callbackEndpoint); throw new GridwichEncodeCreateJobException($"Could not create notification endpoint for {callbackEndpoint}", null, e, LogEventIds.MediaServicesV2SpecificDataError); } string jobId; try { jobId = await _mediaServicesV2RestWrapper.CreateJobAsync( jobName, processorId, inputAssetId, preset, outputAssetName, outputAssetStorageAccountName, correlationData : base64UrlEncodedCorrelationDataJsonString, notificationEndPointId).ConfigureAwait(false); } catch (Exception e) { _log.LogExceptionObject(LogEventIds.MediaServicesV2SubmitMesJobFailure, e, new { jobName, processorId, inputAssetId, preset, outputAssetName, outputAssetStorageAccountName, base64UrlEncodedCorrelationDataJsonString, notificationEndPointId }); throw new GridwichEncodeCreateJobException($"Could not start media encoder standard job.", null, e, LogEventIds.MediaServicesV2SubmitMesJobFailure); } return(jobId); }
/// <summary> /// EncodeAsync does the heavy lifting to encode and process a video asset. /// </summary> /// <param name="encodeCreateDTO">encodeCreateDTO.</param> /// <returns>Returns true if encode request was successful, otherwise false.</returns> public async Task <ServiceOperationResultEncodeDispatched> EncodeCreateAsync(RequestMediaServicesV2EncodeCreateDTO encodeCreateDTO) { _ = encodeCreateDTO ?? throw new ArgumentNullException(nameof(encodeCreateDTO)); List <Uri> sourceUris = new List <Uri>(); try { sourceUris = encodeCreateDTO.Inputs.ToList().Select(u => new Uri(u.BlobUri)).ToList(); } catch (Exception e) { throw new GridwichEncodeCreateJobException($"Failed to parse Inputs", encodeCreateDTO.OperationContext, e, LogEventIds.MediaServicesV2InputError); } string inputAssetId = await _mediaServicesV2Service.CopyFilesIntoNewAsset(sourceUris).ConfigureAwait(false); var presetName = encodeCreateDTO.PresetName; TimeSpan?thumbnailTimeSpan; if (encodeCreateDTO.ThumbnailTimeSeconds == 0) { thumbnailTimeSpan = null; } else { if (encodeCreateDTO.ThumbnailTimeSeconds < 0) { throw new GridwichTimeParameterException(nameof(encodeCreateDTO.ThumbnailTimeSeconds), encodeCreateDTO.ThumbnailTimeSeconds, "Must be above zero."); } thumbnailTimeSpan = TimeSpan.FromSeconds(encodeCreateDTO.ThumbnailTimeSeconds); } var preset = _mediaServicesPreset.GetPresetForPresetName(presetName, thumbnailTimeSpan); if (string.IsNullOrEmpty(preset)) { throw new GridwichEncodeCreateJobException($"Failed for PresetName {presetName}", encodeCreateDTO.OperationContext, null, LogEventIds.MediaServicesV2PresetError); } string jobId; try { Uri callbackEndpoint = new Uri(_settingsProvider.GetAppSettingsValue("AmsV2CallbackEndpoint")); var outputContainer = new Uri(encodeCreateDTO.OutputContainer); var correlationData = new Dictionary <string, string>() { { "outputAssetContainer", outputContainer.ToString() }, { "operationContext", encodeCreateDTO.OperationContext.ToString() }, }; jobId = await _mediaServicesV2Service.SubmitMesJobAsync( inputAssetId, preset, outputContainer, callbackEndpoint, correlationData).ConfigureAwait(false); } catch (Exception e) { throw new GridwichEncodeCreateJobException($"Failed to create job.", encodeCreateDTO.OperationContext, e, LogEventIds.MediaServicesV2CreateJobError); } _log.LogEvent(LogEventIds.MediaServicesV2JobSubmitCalled, jobId); return(new ServiceOperationResultEncodeDispatched( workflowJobName: jobId, null, encodeCreateDTO.OperationContext)); }
public async Task <IActionResult> Run( [HttpTrigger(AuthorizationLevel.Function, "post", Route = null)] HttpRequest req, CancellationToken cancellationToken) { if (cancellationToken.IsCancellationRequested) { _logger.LogEvent(LogEventIds.FunctionAppShuttingDown, LogEventIds.FunctionAppShuttingDown.Name); throw new OperationCanceledException("Function invoked with a canceled cancellation token."); } try { cancellationToken.Register(() => { _logger.LogEvent(LogEventIds.FunctionAppShuttingDown, LogEventIds.FunctionAppShuttingDown.Name); }); _logger.LogEvent(LogEventIds.CallbackFunctionTriggered, $"C# HTTP trigger function processed a request. Path={req?.Path}"); // TODO: not sure why we have to get the byte array.. might be legacy code // MemoryStream stream = new MemoryStream(); // await req.Body.CopyToAsync(stream); // byte[] bodyByteArray = stream.ToArray(); string requestBody; using (var sr = new StreamReader(req.Body)) { requestBody = await sr.ReadToEndAsync().ConfigureAwait(false); } if (req.Headers.TryGetValue("ms-signature", out _)) { // TODO: need to verify headers here. However not sure how to get the signing key. MediaServicesV2NotificationMessage notificationMessage = JsonConvert.DeserializeObject <MediaServicesV2NotificationMessage>(requestBody); var eventGridEventId = System.Guid.NewGuid().ToString(); var eventToPublish = new Microsoft.Azure.EventGrid.Models.EventGridEvent { Id = eventGridEventId, Data = notificationMessage, EventTime = System.DateTime.UtcNow, EventType = CustomEventTypes.ResponseEncodeMediaServicesV2TranslateCallback, Subject = $"/{CustomEventTypes.ResponseEncodeMediaServicesV2TranslateCallback}/{eventGridEventId}", DataVersion = "1.0", }; await _publisher.PublishEventToTopic(eventToPublish).ConfigureAwait(false); _logger.LogEvent(LogEventIds.CallbackFunctionNotificationMessageProcessed, "processed notification message"); } else { _logger.LogEvent(LogEventIds.RequestIsMissingVerifyWebHookRequestSignature, "VerifyWebHookRequestSignature failed."); return(new BadRequestObjectResult("VerifyWebHookRequestSignature failed.")); } return(new OkObjectResult("OK")); } catch (OperationCanceledException oce) { _logger.LogEventObject(LogEventIds.OperationCancelException, oce); throw; } }