Azure Fire-And-Forget HTTP Request - c#

I want to create a very simple azure function to fire a post request and does not wait to the response.I want to make sure that the request is sent but I don't want to wait for the response. I really don't care about the response.
[FunctionName("FireForgetPostRequest")]
public async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Anonymous, "Post", Route = "MyTest")] HttpRequest req,
ILogger log)
{
//Send Post Request to certain end point without validating the response
}

Related

How to write HttpResponseMessage through middleware in aspnetcore 3.1

I have an middleware which executes based on specific routing and redirects the request to call another service and the response of the service call need to be sent back to the caller.
public Task Invoke(HttpContext context)
{
return GetServiceDataAsync(context);
}
private async Task<object> GetServiceDataAsync(HttpContext context)
{
var response = service.GetDataAsync();
return await response;
}
When executing this call, I do see the service call returns response properly. But, the response is not written back as HttpResponseMessage so the caller can read again from the body.
In this case, the response was already read and converted to response. Need some pointers on how to provide the same response back to the caller. With this code, I'm seeing 200 status code, but the body is empty. TIA !

Dequeue Azure Storage queue from Azure Function

I've been looking for examples to easily dequeue an Azure Storage queue the same way you can enqueue an item (by injecting IAsyncCollector in the Run method). but alas, no success.
The only things I've found are enqueueing items or reacting to items being added to a queue.
There is an app running on my local server that will periodically call the function (and keeps calling till the queue is empty) to get the items of the queue. I want to do this using an Azure function.
Any help is welcome.
Please check this doc about ICollector:ICollector with Azure Storage Queue.
ICollector and IAsyncCollector can be used as parameter types for Storage Queue output bindings.
For now azure function binding only supports output binding to write messages to a queue. Or You could use queue trigger to retrieve message if you don't need to call it with HTTP request.
If you have to use HTTP request, suppose you have to create a HTTP trigger function, then retrieve and delete the queue to implement a dequeue action like the below code.
public static async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req,
ILogger log)
{
log.LogInformation("C# HTTP trigger function processed a request.");
// Parse the connection string and return a reference to the storage account.
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(Environment.GetEnvironmentVariable("AzureWebJobsStorage"));
CloudQueueClient queueClient = storageAccount.CreateCloudQueueClient();
// Retrieve a reference to a queue
CloudQueue queue = queueClient.GetQueueReference("myqueue");
// Async dequeue the message
CloudQueueMessage retrievedMessage = await queue.GetMessageAsync();
Console.WriteLine("Retrieved message with content '{0}'", retrievedMessage.AsString);
//Process the message in less than 30 seconds, and then delete the message
await queue.DeleteMessageAsync(retrievedMessage);
return (ActionResult)new OkObjectResult(retrievedMessage.AsString);
}
Why don't you create a webhook function that your app calls then within the function you can dequeue items as necessary using the standard storage queue api for whatever language you use.

HttpClient.PostAsync continueWith not executing

I need some help figuring out why the following code in the continueWith block is not being executed for a long running service call.
public static async void postServiceAsync(string json, string postServiceUrl, string callbackUrl, string clientId,
string tenant, string secret, string d365Environment, TraceWriter log)
{
HttpClient client = new HttpClient();
//Get authorization header
string authHeader = await D365Authorization.getAccessToken(clientId, tenant, secret, d365Environment);
client.DefaultRequestHeaders.Add("Authorization", authHeader);
var httpContent = new StringContent(json);
client.Timeout = TimeSpan.FromMinutes(90);
client.PostAsync(postServiceUrl, httpContent).ContinueWith(async (result) =>
{
//call callback URL
//This is not executed after a long running service that runs for 20 minutes.
}
}
The continueWith code does get run if the service execution time is short though. I thought it was a timeout issue so I added the client.Timeout value. I tried calling the service in Postman and a value is returned even after waiting for 20+ minutes. I am not using await as I want the execution to continue after calling PostAsync. I just want the continueWith callback executed after the long running service execution has completed. Thanks for your help!
The above method called postServiceAsync is called from an Azure function which is being called from an Azure Logic App http webhook action. Here is the Azure function:
public static async Task<HttpResponseMessage> Run([HttpTrigger(AuthorizationLevel.Function, "post", Route = null)]HttpRequestMessage req, TraceWriter log)
{
...
PostServiceAsync.postServiceAsync(json, shipServiceUrl, callbackUrl, clientId, tenant, secret, d365Environment, log);
var resp = req.CreateResponse(HttpStatusCode.Accepted);
return resp;
}
}
From the Azure function, I need to return the Accepted status code right away. After I've finished calling the long running service using PostAsync, I need to post to the callback URL, which is what I am doing in the continueWith block. Like I mentioned, it works if the service runtime is short. I tried Camilo's suggestion of adding await but the continueWith code did not get executed. I also tried getting rid of the continueWith and just added the code after "await client.PostAsync(...)".
It turns out that there is an Azure function 230 second timeout for http calls without a response. I might not be able to use an Azure function for my purposes.

BrokeredMessage being disposed after await

I'm trying to use a service bus Azure function, where I accept a BrokeredMessage, then perform http requests, and then afterward decide whether to complete, abandon, or dead letter the message. But I've been finding the BrokeredMessage is being disposed early if I await an http request. It's throwing System.ObjectDisposedException: 'BrokeredMessage has been disposed.' if I try to use it at all.
Example:
public static async void Run(BrokeredMessage message, TraceWriter log)
{
var httpClient = new HttpClient()
{
BaseAddress = new Uri("http://google.com")
};
httpClient.DefaultRequestHeaders.Accept.Clear();
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var request = new HttpRequestMessage(HttpMethod.Get, "/");
HttpResponseMessage response = await httpClient.SendAsync(request);
message.DeadLetter(); //Throws exception
}
I'm not sure if I'm doing something wrong or missing something but I can't figure out how to make any actions I need to do with the message after the await work correctly.
You shouldn't call Complete() explicitly. Azure Functions runtime will complete the message if the function finishes successfully or abandon if the function fails.
The Functions runtime receives a message in PeekLock mode and calls Complete on the message if the function finishes successfully, or calls Abandon if the function fails.
from docs
The issue was the function needs to return Task instead of void for the async to work correctly. After making that change it awaits correctly.

How to cancel on going transaction(in controller) from UI in Asp.Net MVC?

I am sending Transaction request from UI to controller and processing that request in controller.
This process may consume time around 10 seconds.
While processing transaction the user has a provision to cancel the transaction.
So i need to check whether cancel button has been clicked before every commit.
I Suspect when cancel button clicked I cannot pass that value as new request since new instance of controller will be created.
Another option is using static.But suggestions tell me that don't introduce static fields for controllers.
How to handle this situation? (may be with some token or still some easy work around is there ?)
Not sure what specific UI you are using, but what you can do is terminate the request by clicking the cancel button.
If you are in javascript you can just call abort (content take from here)
var xhr = $.ajax({
type: "POST",
url: "some",
data: "name=John&location=Boston",
success: function(msg){
alert( "Data Saved: " + msg );
}
});
//kill the request
xhr.abort()
Then in the MVC code just bind the cancellation token and check it before calling submit (or better yet use async APIs and pass in the cancellation token).
public ActionResult Action(string param, CancellationToken token)
{
// do your thing
if (token.IsCancellationRequested)
{
// abort
}
// do your thing
}

Categories

Resources