最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

c# - HTTP function doesn't wait for response - Stack Overflow

programmeradmin1浏览0评论

I am having the worst time of my life trying to get this Power Automate Flow to work.

I have made a Power Automate flow that was extracting a Purchase Order from Invoices. It was triggered on every new email on an inbox. I am cycling through the pdf attachments, calling the AI builder to extract information from the invoice, and get the Purchase Order.

I needed more accurate options in finding the Purchase Order, so I moved the logic of the extracting the purchase order to an API call. Now the flow just sends the pdf to the Endpoint and I can handle all the functionality in C#, and return the necessary details so the flow can continue.

This API call takes around 20 seconds in Postman. When I try to call it in my flow, it times out.

I attached a debugger to my API, and I found that right when I am waiting for a response from the AI client, the Flow is resending the request. It results in an endless loop. I know the call to the endpoint is working, because I can return an OK response before the AI call and it works.

How do I get my HTTP request to wait for this result? Or is it an issue with the async-ness of the client AI call? I have noticed when I'm debugging that my breakpoint is always lost on the first call to the aiClient, which is the first async operation in the call.

Here is the code-view of the HTTP call in Power Automate

    "inputs": {
        "method": "POST",
        "uri": "REDACTED",
        "headers": {
            "Connection": "keep-alive",
            "Accept": "*/*",
            "Host": "REDACTED",
            "Accept-Encoding": "gzip, deflate, br"
        },
        "body": {
            "$content-type": "multipart/form-data",
            "$multipart": [
                {
                    "headers": {
                        "Content-Disposition": "form-data; name=\"invoicePdf\"; filename=\"invoicePdf.pdf\""
                    },
                    "body": "@outputs('Get_file_content')"
                }
            ]
        },
        "authentication": {
            "type": "Basic",
            "username": "REDACTED",
            "password": "REDACTED"
        }
    },
    "operationOptions": "DisableAsyncPattern",
    "metadata": {
        "operationMetadataId": "38dae010-f79b-4c3e-ae7c-22a6047b4151"
    }
}

Here is my C# method with the ai calls:

        {
            // Check if a file was uploaded
            if (invoicePdf == null || invoicePdf.Length == 0)
            {
                return BadRequest("No file uploaded.");
            }

            // Check if the file is a PDF
            if (!invoicePdf.FileName.EndsWith(".pdf"))
            {
                return BadRequest("Only PDF files are allowed.");
            }

            AzureKeyCredential credential = new AzureKeyCredential(AppSettings.AzureAiServiceKey);
            DocumentAnalysisClient aiClient = new DocumentAnalysisClient(new Uri(AppSettings.AzureAiServiceEndpoint), credential);

            //var operation = await aiClient.AnalyzeDocumentAsync(WaitUntil.Completed, "prebuilt-invoice", invoicePdf.OpenReadStream());
            var invoiceOperation = aiClient.AnalyzeDocumentAsync(WaitUntil.Completed, "prebuilt-invoice",
                invoicePdf.OpenReadStream(), new AnalyzeDocumentOptions
                {
                    Pages = { "1-2" }
                }).Result;

            var invoiceResult = invoiceOperation.Value;

            //check default area
            for (int i = 0; i < invoiceResult.Documents.Count; i++)
            {
                var document = invoiceResult.Documents[i];

                //try to find the purchase order from the default area
                if (document.Fields.ContainsKey("PurchaseOrder"))
                {
                    document.Fields.TryGetValue("PurchaseOrder", out var purchaseOrderObject);

                    var purchaseOrderValue = purchaseOrderObject.Content;
                    var purchaseOrderConfidence = purchaseOrderObject.Confidence;

                    var sanitizedPurchaseOrderValue = SanitizePurchaseOrder(purchaseOrderValue);

                    return Ok(new
                    {
                        Found = true,
                        PurchaseOrderValue = sanitizedPurchaseOrderValue,
                        PurchaseOrderConfidence = purchaseOrderConfidence,
                        FoundIn = "Default Location"
                    });
                }
            }

            var layoutOperation = aiClient.AnalyzeDocumentAsync(WaitUntil.Completed, "prebuilt-document",
                invoicePdf.OpenReadStream(), new AnalyzeDocumentOptions
                {
                    Pages = { "1-2" }
                }).Result;

            var layoutResult = layoutOperation.Value;
            DocumentKeyValuePair? poKeyValuePair;

            poKeyValuePair = layoutResult.KeyValuePairs.FirstOrDefault(x => firstPriorityKeys.Contains(x.Key.Content));
            if (poKeyValuePair == null)
            {
                poKeyValuePair = layoutResult.KeyValuePairs.FirstOrDefault(x => secondPriorityKeys.Contains(x.Key.Content));
                if (poKeyValuePair == null)
                {
                    poKeyValuePair = layoutResult.KeyValuePairs.FirstOrDefault(x => thirdPriorityKeys.Contains(x.Key.Content));
                    if (poKeyValuePair == null)
                    {
                        poKeyValuePair = layoutResult.KeyValuePairs.FirstOrDefault(x => fourthPriorityKeys.Contains(x.Key.Content));
                        if (poKeyValuePair == null)
                        {
                            poKeyValuePair = layoutResult.KeyValuePairs.FirstOrDefault(x => fifthPriorityKeys.Contains(x.Key.Content));
                        }
                    }
                }
            }

            if (poKeyValuePair != null)
            {
                var sanitizedPurchaseOrderValue = SanitizePurchaseOrder(poKeyValuePair.Value.Content);

                return Ok(new
                {
                    Found = true,
                    PurchaseOrderValue = sanitizedPurchaseOrderValue,
                    PurchaseOrderConfidence = poKeyValuePair.Confidence,
                    FoundIn = $"{poKeyValuePair.Key.Content} (KVP)"
                });
            }

            //check plain text with regex
            Regex regex =
                new Regex(@"([Pp][Oo]|[Pp][Uu][Rr][Cc][Hh][Aa][Ss][Ee]\s?[Oo][Rr][Dd][Ee][Rr]).{0,3}(\d{7})");
            Match match = regex.Match(layoutResult.Content);
            if (match.Success)
            {
                var foundPo = match.Value;
                var sanitizedPurchaseOrderValue = SanitizePurchaseOrder(foundPo);

                return Ok(new
                {
                    Found = true,
                    PurchaseOrderValue = sanitizedPurchaseOrderValue,
                    PurchaseOrderConfidence = 0.5,
                    FoundIn = "Plain Text Regex Parse"
                });

            }

            return Ok(new
            {
                Found = false
            });
        }

Summary

  • The Power Automate Flow's HTTP call doesn't wait for a response
  • It works in Postman, but takes around 20 seconds
  • Is there a way I can get the Flow to wait for this response?

I am having the worst time of my life trying to get this Power Automate Flow to work.

I have made a Power Automate flow that was extracting a Purchase Order from Invoices. It was triggered on every new email on an inbox. I am cycling through the pdf attachments, calling the AI builder to extract information from the invoice, and get the Purchase Order.

I needed more accurate options in finding the Purchase Order, so I moved the logic of the extracting the purchase order to an API call. Now the flow just sends the pdf to the Endpoint and I can handle all the functionality in C#, and return the necessary details so the flow can continue.

This API call takes around 20 seconds in Postman. When I try to call it in my flow, it times out.

I attached a debugger to my API, and I found that right when I am waiting for a response from the AI client, the Flow is resending the request. It results in an endless loop. I know the call to the endpoint is working, because I can return an OK response before the AI call and it works.

How do I get my HTTP request to wait for this result? Or is it an issue with the async-ness of the client AI call? I have noticed when I'm debugging that my breakpoint is always lost on the first call to the aiClient, which is the first async operation in the call.

Here is the code-view of the HTTP call in Power Automate

    "inputs": {
        "method": "POST",
        "uri": "REDACTED",
        "headers": {
            "Connection": "keep-alive",
            "Accept": "*/*",
            "Host": "REDACTED",
            "Accept-Encoding": "gzip, deflate, br"
        },
        "body": {
            "$content-type": "multipart/form-data",
            "$multipart": [
                {
                    "headers": {
                        "Content-Disposition": "form-data; name=\"invoicePdf\"; filename=\"invoicePdf.pdf\""
                    },
                    "body": "@outputs('Get_file_content')"
                }
            ]
        },
        "authentication": {
            "type": "Basic",
            "username": "REDACTED",
            "password": "REDACTED"
        }
    },
    "operationOptions": "DisableAsyncPattern",
    "metadata": {
        "operationMetadataId": "38dae010-f79b-4c3e-ae7c-22a6047b4151"
    }
}

Here is my C# method with the ai calls:

        {
            // Check if a file was uploaded
            if (invoicePdf == null || invoicePdf.Length == 0)
            {
                return BadRequest("No file uploaded.");
            }

            // Check if the file is a PDF
            if (!invoicePdf.FileName.EndsWith(".pdf"))
            {
                return BadRequest("Only PDF files are allowed.");
            }

            AzureKeyCredential credential = new AzureKeyCredential(AppSettings.AzureAiServiceKey);
            DocumentAnalysisClient aiClient = new DocumentAnalysisClient(new Uri(AppSettings.AzureAiServiceEndpoint), credential);

            //var operation = await aiClient.AnalyzeDocumentAsync(WaitUntil.Completed, "prebuilt-invoice", invoicePdf.OpenReadStream());
            var invoiceOperation = aiClient.AnalyzeDocumentAsync(WaitUntil.Completed, "prebuilt-invoice",
                invoicePdf.OpenReadStream(), new AnalyzeDocumentOptions
                {
                    Pages = { "1-2" }
                }).Result;

            var invoiceResult = invoiceOperation.Value;

            //check default area
            for (int i = 0; i < invoiceResult.Documents.Count; i++)
            {
                var document = invoiceResult.Documents[i];

                //try to find the purchase order from the default area
                if (document.Fields.ContainsKey("PurchaseOrder"))
                {
                    document.Fields.TryGetValue("PurchaseOrder", out var purchaseOrderObject);

                    var purchaseOrderValue = purchaseOrderObject.Content;
                    var purchaseOrderConfidence = purchaseOrderObject.Confidence;

                    var sanitizedPurchaseOrderValue = SanitizePurchaseOrder(purchaseOrderValue);

                    return Ok(new
                    {
                        Found = true,
                        PurchaseOrderValue = sanitizedPurchaseOrderValue,
                        PurchaseOrderConfidence = purchaseOrderConfidence,
                        FoundIn = "Default Location"
                    });
                }
            }

            var layoutOperation = aiClient.AnalyzeDocumentAsync(WaitUntil.Completed, "prebuilt-document",
                invoicePdf.OpenReadStream(), new AnalyzeDocumentOptions
                {
                    Pages = { "1-2" }
                }).Result;

            var layoutResult = layoutOperation.Value;
            DocumentKeyValuePair? poKeyValuePair;

            poKeyValuePair = layoutResult.KeyValuePairs.FirstOrDefault(x => firstPriorityKeys.Contains(x.Key.Content));
            if (poKeyValuePair == null)
            {
                poKeyValuePair = layoutResult.KeyValuePairs.FirstOrDefault(x => secondPriorityKeys.Contains(x.Key.Content));
                if (poKeyValuePair == null)
                {
                    poKeyValuePair = layoutResult.KeyValuePairs.FirstOrDefault(x => thirdPriorityKeys.Contains(x.Key.Content));
                    if (poKeyValuePair == null)
                    {
                        poKeyValuePair = layoutResult.KeyValuePairs.FirstOrDefault(x => fourthPriorityKeys.Contains(x.Key.Content));
                        if (poKeyValuePair == null)
                        {
                            poKeyValuePair = layoutResult.KeyValuePairs.FirstOrDefault(x => fifthPriorityKeys.Contains(x.Key.Content));
                        }
                    }
                }
            }

            if (poKeyValuePair != null)
            {
                var sanitizedPurchaseOrderValue = SanitizePurchaseOrder(poKeyValuePair.Value.Content);

                return Ok(new
                {
                    Found = true,
                    PurchaseOrderValue = sanitizedPurchaseOrderValue,
                    PurchaseOrderConfidence = poKeyValuePair.Confidence,
                    FoundIn = $"{poKeyValuePair.Key.Content} (KVP)"
                });
            }

            //check plain text with regex
            Regex regex =
                new Regex(@"([Pp][Oo]|[Pp][Uu][Rr][Cc][Hh][Aa][Ss][Ee]\s?[Oo][Rr][Dd][Ee][Rr]).{0,3}(\d{7})");
            Match match = regex.Match(layoutResult.Content);
            if (match.Success)
            {
                var foundPo = match.Value;
                var sanitizedPurchaseOrderValue = SanitizePurchaseOrder(foundPo);

                return Ok(new
                {
                    Found = true,
                    PurchaseOrderValue = sanitizedPurchaseOrderValue,
                    PurchaseOrderConfidence = 0.5,
                    FoundIn = "Plain Text Regex Parse"
                });

            }

            return Ok(new
            {
                Found = false
            });
        }

Summary

  • The Power Automate Flow's HTTP call doesn't wait for a response
  • It works in Postman, but takes around 20 seconds
  • Is there a way I can get the Flow to wait for this response?
Share Improve this question edited Nov 25, 2024 at 6:55 DarkBee 15.5k8 gold badges72 silver badges117 bronze badges asked Nov 20, 2024 at 6:28 impoimpo 7971 gold badge11 silver badges41 bronze badges 4
  • 1 Is there a reason that you're not awaiting your async calls and using .Result? According to Microsoft's documentation, async methods should always be awaited using await asyncmethod() and using AyncMethod().Result should be avoided. learn.microsoft/en-us/dotnet/csharp/… – akseli Commented Nov 21, 2024 at 23:12
  • Ah, that was a last ditch attempt to make the thread wait for the response. I thought maybe the reason the Flow wasn't waiting for the await, so if I removed it maybe it would? I tried asyncs and await, and .Results, and updating the settings of the HTTP action in Flow, but nothing worked – impo Commented Nov 21, 2024 at 23:19
  • 1 Have you tried modifying the TImeOut and Retry policy so it uses a fixed interval between retries set to 60 seconds, for example? – akseli Commented Nov 21, 2024 at 23:33
  • @askeli yes, I tried that too and it didn't work. I find it hard to troubleshoot the action settings, but I was spending too much time on it so I changed the API to two endpoints and instead of sending the whole pdf I send the AI action output instead. It's not ideal, but it works – impo Commented Nov 22, 2024 at 0:21
Add a comment  | 

1 Answer 1

Reset to default 0

How incredibly frustrating... I have found a workaround.

I have updated my endpoint to take in a base64 encoded string.

And I have updated to Power Automate flow to use the Get Attachment (V2) call instead of using the New email trigger's attachments.

For some reason it works now... I have no idea what the different between the attachments from the trigger and the attachments from the call are, but switching it has worked.

And I'm fairly confident the problem was with getting the attachments from the trigger, and not the Get Attachment (V2) call

发布评论

评论列表(0)

  1. 暂无评论