How to debug locally Azure Function triggered by EventGrid? - c#

I create a new Azure Function which I want it to run by EventGrid. I use Visual Studio 2022 Community.
I want to debug the Function by Postman but I couldn't find the way to do it.
My TestFunction.cs:
public static class TestFunction
{
[FunctionName("Function1")]
public static async Task Function1([EventGridTrigger] EventGridEvent triggerEvent,
[EventGrid(TopicEndpointUri = "Topic", TopicKeySetting = "TopicKey")] IAsyncCollector<EventGridEvent> outputEvents,
ILogger log)
{
//TODO
}
}
When I F5 the project to debug, the console app shows:
Functions:
Function1: eventGridTrigger
For detailed output, run func with --verbose flag.
I try to post by Postman to the Url:
http://localhost:7071/runtime/webhooks/EventGrid?functionName=Function1
There are two things that happen:
1.The Postman request returns:
cannot find function: 'Function1'
2.The console application shows:
[2022-03-14T12:20:57.715Z] Executing HTTP request: {
[2022-03-14T12:20:57.717Z] requestId: "a31453db-3717-43d8-a008-bd459a454fb0",
[2022-03-14T12:20:57.718Z] method: "POST",
[2022-03-14T12:20:57.718Z] userAgent: "PostmanRuntime/7.29.0",
[2022-03-14T12:20:57.719Z] uri: "/runtime/webhooks/EventGrid"
[2022-03-14T12:20:57.721Z] }
[2022-03-14T12:20:57.724Z] cannot find function: 'Function1', available function names: []
[2022-03-14T12:20:57.725Z] Executed HTTP request: {
[2022-03-14T12:20:57.726Z] requestId: "a31453db-3717-43d8-a008-bd459a454fb0",
[2022-03-14T12:20:57.727Z] identities: "(WebJobsAuthLevel:Admin, WebJobsAuthLevel:Admin)",
[2022-03-14T12:20:57.728Z] status: "404",
[2022-03-14T12:20:57.729Z] duration: "10"
[2022-03-14T12:20:57.729Z] }
This is the post which I read to get the Url for debugging: https://harrybellamy.com/posts/debugging-azure-function-event-grid-triggers-locally/
Is there anything which I'm missing in order to debug the Function by Postman?
Thank you in advanced!
Update 15.03.2022
When I remove this line (the parameter in Function1) then it works, I can debug the Function1:
[EventGrid(TopicEndpointUri = "MyEventGridTopicUriSetting", TopicKeySetting = "MyEventGridTopicKeySetting")]IAsyncCollector<EventGridEvent> outputEvents,

The referenced article says:
If you try to send the request to the URL now, you will find that it doesn’t work. This is because Event Grid requests require a ‘magic’ header for them to work.
Add the following header to your request in your request generator:
aeg-event-type: Notification

Have a look at the official Microsoft documentation on how to Manually run a non HTTP-triggered function.
To run a non HTTP-triggered function, you need a way to send a request to Azure to run the function. The URL used to make this request takes a specific form.
Host name: The function app's public location that is made up from the function app's name plus azurewebsites.net or your custom domain.
Folder path: To access non HTTP-triggered functions via an HTTP request, you have to send the request through the folders admin/functions.
Function name: The name of the function you want to run.
This works both in Azure and local.
Next to this, see Azure Function Event Grid Trigger Local Debugging which takes an alternative approach of running your Function locally and using ngrok to have Event Grid actually call into your locally running Function.

Related

ADF pipeline - How can I check pipeline run status via c# code (pipeline triggered via a blob trigger)

I'm trying to check the pipeline run status of a specific pipeline via c# code.
The pipeline is triggered via a Blob Events Trigger (Blob Created/File Uploaded via c# code) rather than an API call or DataFactoryManagementClient.Pipelines.CreateRunWithHttpMessagesAsync.
If the pipeline was triggered via code and I had the runId then I'd have simply captured the status from the response using DataFactoryManagementClient.PipelineRuns.GetAsync() method. But i'm trying to get the status from a pipeline triggered via file upload to a Storage container.
I tried to use the answer suggested on this Question but it mentions PipelineRunFilterParameters which I can't find the namespace for.
Thanks in advance
You can use datafactory API
First get runs on the pipeline by calling the pipeline API
Pipeline Runs - Query By Factory
Get your id from this call, you can pass filters to limit number of runs received to get your target one.
Then call the pipeline runs api passing your runId and you get the status of the run.
Pipeline Runs - Get
Sample response
{
"runId": "2f7fdb90-5df1-4b8e-ac2f-064cfa58202b",
"pipelineName": "examplePipeline",
"parameters": {
"OutputBlobNameList": "[\"exampleoutput.csv\"]"
},
"invokedBy": {
"id": "80a01654a9d34ad18b3fcac5d5d76b67",
"name": "Manual"
},
"runStart": "2018-06-16T00:37:44.6257014Z",
"runEnd": "2018-06-16T00:38:12.7314495Z",
"durationInMs": 28105,
"status": "Succeeded",
"message": "",
"lastUpdated": "2018-06-16T00:38:12.7314495Z",
"annotations": []
}
You can see the status is "Succeeded"
It would be one of InProgress, Succeeded, and Failed.

C# API call from MarketStack and print values - Error 403

I would like to make a successful API call, then print the values in order to see if it works. My main goal is to analyze the data, after I can make a successful API call, and build a systematic strategy for trading.
System.Net.Http.HttpRequestException: "Response status code does not indicate success: 403 (Forbidden)
namespace marketstacktest
{
class Program
{
static async Task Main(string[] args)
{
Console.WriteLine("Hello World!");
var options = Options.Create(new MarketstackOptions() { ApiToken = "secretTokenHere" });
var marketstackService = new MarketstackService(options, NullLogger<MarketstackService>.Instance);
var appleSymbol = "AAPL";
var fromDate = DateTime.Now.AddDays(-200);
var toDate = DateTime.Now;
//error at the await System.Net.Http.HttpRequestException: "Response status code does not indicate success: 403 (Forbidden)."
List<Marketstack.Entities.Stocks.StockBar> stock = await marketstackService.GetStockEodBars(appleSymbol, fromDate, toDate);
foreach (var stock_i in stock)
{
Console.WriteLine($"close: {stock_i.Close}");
}
}
}
}
In the API manual, which is directly linked from the github, it gives information about all of the error codes. The relevant ones here are these two:
Code
Type
Description
403
https_access_restricted
HTTPS access is not supported on the current subscription plan.
403
function_access_restricted
The given API endpoint is not supported on the current subscription plan.
Their class library on github is just wrapping a json REST api. Every call to the API is just an http request, returning data as json objects. The 403 error indicates that your request was accepted as a valid request, but intentionally rejected by the server for some reason. And according to the docs, the error was because your account is not allowed access to either https or to the type of request.
Their free-tier subscription only includes end-of-day data, which is what you requested, so it wouldn't make sense for that not to be allowed. So, your app is almost certainly making an https call.
I went to the examples at the very beginning of their quick start guide, and chose the end-of-day example to match your app, and clicked on the link. It worked, and gave a bunch of json records. But, the request they made was using 'http' not 'https'.
Changing the requst to 'https' elicited a 403 response with this content (formatted for readability):
{
"error":
{
"code": "https_access_restricted",
"message": "Access Restricted - Your current Subscription Plan does not support HTTPS Encryption."
}
}
At this point we have enough to be almost certain that this is your issue. The final thing is to go look up how to turn https requests off in their class library. To avoid having to go through the code, I checked the help at the bottom of the page one more time, and found this (formatted for readability):
var options = Options.Create(new MarketstackOptions(){
ApiToken = apiKey,
MaxRequestsPerSecond = 3,
Https = true
});
Welp. This should probably be in their first example, since that's what people are most likely to try first, but it's not. So, to stop trying to make http requests, you just need to set the Https option to false in your code. You just need to add that to the options in your code, like so:
var options = Options.Create(new MarketstackOptions(){
ApiToken = "secretTokenHere",
Https = false
});
I will leave the testing to you, but from the browser test, we know that the request should work, unless there's a bug in their library. Given the information that was available, this is almost certainly the issue.

Setting up an HTTP endpoint for Azure EventGrid Webhook in my MVS Webapp?

I'm trying to create an Azure Eventgrid and Webhook response to send me inbound text messages from Azure communications services to my Azure hosted WebApp. Right now I'm having a really hard time finding documentation that shows how to create an endpoint within a Webapp controller to get the Azure webhook response to handshake and validate. I've created an endpoint within my controller that I believe should be catching the the data and processing it in a POST method, but it fails because of the arguments I'm trying to mimic. Any insight on this topic is appreciated.
I tried integrating a lot of what I found in these Docs into my app controller to try and get it to work, but I think I might be doing this all the wrong way since it says this code is for an Azure function??? I'm not entirely sure how those are used, but I tried integrating the same C# code into my controller. See Docs below:
https://learn.microsoft.com/en-us/azure/event-grid/receive-events
And here is the controller I have that is trying to imitate what I read in the docs I linked
[HttpPost("incoming")]
public async Task<IActionResult> GetFlightInfo([HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest incoming,
ILogger log)
{
log.LogInformation("C# HTTP trigger function processed a request.");
string response = string.Empty;
BinaryData events = await BinaryData.FromStreamAsync(incoming.Body);
log.LogInformation($"Received events: {events}");
EventGridEvent[] egEvents = EventGridEvent.ParseMany(events);
foreach (EventGridEvent eventGridEvent in egEvents)
{
// Handle system events
if (eventGridEvent.TryGetSystemEventData(out object eventData))
{
// Handle the subscription validation event
if (eventData is SubscriptionValidationEventData subscriptionValidationEventData)
{
log.LogInformation($"Got SubscriptionValidation event data, validation code: {subscriptionValidationEventData.ValidationCode}, topic: {eventGridEvent.Topic}");
// Do any additional validation (as required) and then return back the below response
var responseData = new SubscriptionValidationResponse()
{
ValidationResponse = subscriptionValidationEventData.ValidationCode
};
return new OkObjectResult(responseData);
}
}
}
return new OkObjectResult(response);
}
I'd suggest to start by deploying and exploring the Azure Event Grid Viewer sample application according to the Handle SMS events for Delivery Reports and Inbound Messages tutorial.
This app is designed to consume any events generated by the Event Grid, including the SMS ones. The app utilizes SignalR, just as #roman-kiss suggests in his answer, to push the events in near real time to the user.
Once you get a good grasp of the whole flow, you can start adjusting the code to match your use case. A good first step would be adjusting the deserialization logic to take advantage of more specific models. You can get the sample JSON models for SMS events here and convert them to C#.

Autodesk Forge Error trying to access the API online

I have a problem loading a 3D model on an online server, the error shown is related to accessing the Forge API, locally works smoothly however when mounted on the server or a website is made marks the following error "Failed to load resource: the server responded with a status of 404 (Not Found)", then "onDocumentLoadFailure() - errorCode:7".
As I comment, what I find stranger is that, locally, it works. Attached the segment of the code where it displays the error.
function getAccessToken() {
var xmlHttp = null;
xmlHttp = new XMLHttpRequest();
xmlHttp.open("GET", '/api/forge/toke', false); //Address not found
xmlHttp.send(null);
return xmlHttp.responseText;
}
Thank you very much in advance.
Are you sure the code you're running locally and the code you've deployed are really the same?
The getAccessToken function doesn't seem to be correct, for several reasons:
First of all, there seems to be a typo in the URL - shouldn't it be /api/forge/token instead of /api/forge/toke?
More importantly, the HTTP request is asynchronous, meaning that it cannot return the response immediately after calling xmlHttp.send(). You can find more details about the usage of XMLHttpRequest in https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest.
And finally, assuming that the function is passed to Autodesk.Viewing.Initializer options, it should return the token using a callback parameter passed to it (as shown in https://forge.autodesk.com/en/docs/viewer/v7/developers_guide/viewer_basics/initialization/#example).
With that, your getAccessToken should probably look more like this (using the more modern fetch and async/await):
async function getAccessToken(callback) {
const resp = await fetch('/api/forge/token');
const json = await resp.json();
callback(json.access_token, json.expires_in);
}
I've already found the issue. When I make the deploy I have to change the url where the request is made for the public or the name of the domain. For example: mywebsite.com/aplication-name/api/forge/token.

How to set up HTTP outputs in Azure Functions

I've got a simple Azure function for which I set up a DocumentDB output (as an example):
I then added the outputDocument parameter to the function and assigned a value to it in the code (by the way I was surprised that when I set up the output that the runtime didn't automatically modify the function signature):
using System;
public static void Run(string input, out object outputDocument, TraceWriter log)
{
log.Info($"C# manually triggered function called with input: {input}");
outputDocument = new {
text = $"I'm running in a C# function! {input}"
};
}
When I run the function the Azure Functions runtime does it's binding magic and the DocumentDB document gets created.
I then set up an HTTP output:
and defined the res output parameter.
But now what? What's the process of assigning to res? I've of course got to define the destination, request type, parms, etc.
Howiecamp,
The HTTP output binding works in conjunction with the HTTP Trigger to act as the response handler for an HTTP request.
Currently, there isn't an output binding that would send the output payload over HTTP for you, so you'd need to make that HTTP request from your function code (e.g. using the HttpClient and issuing the request). You can see an example in one of our templates here: https://github.com/Azure/azure-webjobs-sdk-templates/blob/10650dbf9c4bad75b0c89b9c355edc53fe913cde/Templates/GitHubCommenter-CSharp/run.csx#L40-L49
I hope this helps!

Categories