/// <summary> /// Validates that the request is valid. /// </summary> /// <param name="envelopeType">Type of envelope to build.</param> /// <param name="scenario">(Optional) Name of the scenario we're building an envelope for.</param> /// <param name="requestDetails"><see cref="RequestDetails"/> instance containing additional request details.</param> /// <param name="logPrefix">Logging prefix to use.</param> /// <param name="log"><see cref="ILogger"/> instance used for logging.</param> /// <returns><see cref="IActionResult"/> instance or null if request is valid.</returns> private static IActionResult ValidateRequest(string envelopeType, string scenario, RequestDetails requestDetails, string logPrefix, ILogger log) { // Check we have a valid envelopeType if (!s_allowedEnvelopeTypes.Contains(envelopeType)) { // Invalid EnvelopeType return(AzureResponseHelper.CreateFaultObjectResult(requestDetails, $"Invalid envelopeType parameter supplied - must be one of {string.Join(", ", s_allowedEnvelopeTypes)}", logPrefix, log)); } // Check that ApimInstanceName is set if (string.IsNullOrWhiteSpace(requestDetails.ApimInstanceName)) { // No ApimInstanceName set in config return(AzureResponseHelper.CreateFaultObjectResult(requestDetails, "No ApimInstanceName is set in config", logPrefix, log)); } // Check that ApimSubscriptionKey is set if (string.IsNullOrWhiteSpace(requestDetails.ApimSubscriptionKey)) { // No ApimSubscriptionKey set in config return(AzureResponseHelper.CreateFaultObjectResult(requestDetails, "No ApimSubscriptionKey is set in config", logPrefix, log)); } // We need a Scenario if we have a Document envelopeType if (string.Compare(envelopeType, EnvelopeTypeDocument, true) == 0 && string.IsNullOrWhiteSpace(scenario)) { // Missing Scenario return(AzureResponseHelper.CreateFaultObjectResult(requestDetails, "Scenario must be supplied if envelopeType is Document", logPrefix, log)); } return(null); }
public static async Task <IActionResult> Run( [HttpTrigger(AuthorizationLevel.Function, "post", Route = "convertxmltojson")] HttpRequest req, ILogger log) { // Get Request Details RequestDetails requestDetails = new RequestDetails(req, LogId); string logPrefix = $"{LogId}:{requestDetails.TrackingId}: "; // Add the tracking ID to the Response Headers if (!string.IsNullOrWhiteSpace(requestDetails.TrackingId)) { req.HttpContext.Response.Headers[HeaderConstants.AimTrackingId] = requestDetails.TrackingId; } log.LogDebug($"{logPrefix}Called with parameters messageContentType: {requestDetails.RequestContentType}, messageContentEncoding: {requestDetails.RequestContentEncoding}, messageTransferEncoding: {requestDetails.RequestTransferEncoding}, headerTrackingId: {requestDetails.TrackingId}, clearCache: {requestDetails.ClearCache}, enableTrace: {requestDetails.EnableTrace}"); bool removeOuterEnvelope = ((string)req.Query["removeOuterEnvelope"] ?? "false") == "true"; // Load the body into an XDocument XDocument xDocument; try { xDocument = XDocument.Parse(requestDetails.RequestBody); } catch (Exception ex) { return(await Task.FromResult <IActionResult>(AzureResponseHelper.CreateFaultObjectResult(requestDetails, $"An exception occurred trying to parse the supplied XML body - check that valid XML has been supplied", ex, logPrefix, log))); } // Remove all namespaces and prefixes from the XML (as not supported by JSON and we don't want to emit them) try { // Remove namespace (and prefix) from all elements and attributes foreach (XElement xElement in xDocument.Root.DescendantsAndSelf()) { xElement.Name = xElement.Name.LocalName; var query = from xAttribute in xElement.Attributes() where !xAttribute.IsNamespaceDeclaration select new XAttribute(xAttribute.Name.LocalName, xAttribute.Value); xElement.ReplaceAttributes(query.ToList()); } } catch (Exception ex) { return(await Task.FromResult <IActionResult>(AzureResponseHelper.CreateFaultObjectResult(requestDetails, $"An exception occurred trying to remove namespaces and prefixes from the supplied XML", ex, logPrefix, log))); } try { JToken json = JToken.Parse(JsonConvert.SerializeXmlNode(XmlHelper.ToXmlDocument(xDocument), Newtonsoft.Json.Formatting.Indented, removeOuterEnvelope)); return(await Task.FromResult <IActionResult>(new OkObjectResult(json))); } catch (Exception ex) { return(await Task.FromResult <IActionResult>(AzureResponseHelper.CreateFaultObjectResult(requestDetails, $"An exception occurred trying to convert XML to JSON", ex, logPrefix, log))); } }
public static async Task <IActionResult> Run( [HttpTrigger(AuthorizationLevel.Function, "post", Route = "convertjsontoxml")] HttpRequest req, ILogger log) { // Get Request Details RequestDetails requestDetails = new RequestDetails(req, LogId); string logPrefix = $"{LogId}:{requestDetails.TrackingId}: "; // Add the tracking ID to the Response Headers if (!string.IsNullOrWhiteSpace(requestDetails.TrackingId)) { req.HttpContext.Response.Headers[HeaderConstants.AimTrackingId] = requestDetails.TrackingId; } log.LogDebug($"{logPrefix}Called with parameters messageContentType: {requestDetails.RequestContentType}, messageContentEncoding: {requestDetails.RequestContentEncoding}, messageTransferEncoding: {requestDetails.RequestTransferEncoding}, headerTrackingId: {requestDetails.TrackingId}, clearCache: {requestDetails.ClearCache}, enableTrace: {requestDetails.EnableTrace}"); string rootNode = req.Query["rootNode"]; string rootNodeNamespace = req.Query["rootNodeNamespace"]; bool writeArrayAttribute = ((string)req.Query["writeArrayAttribute"] ?? "true") == "true"; bool encodeSpecialCharacters = req.Query["encodeSpecialCharacters"] == "true"; bool addMessageBodyForEmptyMessage = req.Query["addMessageBodyForEmptyMessage"] == "true"; string xmlBody = requestDetails.RequestBody; if (addMessageBodyForEmptyMessage && string.IsNullOrWhiteSpace(xmlBody)) { xmlBody = "{}"; } try { // Convert to XML XDocument xDocument = XmlHelper.ToXDocument(JsonConvert.DeserializeXmlNode(xmlBody, rootNode, writeArrayAttribute, encodeSpecialCharacters)); if (!string.IsNullOrEmpty(rootNodeNamespace)) { xDocument = XmlHelper.AddNamespace(xDocument, "ns0", rootNodeNamespace); xDocument = XmlHelper.UpdateRootQualifiedName(xDocument, "ns0"); } // Special hack for XML content - OkObjectResult doesn't support XmlDocument in Functions at this time // without adding the XmlSerializerFormmatter to the list of services // See here: https://github.com/Azure/azure-functions-host/issues/2896 return(await Task.FromResult <IActionResult>(new ContentResult() { Content = xDocument.ToString(), ContentType = "application/xml", StatusCode = 200 })); } catch (Exception ex) { return(await Task.FromResult <IActionResult>(AzureResponseHelper.CreateFaultObjectResult(requestDetails, $"An exception occurred trying to convert JSON to XML", ex, logPrefix, log))); } }
/// <summary> /// Validates that the request is valid. /// </summary> /// <param name="requestDetails"><see cref="RequestDetails"/> instance containing additional request details.</param> /// <param name="logPrefix">Logging prefix to use</param> /// <param name="log"><see cref="ILogger"/> instance used for logging.</param> /// <returns><see cref="IActionResult"/> instance or null if request is valid.</returns> private static IActionResult ValidateRequest(RequestDetails requestDetails, string logPrefix, ILogger log) { // Check that ApimInstanceName is set if (string.IsNullOrWhiteSpace(requestDetails.ApimInstanceName)) { // No ApimInstanceName set in config return(AzureResponseHelper.CreateFaultObjectResult(requestDetails, "No ApimInstanceName is set in config", logPrefix, log)); } // Check that ApimSubscriptionKey is set if (string.IsNullOrWhiteSpace(requestDetails.ApimSubscriptionKey)) { // No ApimSubscriptionKey set in config return(AzureResponseHelper.CreateFaultObjectResult(requestDetails, "No ApimSubscriptionKey is set in config", logPrefix, log)); } return(null); }
/// <summary> /// Validates that the request is valid. /// </summary> /// <param name="requestDetails"><see cref="RequestDetails"/> instance containing additional request details.</param> /// <param name="logPrefix">Logging prefix to use.</param> /// <param name="log"><see cref="ILogger"/> instance used for logging.</param> /// <returns><see cref="IActionResult"/> instance or null if request is valid.</returns> private static IActionResult ValidateRequest(RequestDetails requestDetails, string logPrefix, ILogger log) { // Check that ApimInstanceName is set if (string.IsNullOrWhiteSpace(requestDetails.ApimInstanceName)) { // No ApimInstanceName set in config return(AzureResponseHelper.CreateFaultObjectResult(requestDetails, "No ApimInstanceName is set in config", logPrefix, log)); } // Check that ApimSubscriptionKey is set if (string.IsNullOrWhiteSpace(requestDetails.ApimSubscriptionKey)) { // No ApimSubscriptionKey set in config return(AzureResponseHelper.CreateFaultObjectResult(requestDetails, "No ApimSubscriptionKey is set in config", logPrefix, log)); } // We need a Body if (requestDetails.RequestBody.Length == 0) { // Invalid body return(AzureResponseHelper.CreateFaultObjectResult(requestDetails, "A request body must be supplied", logPrefix, log)); } // Request ContentType header must be supplied if (string.IsNullOrWhiteSpace(requestDetails.RequestContentType)) { // Missing ContentType return(AzureResponseHelper.CreateFaultObjectResult(requestDetails, "Content-Type header must be supplied", logPrefix, log)); } // Request ContentType must be JSON if (!requestDetails.RequestContentType.ToLower().StartsWith("text/json") && !requestDetails.RequestContentType.ToLower().StartsWith("application/json")) { // Invalid ContentType return(AzureResponseHelper.CreateFaultObjectResult(requestDetails, $"Content-Type header must be text/json or application/json - instead it has an unsupported value of {requestDetails.RequestContentType}", logPrefix, log)); } return(null); }
public static async Task <IActionResult> Run( [HttpTrigger(AuthorizationLevel.Function, "post", Route = "sendtonextroute")] HttpRequest req, ILogger log) { // Get Request Details RequestDetails requestDetails = new RequestDetails(req, LogId); string logPrefix = $"{LogId}:{requestDetails.TrackingId}: "; // Add the tracking ID to the Response Headers if (!string.IsNullOrWhiteSpace(requestDetails.TrackingId)) { req.HttpContext.Response.Headers[HeaderConstants.AimTrackingId] = requestDetails.TrackingId; } log.LogDebug($"{logPrefix}Called with parameters messageContentType: {requestDetails.RequestContentType}, messageContentEncoding: {requestDetails.RequestContentEncoding}, messageTransferEncoding: {requestDetails.RequestTransferEncoding}, headerTrackingId: {logPrefix}, clearCache: {requestDetails.ClearCache}, enableTrace: {requestDetails.EnableTrace}"); // Validate the request IActionResult result = ValidateRequest(requestDetails, logPrefix, log); if (result != null) { return(result); } log.LogDebug($"{logPrefix}Request parameters are valid"); // Attempt to load the envelope Envelope envelope; try { log.LogDebug($"{logPrefix}Parsing the request body as an envelope"); envelope = new Envelope(requestDetails); requestDetails.UpdateTrackingId(envelope.TrackingId); // Add TrackingId header if (!string.IsNullOrEmpty(logPrefix) && req?.HttpContext?.Response?.Headers?.ContainsKey(HeaderConstants.AimTrackingId) == false) { req?.HttpContext?.Response?.Headers?.Add(HeaderConstants.AimTrackingId, logPrefix); } } catch (Exception ex) { return(AzureResponseHelper.CreateFaultObjectResult(requestDetails, $"An exception occurred trying to parse the received envelope message", ex, logPrefix, log)); } // We need a ScenarioName if (string.IsNullOrWhiteSpace(envelope.Scenario)) { // Missing ScenarioName return(AzureResponseHelper.CreateFaultObjectResult(requestDetails, "ScenarioName cannot be found in the request body", logPrefix, log)); } // Check we have a routeIndex if (envelope.RouteIndex == null) { // Invalid RouteIndex return(AzureResponseHelper.CreateFaultObjectResult(requestDetails, "RouteIndex is blank or not a number", logPrefix, log)); } // RouteIndex must not be a negative number if (envelope.RouteIndex < 0) { // Invalid RouteIndex return(AzureResponseHelper.CreateFaultObjectResult(requestDetails, "RouteIndex must be 0 or greater", logPrefix, log)); } // Check if we have any routes if (envelope.Routes == null) { // No routes to process - return an ACK log.LogDebug($"{logPrefix}No routes to process - returning an ACK"); return(new OkObjectResult(EnvelopeBuilder.BuildAckEnvelope("No routes to process", null, logPrefix))); } // Check if we're past the last route if (envelope.NextRoute == null) { // No more routes - return an ACK log.LogDebug($"{logPrefix}Have processed all routes - returning an ACK"); return(new OkObjectResult(EnvelopeBuilder.BuildAckEnvelope("Finished processing all routes", null, logPrefix))); } // Get the full RoutingSlip (including the routing parameters) from App Configuration JObject routingSlip; try { log.LogDebug($"{logPrefix}Getting the full RoutingSlip from config"); routingSlip = await new ApimRestClient(requestDetails).GetRoutingSlipAsync(envelope.Scenario); } catch (AzureResponseException arex) { // Exception occurred return(AzureResponseHelper.CreateFaultObjectResult($"An AzureResponseException occurred calling APIM to get a RoutingSlip for scenario {envelope.Scenario}", arex, logPrefix, log)); } catch (Exception ex) { // Exception occurred return(AzureResponseHelper.CreateFaultObjectResult(requestDetails, $"An exception occurred calling APIM to get a RoutingSlip for scenario {envelope.Scenario}", ex, logPrefix, log)); } // Get the array of routes JArray routes = (JArray)routingSlip?.First?.First; // Get the current route JObject currentRoute = routes[envelope.RouteIndex] as JObject; if (currentRoute == null) { return(AzureResponseHelper.CreateFaultObjectResult(requestDetails, $"Unable to find the current route, with routeIndex {envelope.RouteIndex}", logPrefix, log)); } // Get the route parameters JObject routingParameters = currentRoute["routingParameters"] as JObject; if (routingParameters == null) { return(AzureResponseHelper.CreateFaultObjectResult(requestDetails, $"Unable to find any parameters for the route with index {envelope.RouteIndex}", logPrefix, log)); } // Get the message receiver type string messageReceiverType = routingParameters?["messageReceiverType"]?.ToString(); if (string.IsNullOrWhiteSpace(messageReceiverType)) { return(AzureResponseHelper.CreateFaultObjectResult(requestDetails, $"No MessageReceiverType is set for the route with index {envelope.RouteIndex}", logPrefix, log)); } log.LogDebug($"{logPrefix}Next route MessageReceiverType is {messageReceiverType}"); JObject routeParameters = routingParameters?["parameters"] as JObject; // Increment the routeIndex envelope.IncrementRouteIndex(); // Switch by messageReceiverType switch (messageReceiverType.ToLower()) { case "microsoft.workflows.azurelogicapp": { log.LogDebug($"{logPrefix}Calling the next route LogicApp"); return(await RouteToLogicApp(envelope, routeParameters, requestDetails, logPrefix, log)); } default: { return(AzureResponseHelper.CreateFaultObjectResult(requestDetails, $"Unsupported MessageReceiverType value of {messageReceiverType}", logPrefix, log)); } } }
/// <summary> /// Sends the envelope to a LogicApp and returns the response, as an <see cref="IActionResult"/> instance. /// </summary> /// <param name="envelope"><see cref="Envelope"/> instance containing the envelope.</param> /// <param name="routeParameters"><see cref="JObject"/> instance containing the route parameters.</param> /// <param name="requestDetails"><see cref="RequestDetails"/> instance containing details about the request.</param> /// <param name="logPrefix">Logging prefix to use.</param> /// <param name="log"><see cref="ILogger"/> instance to use for logging.</param> /// <returns><see cref="Task{IActionResult}"/> instance.</returns> private static async Task <IActionResult> RouteToLogicApp(Envelope envelope, JObject routeParameters, RequestDetails requestDetails, string logPrefix, ILogger log) { // Get the ResourceId string resourceId = routeParameters["resourceId"]?.ToString(); if (string.IsNullOrWhiteSpace(resourceId)) { return(AzureResponseHelper.CreateFaultObjectResult(requestDetails, $"No resourceId is set in the parameters section for the route with index {envelope.RouteIndex}", logPrefix, log)); } string[] resourceIdParts = resourceId.Split('/'); if (resourceIdParts.Length != 3) { return(AzureResponseHelper.CreateFaultObjectResult(requestDetails, $"The resourceId that is set in the parameters section for the route with index {envelope.RouteIndex} is malformed - expected 3 parts, but received only {resourceIdParts.Length} parts", logPrefix, log)); } string resourceGroupName = resourceIdParts[1]; string logicAppName = resourceIdParts[2]; Uri logicAppCallbackUri; // Get the logicApps callback URL try { logicAppCallbackUri = await new ApimRestClient(requestDetails).GetLogicAppCallbackUrlAsync(resourceGroupName, logicAppName); log.LogDebug($"{logPrefix}Retrieved CallbackUrl for LogicApp {logicAppName}"); } catch (AzureResponseException arex) { // Exception occurred return(AzureResponseHelper.CreateFaultObjectResult($"An AzureResponseException error occurred calling APIM to get a LogicApp URL for the route with index {envelope.RouteIndex}", arex, logPrefix, log)); } catch (Exception ex) { // Exception occurred return(AzureResponseHelper.CreateFaultObjectResult(requestDetails, $"An error occurred calling APIM to get a LogicApp URL for the route with index {envelope.RouteIndex}", ex, logPrefix, log)); } // Build headers IDictionary <string, string> headers = new Dictionary <string, string>(); headers[HeaderConstants.AimClearCache] = requestDetails.ClearCache.ToString(); headers[HeaderConstants.AimEnableTracing] = requestDetails.EnableTrace.ToString(); AzureResponse response; try { // Call the LogicApp log.LogDebug($"{logPrefix}Calling LogicApp {logicAppName} using Url {logicAppCallbackUri}"); response = await new AzureRestClient(requestDetails, AzureAuthenticationEndpoints.LogicApps).SendAsync(HttpMethod.Post, logicAppCallbackUri, headers, envelope.ToString()); log.LogDebug($"{logPrefix}Finished calling LogicApp {logicAppName} - return StatusCode is {response?.StatusCode}"); } catch (AzureResponseException arex) { // Exception occurred return(AzureResponseHelper.CreateFaultObjectResult($"An AzureResponseException error occurred calling the LogicApp {logicAppName}", arex, logPrefix, log)); } catch (Exception ex) { // Exception occurred return(AzureResponseHelper.CreateFaultObjectResult(requestDetails, $"An error occurred calling the LogicApp {logicAppName}", ex, logPrefix, log)); } // The response from the LogicApp should be 200 (ACK or NACK). // If it's anything else (e.g. a 500) then it's a fault, and an envelope will need to be created. // Look at the StatusCode and the ResponseContent and work out what to return return(AzureResponseHelper.GenerateRouteResponse(requestDetails, response, "LogicApp", logicAppName, logPrefix, log)); }
public static async Task <IActionResult> Run( [HttpTrigger(AuthorizationLevel.Function, "post", Route = "resolveroutingproperties")] HttpRequest req, ILogger log) { // Get Request Details RequestDetails requestDetails = new RequestDetails(req, LogId); string logPrefix = $"{LogId}:{requestDetails.TrackingId}: "; // Add the tracking ID to the Response Headers if (!string.IsNullOrWhiteSpace(requestDetails.TrackingId)) { req.HttpContext.Response.Headers[HeaderConstants.AimTrackingId] = requestDetails.TrackingId; } log.LogDebug($"{logPrefix}called with parameters messageContentType: {requestDetails.RequestContentType}, messageContentEncoding: {requestDetails.RequestContentEncoding}, messageTransferEncoding: {requestDetails.RequestTransferEncoding}, headerTrackingId: {requestDetails.TrackingId}, clearCache: {requestDetails.ClearCache}, enableTrace: {requestDetails.EnableTrace}"); // Validate the request IActionResult result = ValidateRequest(requestDetails, logPrefix, log); if (result != null) { return(result); } log.LogDebug($"{logPrefix}Request parameters are valid"); // Attempt to load the envelope Envelope envelope; try { log.LogDebug($"{logPrefix}Parsing the request body as an envelope"); envelope = new Envelope(requestDetails); requestDetails.UpdateTrackingId(envelope.TrackingId); // Add TrackingId header if (!string.IsNullOrEmpty(requestDetails.TrackingId) && req?.HttpContext?.Response?.Headers?.ContainsKey(HeaderConstants.AimTrackingId) == false) { req?.HttpContext?.Response?.Headers?.Add(HeaderConstants.AimTrackingId, requestDetails.TrackingId); } } catch (Exception ex) { return(AzureResponseHelper.CreateFaultObjectResult(requestDetails, $"An exception occurred trying to parse the received envelope message", ex, logPrefix, log)); } // Check if we have a ScenarioName if (string.IsNullOrWhiteSpace(envelope.Scenario)) { // Missing ScenarioName return(AzureResponseHelper.CreateFaultObjectResult(requestDetails, "ScenarioName cannot be found in the request body", logPrefix, log)); } // Get the RoutingProperties from config JObject routingProperties; try { log.LogDebug($"{logPrefix}Getting full RoutingSlip from config"); routingProperties = await new ApimRestClient(requestDetails).GetRoutingPropertiesAsync(envelope.Scenario); } catch (AzureResponseException arex) { // Exception occurred AzureResponseHelper.SetCustomResponseHeaders(req, arex); return(AzureResponseHelper.CreateFaultObjectResult("An AzureResponseException error occurred calling APIM", arex, logPrefix, log)); } catch (Exception ex) { // Exception occurred return(AzureResponseHelper.CreateFaultObjectResult(requestDetails, "An error occurred calling APIM", ex, logPrefix, log)); } try { RoutingPropertyHelper.CalculateRoutingProperties(routingProperties, envelope); } catch (Exception ex) { // Exception occurred return(AzureResponseHelper.CreateFaultObjectResult(requestDetails, "An error occurred calculating routing properties", ex, logPrefix, log)); } log.LogDebug($"{logPrefix}Finished calculating routing properties - returning response"); return(new OkObjectResult(envelope.ToJObject())); }
public static async Task <IActionResult> Run( [HttpTrigger(AuthorizationLevel.Function, "post", Route = "buildenvelope/{envelopeType}/{scenario}")] HttpRequest req, string envelopeType, string scenario, ILogger log) { // Get Request Details RequestDetails requestDetails = new RequestDetails(req, LogId); string logPrefix = $"{LogId}:{requestDetails.TrackingId}: "; // Add the tracking ID to the Response Headers if (!string.IsNullOrWhiteSpace(requestDetails.TrackingId)) { req.HttpContext.Response.Headers[HeaderConstants.AimTrackingId] = requestDetails.TrackingId; } log.LogDebug($"{logPrefix}Called with parameters envelopeType: {envelopeType}, scenario: {scenario}, messageContentType: {requestDetails.RequestContentType}, messageContentEncoding: {requestDetails.RequestContentEncoding}, messageTransferEncoding: {requestDetails.RequestTransferEncoding}, headerTrackingId: {requestDetails.TrackingId}, clearCache: {requestDetails.ClearCache}, enableTrace: {requestDetails.EnableTrace}"); envelopeType = envelopeType.ToLower(); // Validate the request IActionResult result = ValidateRequest(envelopeType, scenario, requestDetails, logPrefix, log); if (result != null) { return(result); } log.LogDebug($"{logPrefix}Request parameters are valid"); JObject envelope; // Switch by envelopeType switch (envelopeType) { case EnvelopeTypeAck: { log.LogDebug($"{logPrefix}Building an ACK envelope"); envelope = EnvelopeBuilder.BuildAckEnvelope(requestDetails); break; } case EnvelopeTypeNack: { log.LogDebug($"{logPrefix}Building a NACK envelope"); envelope = EnvelopeBuilder.BuildNackEnvelope(requestDetails); break; } case EnvelopeTypeDocument: { try { log.LogDebug($"{logPrefix}Building a Content envelope"); envelope = await BuildDocumentEnvelopeAsync(scenario, requestDetails, logPrefix, log); // Update the request TrackingId if need be requestDetails.UpdateTrackingId(envelope?["header"]?["properties"]?["trackingId"]?.Value <string>()); } catch (AzureResponseException arex) { // Exception occurred AzureResponseHelper.SetCustomResponseHeaders(req, arex); return(AzureResponseHelper.CreateFaultObjectResult("An AzureResponseException error occurred building a Document envelope", arex, logPrefix, log)); } catch (Exception ex) { // Exception occurred return(AzureResponseHelper.CreateFaultObjectResult(requestDetails, "An error occurred building a Document envelope", ex, logPrefix, log)); } break; } default: { // Invalid EnvelopeType return(AzureResponseHelper.CreateFaultObjectResult(requestDetails, $"Invalid envelopeType parameter supplied - must be one of {string.Join(", ", s_allowedEnvelopeTypes)}", logPrefix, log)); } } // Add TrackingId header if (!string.IsNullOrEmpty(requestDetails.TrackingId) && req?.HttpContext?.Response?.Headers?.ContainsKey(HeaderConstants.AimTrackingId) == false) { req?.HttpContext?.Response?.Headers?.Add(HeaderConstants.AimTrackingId, requestDetails.TrackingId); } log.LogDebug($"{logPrefix}Finished building envelope - returning response"); return(new OkObjectResult(envelope)); }
public static async Task <IActionResult> Run( [HttpTrigger(AuthorizationLevel.Function, "post", Route = "wrapxmlenvelope")] HttpRequest req, ILogger log) { // Get Request Details RequestDetails requestDetails = new RequestDetails(req, LogId); string logPrefix = $"{LogId}:{requestDetails.TrackingId}: "; // Add the tracking ID to the Response Headers if (!string.IsNullOrWhiteSpace(requestDetails.TrackingId)) { req.HttpContext.Response.Headers[HeaderConstants.AimTrackingId] = requestDetails.TrackingId; } log.LogDebug($"{logPrefix}Called with parameters messageContentType: {requestDetails.RequestContentType}, messageContentEncoding: {requestDetails.RequestContentEncoding}, messageTransferEncoding: {requestDetails.RequestTransferEncoding}, headerTrackingId: {requestDetails.TrackingId}, clearCache: {requestDetails.ClearCache}, enableTrace: {requestDetails.EnableTrace}"); bool emitXmlDeclaration = ((string)req.Query["emitXmlDeclaration"] ?? "false") == "true"; string envelopeSpecNames = req.Query["envelopeSpecNames"]; // Validate the request IActionResult result = ValidateRequest(requestDetails, logPrefix, log); if (result != null) { return(await Task.FromResult <IActionResult>(result)); } if (string.IsNullOrWhiteSpace(envelopeSpecNames)) { return(await Task.FromResult <IActionResult>(AzureResponseHelper.CreateFaultObjectResult(requestDetails, $"The envelopeSpecNames query string parameter is blank - this needs to be supplied and populated with a least one envelope SpecName", logPrefix, log))); } log.LogDebug($"{logPrefix}Request parameters are valid"); // Check that BodyContent is XML if ((string.Compare(requestDetails.RequestContentType, "text/xml", true) != 0) && (string.Compare(requestDetails.RequestContentType, "application/xml", true) != 0)) { return(await Task.FromResult <IActionResult>(AzureResponseHelper.CreateFaultObjectResult(requestDetails, $"Expected an XML content type, but instead have been supplied a ContentType of {(string.IsNullOrWhiteSpace(requestDetails.RequestContentType) ? "text" : requestDetails.RequestContentType)}", logPrefix, log))); } // Attempt to load the content into an XDocument XDocument bodyDocument; try { log.LogDebug($"{logPrefix}Parsing the request body as an XDocument"); bodyDocument = XDocument.Parse(requestDetails.RequestBody); // Add TrackingId header if (!string.IsNullOrEmpty(requestDetails.TrackingId) && req?.HttpContext?.Response?.Headers?.ContainsKey(HeaderConstants.AimTrackingId) == false) { req?.HttpContext?.Response?.Headers?.Add(HeaderConstants.AimTrackingId, requestDetails.TrackingId); } } catch (Exception ex) { return(await Task.FromResult <IActionResult>(AzureResponseHelper.CreateFaultObjectResult(requestDetails, $"An exception occurred trying to parse the received XML body into an XDocument", ex, logPrefix, log))); } // Attempt to get the first EnvelopeSchema string envelopeSchemaName = envelopeSpecNames.Split(",")[0]; string envelopeSchemaContent; try { log.LogDebug($"{logPrefix}Getting schema content from IntegrationAccount"); envelopeSchemaContent = await new ApimRestClient(requestDetails).GetSchemaContentByNameAsync(envelopeSchemaName); } catch (AzureResponseException arex) { // Exception occurred AzureResponseHelper.SetCustomResponseHeaders(req, arex); return(AzureResponseHelper.CreateFaultObjectResult("An AzureResponseException error occurred calling APIM", arex, logPrefix, log)); } catch (Exception ex) { // Exception occurred return(AzureResponseHelper.CreateFaultObjectResult(requestDetails, "An error occurred calling APIM", ex, logPrefix, log)); } // TODO: Load the XSD into an XmlSchema class // TODO: Check the BizTalk IsEnvelope property is set // TODO: Check the Body XPath value is set // TODO: Generate an instance of the envelope // TODO: Select the body node using the Body xPath // TODO: Support the emitXmlDeclarationProperty // TODO: Insert body content // TODO: Return this content XDocument xmlEnvelope = bodyDocument; log.LogDebug($"{logPrefix}Finished wrapping content - returning response"); // Special hack for XML content - OkObjectResult doesn't support XmlDocument in Functions at this time // without adding the XmlSerializerFormmatter to the list of services // See here: https://github.com/Azure/azure-functions-host/issues/2896 return(await Task.FromResult <IActionResult>(new ContentResult() { Content = xmlEnvelope.ToString(), ContentType = "application/xml", StatusCode = 200 })); }
public static async Task <IActionResult> Run( [HttpTrigger(AuthorizationLevel.Function, "post", Route = "mergeproperties")] HttpRequest req, ILogger log) { // Get Request Details RequestDetails requestDetails = new RequestDetails(req, LogId); string logPrefix = $"{LogId}:{requestDetails.TrackingId}: "; // Add the tracking ID to the Response Headers if (!string.IsNullOrWhiteSpace(requestDetails.TrackingId)) { req.HttpContext.Response.Headers[HeaderConstants.AimTrackingId] = requestDetails.TrackingId; } log.LogDebug($"{logPrefix}Called with parameters messageContentType: {requestDetails.RequestContentType}, messageContentEncoding: {requestDetails.RequestContentEncoding}, messageTransferEncoding: {requestDetails.RequestTransferEncoding}, headerTrackingId: {requestDetails.TrackingId}, clearCache: {requestDetails.ClearCache}, enableTrace: {requestDetails.EnableTrace}"); // Validate the request IActionResult result = ValidateRequest(requestDetails, logPrefix, log); if (result != null) { return(await Task.FromResult <IActionResult>(result)); } log.LogDebug($"{logPrefix}Request parameters are valid"); // We expect the body to be an array of property bags // e.g. // [ // { // "properties": // { // "property1": "value1" // } // }, // { // "properties": // { // "property2": "value2" // } // } // ] // Check we have a JSON array in the body content if (!(requestDetails.RequestBodyAsJson is JArray)) { // We need an array to be supplied return(await Task.FromResult <IActionResult>(AzureResponseHelper.CreateFaultObjectResult(requestDetails, "The supplied request body is not a JSON array", logPrefix, log))); } JArray propertiesArray = requestDetails.RequestBodyAsJson as JArray; // Check we have at least one element in the array if (propertiesArray.Count == 0) { // We need at least one element in the supplied array return(await Task.FromResult <IActionResult>(AzureResponseHelper.CreateFaultObjectResult(requestDetails, "The supplied request body contains an empty JSON array", logPrefix, log))); } // Check that all the array elements are JSON Objects if (!propertiesArray.All(j => j is JObject)) { // All elements in the array must be JSON Objects return(await Task.FromResult <IActionResult>(AzureResponseHelper.CreateFaultObjectResult(requestDetails, "All elements in the supplied JSON Array must be JSON Objects", logPrefix, log))); } JObject firstElement = propertiesArray[0] as JObject; log.LogDebug($"{logPrefix}Merging property objects"); try { // Merge every subsequent element in the array (other than the first) with the first array element for (int arrayIndex = 1; arrayIndex < propertiesArray.Count; arrayIndex++) { firstElement.Merge(propertiesArray[arrayIndex] as JObject, new JsonMergeSettings { // Union array values together to avoid duplicates MergeArrayHandling = MergeArrayHandling.Union }); } } catch (Exception ex) { return(await Task.FromResult <IActionResult>(AzureResponseHelper.CreateFaultObjectResult(requestDetails, $"An exception occurred trying to merge the property bags", ex, logPrefix, log))); } return(await Task.FromResult <IActionResult>(new OkObjectResult(firstElement))); }
public static async Task <IActionResult> Run( [HttpTrigger(AuthorizationLevel.Function, "post", Route = "decodebodycontent")] HttpRequest req, ILogger log) { // Get Request Details RequestDetails requestDetails = new RequestDetails(req, LogId); string logPrefix = $"{LogId}:{requestDetails.TrackingId}: "; // Add the tracking ID to the Response Headers if (!string.IsNullOrWhiteSpace(requestDetails.TrackingId)) { req.HttpContext.Response.Headers[HeaderConstants.AimTrackingId] = requestDetails.TrackingId; } log.LogDebug($"{logPrefix}Called with parameters messageContentType: {requestDetails.RequestContentType}, messageContentEncoding: {requestDetails.RequestContentEncoding}, messageTransferEncoding: {requestDetails.RequestTransferEncoding}, headerTrackingId: {requestDetails.TrackingId}, clearCache: {requestDetails.ClearCache}, enableTrace: {requestDetails.EnableTrace}"); // Validate the request IActionResult result = ValidateRequest(requestDetails, logPrefix, log); if (result != null) { return(await Task.FromResult <IActionResult>(result)); } log.LogDebug($"{logPrefix}Request parameters are valid"); // Attempt to parse the envelope Envelope envelope; try { log.LogDebug($"{logPrefix}Parsing the request body as an envelope"); envelope = new Envelope(requestDetails); requestDetails.UpdateTrackingId(envelope.TrackingId); // Add TrackingId header if (!string.IsNullOrEmpty(requestDetails.TrackingId) && req?.HttpContext?.Response?.Headers?.ContainsKey(HeaderConstants.AimTrackingId) == false) { req?.HttpContext?.Response?.Headers?.Add(HeaderConstants.AimTrackingId, requestDetails.TrackingId); } } catch (Exception ex) { return(await Task.FromResult <IActionResult>(AzureResponseHelper.CreateFaultObjectResult(requestDetails, $"An exception occurred trying to parse the received envelope message", ex, logPrefix, log))); } // Attempt to get the decoded root part content object decodedContent; try { decodedContent = envelope.GetDecodedRootPartContent(); } catch (Exception ex) { return(await Task.FromResult <IActionResult>(AzureResponseHelper.CreateFaultObjectResult(requestDetails, $"An error occurred trying to decode the root part content", ex, logPrefix, log))); } log.LogDebug($"{logPrefix}Finished getting content - returning response"); // Special hack for XML content - OkObjectResult doesn't support XmlDocument in Functions at this time // without adding the XmlSerializerFormmatter to the list of services // See here: https://github.com/Azure/azure-functions-host/issues/2896 if (decodedContent is XmlDocument) { return(await Task.FromResult <IActionResult>(new ContentResult() { Content = ((XmlDocument)decodedContent).OuterXml, ContentType = "application/xml", StatusCode = 200 })); } return(await Task.FromResult <IActionResult>(new OkObjectResult(decodedContent))); }
public static async Task <IActionResult> Run( [HttpTrigger(AuthorizationLevel.Function, "post", Route = "getbodycontent")] HttpRequest req, ILogger log) { // Get Request Details RequestDetails requestDetails = new RequestDetails(req, LogId); string logPrefix = $"{LogId}:{requestDetails.TrackingId}: "; // Add the tracking ID to the Response Headers if (!string.IsNullOrWhiteSpace(requestDetails.TrackingId)) { req.HttpContext.Response.Headers[HeaderConstants.AimTrackingId] = requestDetails.TrackingId; } log.LogDebug($"{logPrefix}Called with parameters messageContentType: {requestDetails.RequestContentType}, messageContentEncoding: {requestDetails.RequestContentEncoding}, messageTransferEncoding: {requestDetails.RequestTransferEncoding}, headerTrackingId: {requestDetails.TrackingId}, clearCache: {requestDetails.ClearCache}, enableTrace: {requestDetails.EnableTrace}"); // Validate the request IActionResult result = ValidateRequest(requestDetails, logPrefix, log); if (result != null) { return(await Task.FromResult <IActionResult>(result)); } log.LogDebug($"{logPrefix}Request parameters are valid"); // Attempt to parse the envelope Envelope envelope; try { log.LogDebug($"{logPrefix}Parsing the request body as an envelope"); envelope = new Envelope(requestDetails); requestDetails.UpdateTrackingId(envelope.TrackingId); // Add TrackingId header if (!string.IsNullOrEmpty(requestDetails.TrackingId) && req?.HttpContext?.Response?.Headers?.ContainsKey(HeaderConstants.AimTrackingId) == false) { req?.HttpContext?.Response?.Headers?.Add(HeaderConstants.AimTrackingId, requestDetails.TrackingId); } } catch (Exception ex) { return(await Task.FromResult <IActionResult>(AzureResponseHelper.CreateFaultObjectResult(requestDetails, $"An exception occurred trying to parse the received envelope message", ex, logPrefix, log))); } // Attempt to get the encoded root part content JObject decodedContent; try { decodedContent = envelope.GetEncodedRootPartContent(); } catch (Exception ex) { return(await Task.FromResult <IActionResult>(AzureResponseHelper.CreateFaultObjectResult(requestDetails, $"An error occurred trying to encode the root part content", ex, logPrefix, log))); } log.LogDebug($"{logPrefix}Finished getting content - returning response"); return(await Task.FromResult <IActionResult>(new OkObjectResult(decodedContent))); }