Azure Function Generic Webhook - c#

Using Visual Studio 2017, I created a Function App with a Generic WebHook:
public static class FunctionWebHook
{
[FunctionName("FunctionWebHook")]
public static async Task<object> Run([HttpTrigger(WebHookType = "genericJson")]HttpRequestMessage request, TraceWriter log)
{
log.Info($"Webhook was triggered!");
string jsonContent = await request.Content.ReadAsStringAsync();
log.Info(jsonContent);
return request.CreateResponse(HttpStatusCode.NoContent);
}
}
The code is little more than the default template. I deployed this to my Azure account and tried to invoke it. I used the 'Get function url' link on the portal to get the correct URL, this included both the code and clientId parameters. When I try to POST JSON to the function (with content type set to application/json) I receive a 400 Bad Request:
{"Message":"The 'code' query parameter provided in the HTTP request did not match the expected value."}
I've check the code parameter and it is correct. I've also re-created the Function App several times, however I continue to receive the error. When I invoke the function using the Portal's Run command it executes correctly.
Has anyone come across this issue before?

So I use Restlet Client for any API work and it seems it has a strange issue. I copied the default (Host Key) from the Portal and pasted the URL into the Restlet Client and for some reason the last '==' of the code parameter is dropped. I tried the request using Postman and that request worked!
Thanks for all of the comments and the reply!

Which key did you choose to authenticate your request? There are 3 types of keys. Please choose the default(Function key) and use the generated URL and the key. I tested it on my side and the function key could pass the validation from server.
For more information of function key and host key, link below is for your reference.
Azure Function WebHook API Keys

Related

Azure Function App - HttpContext IServerVariablesFeature not supported in local environment

I am running an azure function app with runtime 4, .NET 6.0.
When I call the function app in a locally running environment the req.HttpContext.GetServerVariable() always returns null because the IServerVariablesFeature is not supported in the list of context.Features.
When I deploy this to an azure hosted instance of the function app, the variables are populated correctly. I have done extensive research and have been unable to find out if this is intentionally not supported or if I am missing some form of additional configuration in my local environment.
Here is a test function that attempts to read 3 different server variables and returns them as a string and can be called using a get request in postman or via a browser http://localhost:7071/api/GetServerVariable:
public static class TestFunction
{
[FunctionName("GetServerVariable")]
public static async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "GetServerVariable")] HttpRequest req,
ILogger log)
{
log.LogInformation("C# HTTP trigger function processed a request.");
var url = req.HttpContext.GetServerVariable("URL");
var remoteAddr = req.HttpContext.GetServerVariable("REMOTE_ADDR");
var https = req.HttpContext.GetServerVariable("HTTPS");
var response = $"Current server variables: URL: {url} - REMOTE_ADDR: {remoteAddr} - HTTPS: {https}";
log.LogWarning(response);
return new OkObjectResult(response);
}
}
According to this document, GetServerVariable returns
null if the server does not support the IServerVariablesFeature feature. May return null or empty if the variable does not exist or is not set.
One of the workaround is to include Forwarded headers Middleware:
Before the request reaches the app, proxy servers, load balancers, and other network appliances usually hide information about the request. The original scheme is lost when HTTPS requests are proxied via HTTP and must be transmitted in a header. The originating client IP address must also be forwarded in a header because an app receives a request from the proxy rather than its true source on the Internet or corporate network.
From the MSDN article:
Although retrieving just the REMOTE_ADDR server variable should be enough, I found resources online that suggested that code like this should also check the HTTP_X_FORWARDED_FOR variable; if the request comes through a proxy server that translates the address, it's this variable that contains the correct address. If you request a server variable that doesn't exist, the ServerVariables property returns an empty string. Therefore, even though this property doesn't appear in my tests, attempting to retrieve its value doesn't cause trouble.
The Forwarded Headers Middleware reads the headers X-Forwarded-For, X-Forwarded-Host and X-Forwarded-Proto and fills in the associated fields on HttpContext.
REFERENCES:- How to access server variables in ASP.Net Core

"The signature for the webhook is not present in the Stripe-Signature header."

I am using Stripe.net SDK from NuGet. I always get the exception from StripeEventUtility.ConstructEvent method.
The WebHook key is correct, the Request Header contains "Stripe-Signature" keys.
I correctly receive incoming data from the Webhook tester utility (using nGrok with Visual Studio).
I tried to manipulate the incoming data from Stripe (Jobject, string, serializing...). The payload signature may cause some problem.
Has anybody had the same problem?
Webhook tester utility
Are you referring to the Stripe CLI, using the listen command and forwarding to your endpoint? If so, it's important that you use the webhook secret returned by the listen command, and not one related to a configured endpoint on your Dashboard.
The other main source of this issue is mutation of the request body. Signature verification depends strictly on having access to the raw body of the request, including original whitespace etc.
See this sample implementation of a webhook endpoint in .NET accessing the raw request body: https://github.com/stripe-samples/accept-a-payment/blob/main/custom-payment-flow/server/dotnet/Controllers/PaymentsController.cs#L86

Azure durable function "terminatePostUri" gives 404 when triggered

I'm creating an Azure Durable function app where the orchestrator run for a while but I need an option to cancel the orchestrator if needed. I'm trying to use the "terminatePostUri" from Postman but it gives me a 404 response.
Other instance management uris like statusQueryGetUri are working as expected.
Here's a code snippet of my Terminate Function.
[FunctionName("klaviyo_terminate_instance")]
public static Task Run([DurableClient(TaskHub = "%KlaviyoTaskHub%")] IDurableOrchestrationClient client,
[QueueTrigger("terminate-queue")] string instanceId)
{
return client.TerminateAsync(instanceId, "Called for terminate instance");
}
Here's the postman response.
So apparently the terminate uri works as a POST request (but not GET) despite not having any payload. Not sure what the reason for that is.
Source: https://learn.microsoft.com/en-us/azure/azure-functions/durable/durable-functions-http-api

401 Unauthorized when querying durable function status

I need some help with Azure Durable Functions.
I created a new durable function with VS Code in C# and deployed it to Azure via the VS Code azure function extension. The function app resource was already created manually in the portal. I use
FUNCTIONS_WORKER_RUNTIME: dotnet
FUNCTIONS_EXTENSION_VERSION: ~2
I can trigger the creation of an durable task and but when I query the status with the statusQueryGetUri, I only get a 401 Unauthrized. The http trigger of the function itself is anonymous and does not require authentication (for debug purpose only).
The requests look like this (I used Postman to send the requests):
HTTP POST https://{function-app}.azurewebsites.net/api/SayHello_HttpStart
Response:
{
"id": "da3259a462084e86a34f8ce9859a6ed6",
"statusQueryGetUri": "https://{function-app}.azurewebsites.net/runtime/webhooks/durabletask/instances/da3259a462084e86a34f8ce9859a6ed6?taskHub=DurableFunctionsHub&connection=Storage&code=ua4tHacVv9JDH5phKCJI1OdKGXQSB/MMUX8WIv1E0OyZANqrRY3L/g==",
"sendEventPostUri": "https://{function-app}.azurewebsites.net/runtime/webhooks/durabletask/instances/da3259a462084e86a34f8ce9859a6ed6/raiseEvent/{eventName}?taskHub=DurableFunctionsHub&connection=Storage&code=ua4tHacVv9JDH5phKCJI1OdKGXQSB/MMUX8WIv1E0OyZANqrRY3L/g==",
"terminatePostUri": "https://{function-app}.azurewebsites.net/runtime/webhooks/durabletask/instances/da3259a462084e86a34f8ce9859a6ed6/terminate?reason={text}&taskHub=DurableFunctionsHub&connection=Storage&code=ua4tHacVv9JDH5phKCJI1OdKGXQSB/MMUX8WIv1E0OyZANqrRY3L/g==",
"rewindPostUri": "https://{function-app}.azurewebsites.net/runtime/webhooks/durabletask/instances/da3259a462084e86a34f8ce9859a6ed6/rewind?reason={text}&taskHub=DurableFunctionsHub&connection=Storage&code=ua4tHacVv9JDH5phKCJI1OdKGXQSB/MMUX8WIv1E0OyZANqrRY3L/g==",
"purgeHistoryDeleteUri": "https://{function-app}.azurewebsites.net/runtime/webhooks/durabletask/instances/da3259a462084e86a34f8ce9859a6ed6?taskHub=DurableFunctionsHub&connection=Storage&code=ua4tHacVv9JDH5phKCJI1OdKGXQSB/MMUX8WIv1E0OyZANqrRY3L/g=="
}
The Get Request is then simply:
GET https://{function-app}.azurewebsites.net/runtime/webhooks/durabletask/instances/da3259a462084e86a34f8ce9859a6ed6?taskHub=DurableFunctionsHub&connection=Storage&code=ua4tHacVv9JDH5phKCJI1OdKGXQSB/MMUX8WIv1E0OyZANqrRY3L/g==
Did I miss some configuration I have to set to allow access to the uri? What logs might help me figure out what the problem is?
When I run the code locally there are no problems and everything works as expected.
Thanks a lot for all help!
Note that the statusQueryGetUri is an admin endpoint which always requires a System Key.
GET <rootUrl>/runtime/webhooks/durabletask/instances/<GUID>
?taskHub={taskHub}
&connection={connection}
&code={systemKey}
As an alternative, you could also set the x-functions-key header of the http request with this key.
More info on the usage of the HTTP endpoints in the docs.

Unable To Post Webhook To C# Application On Azure

I am working on an email program for a WordPress WooCommerce store. I have added a webhook into the WooCommerce settings in order to hit a C# WebAPI application that I have created. I am trying to get run an email process every time an order is created.
I created an API controller with that accepts the JSON data that is sent over from WooCommerce, and when testing it locally from a Postman request, the controller is hit no problem.
I am trying to publish the application on Azure, and when I do, I am getting a 400 error from both the WooCommerce settings as well as any Postman requests.
I have tried setting
<system.webServer>
<httpErrors existingResponse="PassThrough"/>
</system.webServer>
in the web.config file, which then returned a 502 error from Postman, but still the same error on the WooCommerce webhook side.
I also tried re-deploying which did not work either.
I am able to view the homepage as well as the API controller link on the standard MVC homepage/menu view.
The controller is a standard API controller inheriting from the APIController class:
public class OrdersController : ApiController
and it contains one method, ProcessOrders, with an [HttpGet, HttpPost] attribute on it, and a route of /api/orders/callback.
The controller is responsible for inserting the payload from the webhook into the database and then it uses some other classes email out some specific information about the product.
Is there some kind of setting that needs to be set in the Azure portal or on the web.config file? I am not very experienced with Azure so I am not too familiar if there is anything else that needs to be done for this.
Azure Information
I am deploying to azure from quick publish inside Visual Studio
A Pay-As-You-Go resource group
.Net Framework version 4.7
Remote debugging enabled
Web App app service
The only App service setting is WEBSITE_NODE_DEFAULT_VERSION set to 6.9.1
I have tried both Release and Debug configurations, the connection is valid when trying the Validate Connection option inside configuration, the File Publish Options are all unchecked (Remove additional files at destination, precompile during publishing, exclude files from app_data folder) and the publish works fine, and the app is accessible, except for the api controller.
The project is built as a .Net framework version 4.6.1 with Web API.
Thanks in advance for any help!
Edit
I have removed the parameter that was part of the original method that is being hit by the API, and I am now getting the error of No HTTP resource was found that matches the request URI. I have tried changing the Route data annotation as well as just making it HttpGet to see if it was accessible, and it is not working. I created a second action on the controller just to test returning a string, and that worked without problem, so I am not sure why it is not accessible. The intro to the method is as follows:
[HttpGet]
[Route("api/orders/callback")]
public string Callback() { return "Test"; }
I also updated this method to try just returning a simple string and it does not work. I also adjusted the second test method to accept a string POSTed to it and it is returning The requested resource does not support http method 'POST'.
This method looks like the following:
[HttpPost]
[Route("api/orders/new")]
public string SecondCallback(string payload) {
return payload;
}

Categories