HTTP Listener in a HTTP Trigger Azure Function - azure

I have a HTTP Listener console app that works on my local machine. When I try to use it inside a HTTP Trigger Azure Function. I always get the 418 error code.
In my console app:
HttpListener listener = new HttpListener();
try
{
listener.Prefixes.Add("http://localhost:11000/");
listener.Start();
} catch (Exception e)
{ // }
do {
var ctx = listener.GetContext();
var res = ctx.Response;
var req = ctx.Request;
var reqUrl = req.Url;
var readStream = new StreamReader(req.InputStream);
var content = readStream.ReadToEnd();
Console.WriteLine(content);
// business logic
readStream.Close();
res.StatusCode = (int)HttpStatusCode.OK;
res.ContentType = "text/plain";
res.OutputStream.Write(new byte[] { }, 0, 0);
res.Close();
if (stopListener) { listener.Stop(); }
} while (listener.IsListening);
Now HTTP Trigger Function uses the HttpRequest class and that seems to give me the 418 error code. I replaced it with HttpListener() but when I add the prefix of the Azure Function string connection (on the CLI), the stream never goes through and its as if its not capturing it? Or what connection should I use? I feel like self-referencing it is the reason its not working.
Azure Function:
public static async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpListener listener,
ILogger log,
IBinder binder)
{//same as above}
Is this the right approach to getting data from an external app? So far this has been the way I can see it working via the HTTP Listener.
Any suggestions are welcomed.

Is this the right approach to getting data from an external app?
The right way to access Data from an external source and any other source. You can create an API and use this API to access data from external sources.
For create azure function click hereby Microsoft documents.
Below sample code for access web API in azure function.
var _httpclient = new HttpClient();
var _response = await _httpclient .GetAsync(rul);
var result_= await _response .Content.ReadAsStringAsync();
its use is just like using API in C# code.
Azure Function Code:-
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using System.Net.Http;
namespace _73093902_FunctionApp10
{
public static class Function1
{
[FunctionName("Function1")]
public static async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req,
ILogger log)
{
var _httpclient = new HttpClient();
var _response = await _httpclient.GetAsync("https://localhost:7101/WeatherForecast");
var result_ = await _response.Content.ReadAsStringAsync();
return new OkObjectResult(result_);
}
}
}
Debug Output:-

Related

Access FunctionAppDirectory in .NET 5 Azure Function

I need to have access to FunctionAppDirectory in Azure Function
Here is a simplified version of the function
[Function("Test")]
public static HttpResponseData Test([HttpTrigger(AuthorizationLevel.Function, "post", Route = "Test")] HttpRequestData req,
ExecutionContext context, FunctionContext fContext)
{
var log = fContext.GetLogger(nameof(TestOperations));
log.LogInformation(context?.FunctionAppDirectory?.ToString());
return req.CreateResponse(HttpStatusCode.OK);
}
ExecutionContext here is null.
My Program.cs file
class Program
{
static Task Main(string[] args)
{
var host = new HostBuilder()
.ConfigureAppConfiguration(configurationBuilder =>
{
configurationBuilder.AddCommandLine(args);
})
.ConfigureFunctionsWorkerDefaults()
.ConfigureServices(services =>
{
// Add Logging
services.AddLogging();
})
.Build();
return host.RunAsync();
}
}
Azure Function running in .NET 5
How I can configure binding for ExecutionContext or get FunctionAppDirectory in other ways?
As Alex mentioned in the comment, azure function .net 5 is not support 'context.FunctionAppDirectory' to get the directory of function app now.
In function app 3.0, the 'ExecutionContext' is be designed in the package 'Microsoft.Azure.WebJobs'. But in your code, the ExecutionContext is from 'System.Threading'. So these are different classes.
You can use below code to get the azure function directory in .NET 5.0 azure function:
using System;
using System.Collections.Generic;
using System.Net;
using Microsoft.Azure.Functions.Worker;
using Microsoft.Azure.Functions.Worker.Http;
using Microsoft.Extensions.Logging;
namespace FunctionApp6
{
public static class Function1
{
[Function("Function1")]
public static HttpResponseData Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", "post")] HttpRequestData req,
FunctionContext executionContext)
{
var logger = executionContext.GetLogger("Function1");
logger.LogInformation("C# HTTP trigger function processed a request.");
var response = req.CreateResponse(HttpStatusCode.OK);
response.Headers.Add("Content-Type", "text/plain; charset=utf-8");
var local_root = Environment.GetEnvironmentVariable("AzureWebJobsScriptRoot");
var azure_root = $"{Environment.GetEnvironmentVariable("HOME")}/site/wwwroot";
var actual_root = local_root ?? azure_root;
response.WriteString(actual_root);
return response;
}
}
}

SignalR (serverless) .NET console client not receiving messages

I'm trying to learn SignalR by creating a sample .NET console application that receive messages through a serverless SignalR, via a hosted Azure function app; I've been following this tutorial https://www.nikouusitalo.com/blog/qr-code-pings-with-azure-functions-and-azure-signalr/ but even though I get the connection stablished, I never get any message when running a POST request against a given Azure function in Postman. This is what I have:
Azure Functions
public static class Function1
{
[FunctionName("Function1")]
public static async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req,
[SignalR(HubName = "QRCodeRehash")] IAsyncCollector<SignalRMessage> signalRMessages,
ILogger log)
{
log.LogInformation("C# HTTP trigger function processed a request.");
await signalRMessages.AddAsync(
new SignalRMessage
{
Target = "pingQR",
Arguments = new[] { "ping" }
});
var responseMessage = "Success";
return new OkObjectResult(responseMessage);
}
[FunctionName("negotiate")]
public static SignalRConnectionInfo GetOrderNotificationsSignalRInfo(
[HttpTrigger(AuthorizationLevel.Anonymous, "post")] HttpRequest req,
[SignalRConnectionInfo(HubName = "QRCodeRehash")] SignalRConnectionInfo connectionInfo)
{
return connectionInfo;
}
}
.NET Console application to receive message
public class SignalRConnection
{
public async void Start()
{
var url = "https://sample.azurewebsites.net/api";
var connection = new HubConnectionBuilder()
.WithUrl(url)
.WithAutomaticReconnect()
.Build();
// receive a message from the hub
connection.On<string, string>("pingQR", (user, message) => OnReceiveMessage(user, message));
await connection.StartAsync();
}
private void OnReceiveMessage(string user, string message)
{
Console.WriteLine($"{user}: {message}");
}
}
And following the tutorial's steps, I just call Function1 in Postman:
I always get "200 OK" and the logs can be seen in the Azure function as well; also, the negotiate works ok as it seems to connect every time to SignalR:
I've set CORS in the Azure function app to allow anything while I get this to work:
I would appreciate your help on this; it's odd how it works for the tutorial's owner, however, maybe something was left out that I need to do on my end, so any thoughts would be highly appreciated.
Thanks a lot!
Update: Thanks #Brennan's comment, my mistake was in to providing a different number of arguments than the ones detailed in the connection in the client. It's working as expected now.

Azure Function Cosmos DB Output Binding - Custom JsonSerializerSettings

I have an Azure Function with a CosmosDB output binding, like this:
public static class ComponentDesignHttpTrigger
{
[FunctionName("ComponentDesignInserter-Http-From-ComponentDesign")]
public static IActionResult Run(
[HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = "fromComponentDesign")] HttpRequest request,
[CosmosDB(
databaseName: StorageFramework.CosmosDb.DatabaseId,
collectionName: Storage.ComponentDesignCollectionId,
ConnectionStringSetting = "CosmosDBConnection")] out ComponentDesign componentDesignToInsert,
ILogger log)
{
var requestBody = new StreamReader(request.Body).ReadToEnd();
componentDesignToInsert = JsonConvert.DeserializeObject<ComponentDesign>(requestBody);
return new OkObjectResult(componentDesignToInsert);
}
}
In this function componentDesignToInsert is automatically serialized and put into CosmosDB after the function finishes executing. But the default serialization does not put things in camelCase. For this Json.NET lets you provide custom serializer settings, like this:
var settings = new JsonSerializerSettings
{
ContractResolver = new CamelCasePropertyNamesContractResolver()
};
var json = JsonConvert.SerializeObject(yourObject, settings);
but I'm unsure how I can integrate this with my output binding. How can I accomplish this?
Output binding does not expose the serializer settings at this moment.
One thing you can do though, is leverage your own custom DocumentClient for the operation.
One important thing though is that the DocumentClient instance needs to be static (more details on https://github.com/Azure/azure-functions-host/wiki/Managing-Connections).
private static Lazy<DocumentClient> lazyClient = new Lazy<DocumentClient>(InitializeDocumentClient);
private static DocumentClient documentClient => lazyClient.Value;
private static DocumentClient InitializeDocumentClient()
{
// Perform any initialization here
var uri = new Uri("example");
var authKey = "authKey";
var settings = new JsonSerializerSettings
{
ContractResolver = new CamelCasePropertyNamesContractResolver()
};
return new DocumentClient(uri, authKey, settings);
}
[FunctionName("ComponentDesignInserter-Http-From-ComponentDesign")]
public static async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = "fromComponentDesign")] HttpRequest request,
ILogger log)
{
var requestBody = new StreamReader(request.Body).ReadToEnd();
var componentDesignToInsert = JsonConvert.DeserializeObject<ComponentDesign>(requestBody);
var collectionUri = UriFactory.GetDocumentCollectionUri(StorageFramework.CosmosDb.DatabaseId, Storage.ComponentDesignCollectionId);
await documentClient.UpsertDocumentAsync(collectionUri, componentDesignToInsert);
return new OkObjectResult(componentDesignToInsert);
}
Another option is to decorate the class with JsonProperty if that suits your scenario.

Getting next message in an Azure Service Bus Subscription with an Azure Function, with an HTTP Trigger

I want to create an Azure Function that will fulfill the following requirements:
Trigger upon an HTTP request
Looks at an Azure Service Bus Subscription and gets the next message based on a set of filters specified in the HTTP Request.
If you are using C# you can do something like this:
using System;
using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Microsoft.Azure.ServiceBus;
using Microsoft.Azure.ServiceBus.Core;
namespace HttpTriggerSBRead
{
public static class ReadSBOnHttpTrigger
{
const string ServiceBusConnectionString = "{service bus connection string}";
const string TopicName = "{name of your topic}";
const string SubscriptionName = "{name of your subscription}";
[FunctionName("ReadSBOnHttpTrigger")]
public static async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req,
ILogger log)
{
string filter = req.Query["filter"];
string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
dynamic data = JsonConvert.DeserializeObject(requestBody);
filter = filter ?? data?.filter;
SubscriptionClient sqlFilterOnlySubscriptionClient = new SubscriptionClient(ServiceBusConnectionString,
TopicName, SubscriptionName);
await sqlFilterOnlySubscriptionClient.AddRuleAsync(new RuleDescription
{
Filter = new SqlFilter(filter),
Name = filter
});
await ReceiveMessagesAsync(SubscriptionName, log);
await sqlFilterOnlySubscriptionClient.RemoveRuleAsync(filter);
return filter != null
? (ActionResult)new OkObjectResult($"{filter}")
: new BadRequestObjectResult("Please pass a filter on the query string or in the request body");
}
static async Task ReceiveMessagesAsync(string subscriptionName, ILogger log)
{
string subscriptionPath = EntityNameHelper.FormatSubscriptionPath(TopicName, subscriptionName);
IMessageReceiver subscriptionReceiver = new MessageReceiver(ServiceBusConnectionString, subscriptionPath, ReceiveMode.ReceiveAndDelete);
log.LogInformation($"{DateTime.Now} :: Receiving Messages From Subscription: {subscriptionName}");
var receivedMessage = await subscriptionReceiver.ReceiveAsync(TimeSpan.FromSeconds(30));
if (receivedMessage != null)
{
log.LogInformation($"Lable Property = {receivedMessage.Label}");
}
log.LogInformation($"{DateTime.Now} :: Messages From Subscription: {subscriptionName}");
}
}
}
To use it you need to pass in the filter parameter to your function. For example something like this:
http://localhost:7071/api/ReadSBOnHttpTrigger?filter=sys.Label=%27test%27 or http://localhost:7071/api/ReadSBOnHttpTrigger?filter=sys.To=%27test%27
Just for the reference, I used this code as source with some small modifications:
https://github.com/Azure/azure-service-bus/tree/master/samples/DotNet/GettingStarted/Microsoft.Azure.ServiceBus/TopicSubscriptionWithRuleOperationsSample

Reading response content from HTTPResponseMessage

I'm writing queue trigger function where I read data from queue, and send them another web service using RESTFul service. Right now, I'm testing a very simple REST api call that I only need to provide token in the header and expect very simple JSON response from the server. The JSON just contains an email address entry and that's about it. My understanding is that if I read response asynchronously, I would need to change function prototype to comply with async call. But that's not possible in Azure function app. So what's the best way to read JSON response object?
This is my attempt so far :
using System;
using System.Net.Http;
using System.Net.Http.Headers;
public static void Run(string myQueueItem, TraceWriter log)
{
string URL = "https://api.spotlightessentials.com/api/v2/user";
HttpClient client = new HttpClient();
client.BaseAddress = new Uri(URL);
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Add("token","<Token value>");
HttpResponseMessage response = client.GetAsync("").Result;
if (response.IsSuccessStatusCode)
{
// How do I read Json response here
}
}
else
{
Console.WriteLine("{0} ({1})", (int)response.StatusCode, response.ReasonPhrase);
}
}
In your
if (response.IsSuccessStatusCode)
you can do this:
var responseData = await response.Content.ReadAsAsync<YourObjectTypeHere>();
Or you could also do something like this depending on your needs:
var responseData = response.Content.ReadAsStringAsync().GetAwaiter().GetResult();
if (!string.IsNullOrWhiteSpace(responseData))
{
var responseDataObject =
JsonConvert.DeserializeObject<YourObjectTypeHere>(responseData);
}
Or a combination of parts of the 2.

Resources