Passing email content into an Azure Function App - azure

I want to pass the contents of an email into my Function App in order to remove HTML.
I'm following this tutorial but I'm puzzled at how the incoming email is passed in. I know that it is a http request but not sure which line is dealing with this email that we can then do work on.
We have our req which is our http request so I'm guessing that once we create the trigger in Azure, req is passed straight in?
This the example code that is provided:
#r "Newtonsoft.Json"
using System.Net;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Primitives;
using Newtonsoft.Json;
using System.Text.RegularExpressions;
public static async Task<IActionResult> Run(HttpRequest req, ILogger log) {
log.LogInformation("HttpWebhook triggered");
// Parse query parameter
string emailBodyContent = await new StreamReader(req.Body).ReadToEndAsync();
// Replace HTML with other characters
string updatedBody = Regex.Replace(emailBodyContent, "<.*?>", string.Empty);
updatedBody = updatedBody.Replace("\\r\\n", " ");
updatedBody = updatedBody.Replace(#" ", " ");
// Return cleaned text
return (ActionResult)new OkObjectResult(new { updatedBody });
}

req.Body is the body of your HTTP message when you send a POST request to your Function. So the body of your request should contain your entire email content, then you should be good to go.
Actually your comment // Parse query parameter is wrong. It is not parsing a query parameter but reading the HTTP message body.
btw: I would advise you to do yourself a favor and not write C# Script Functions in the Azure Portal but write and test them locally, e.g. in VS Code, then compile them and deploy them properly to Azure Functions.

Related

Azure functions http trigger Unity3d 2019.3

I've created a test HTTP Trigger azure function. I can trigger it correctly on azure portal and browser. However trigger from Unity editor gives "Error HTTP/1.1 500 Internal Server Error".
starting Azure function:
public static async Task<IActionResult> Run(HttpRequest req, ILogger log){
log.LogInformation("C# HTTP trigger function processed a request.");
string name = req.Query["name"];
string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
dynamic data = JsonConvert.DeserializeObject(requestBody);
name = name ?? data?.name;
return name != null
? (ActionResult)new OkObjectResult($"Hello, {name}")
: new BadRequestObjectResult("Please pass a name on the query string or in the request body");}
My Unity code:
formData.Add(new MultipartFormDataSection("name", "SampleName", "text/plain"));
UnityWebRequest www = UnityWebRequest.Post("https://samplefunction.azurewebsites.net/api/HttpTriggerTest?herelongblob", formData);
yield return www.SendWebRequest();
Azure CORS configuration: Request Credentials ON: Enable Access-Control-Allow-Credentials.
Function is setup always on. Integrate-Trigger: selected methods GET, POST. Authorisation level:Function.
function's host.json: "version": "2.0", "extensionBundle": { "id": "Microsoft.Azure.Functions.ExtensionBundle", "version": "[1.*, 2.0.0)"
App Service authentication:Anonymous
Unity-Azure sdk and google setup search results seems all outdated/not supported :(
What route should I take to get this to work please? happy to try any sdk / unity asset store to reach azure you may suggest! Cheers!
The error occurs in the two lines below in your code:
string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
dynamic data = JsonConvert.DeserializeObject(requestBody);
Since you set text/plain in your code. So when you do the www.SendWebRequest(), it will send a form data but not a json format data. So it will show the error message.
Below I provide the code for your reference:
public static async Task<IActionResult> Run(HttpRequest req, ILogger log)
{
log.LogInformation("C# HTTP trigger function processed a request.");
var arr = req.Form.Keys;
foreach (var key in arr) {
log.LogInformation(key);
log.LogInformation(req.Form[key]);
}
return (ActionResult)new OkObjectResult("success");
}
You can get the key and the value of the form data in the code above and then compose them to json format and then do DeserializeObject. Or if you want to use the data to create a object, you can even do not do DeserializeObject and just set the value into your object directly.
By the way, you can also try to change the text/plain to application/json in your code new MultipartFormDataSection("name", "SampleName", "text/plain"). But, as I don't know much about MultipartFormDataSection, so I'm not sure if this solution can work.
Hope it helps.

Azure Function 1.x to 2.x upgrade - Issue with GetQueryNameValuePairs

I have an HTTP Trigger Azure Function which is currently in 1.x. The code is as below:
using System.Net;
using System.Threading.Tasks;
public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, TraceWriter log)
{
log.Info($"C# HTTP trigger function processed a request. RequestUri={req.RequestUri}");
// parse query parameter
string name = req.GetQueryNameValuePairs()
.FirstOrDefault(q => string.Compare(q.Key, "name", true) == 0)
.Value;
// Get request body
dynamic data = await req.Content.ReadAsAsync<object>();
// Set name to query string or body data
name = name ?? data?.name;
return name == null
? req.CreateResponse(HttpStatusCode.BadRequest, "Please pass a name on the query string or in the request body")
: req.CreateResponse(HttpStatusCode.OK, "Hello " + name);
}
While trying to upgrade it to 2.x, I am getting an issue with GetQueryNameValuePairs
I am getting error - 'HttpRequestMessage' does not contain a definition for 'GetQueryNameValuePairs'
Is there no support for this method in 2.0? How can this be accomplished in .net standard?
Function runtime 1.x is on Full .Net Framework, while 2.x runs on .NET Core env and our function code targets at .NET Standard.
For this class HttpRequestMessage, it doesn't have GetQueryNameValuePairs method in .NET Standard assembly.
Migrating from 1.x to 2.x usually needs work of code modification. Since it's just a template, I suggest you delete it and recreate a Http Trigger in 2.x runtime. You may see a different template work with .NET Standard.
Here is the sample code that looks up query string parameters in Functions V2.x
using System.Net;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Primitives;
public static IActionResult Run(HttpRequest req, TraceWriter log)
{
log.Info("C# HTTP trigger function processed a request.");
if (req.Query.TryGetValue("name", out StringValues value))
{
return new OkObjectResult($"Hello, {value.ToString()}");
}
return new BadRequestObjectResult("Please pass a name on the query string");
}
In Functions v2 this has changed to req.GetQueryParameterDictionary();

Azure functions post issue

Hi Iam new to Azure functions i am using VS 2017 15.4 and running helloworld function app on local. i was able to do get request on this function but when i perform post on same uri it gives.
mscorlib: Exception while executing function: HelloWorld. System.Net.Http.Formatting: No MediaTypeFormatter is available to read an object of type 'Object' from content with media type 'application/octet-stream'.
can you tell me what i forgot bold line is giving problem in post request, i tried with contentType and without ContentType; with body and without body.
How can i parse Json object in request body in azure function. one way i could was to parse it in string then deserialized using jsonconvert. is their any better way of doing it like valueproviders modelbinders etc.
[FunctionName("HelloWorld")]
public static async Task Run([HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)]HttpRequestMessage req, TraceWriter log)
{
log.Info("C# HTTP trigger function processed a request.");
// parse query parameter
string name = req.GetQueryNameValuePairs()
.FirstOrDefault(q => string.Compare(q.Key, "name", true) == 0)
.Value;
// Get request body
*dynamic data = await req.Content.ReadAsAsync<object>();*
// Set name to query string or body data
name = name ?? data?.name;
return name == null
? req.CreateResponse(HttpStatusCode.BadRequest, "Please pass a name on the query string or in the request body")
: req.CreateResponse(HttpStatusCode.OK, "Hello " + name);
}.
This should work assuming the Content-Type header on your HTTP request is set to application/json.
Note that if the header's value is multipart/form-data, then this is a known bug documented here.
As Connor said as long as the Content-Type header is set to application/json in your request this code will work fine. An issue I have run into though is that the add header functionality when testing azure functions in azure portal doesn't seem to work in this case.
If you can send a request to your function from outside of the test section of azure functions this should work fine.

How to wire up an HttpTrigger to the Designer

I'm new to Azure Functions.
I'm trying to write an Http Trigger that will not only "fail" bad json (that doesn't match my schema, I want to provide feedback to the caller with the invalid messages about the json they submitted.
Ok, so first I brought up VS2017.
Then I coded it up. I can use PostMan to test it, it works fine during PostMan testing.
using System;
using System.Linq;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
////using MyExceptionLibrary;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.Azure.WebJobs.Host;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Schema;
namespace MyNamespace.AzureFunctionsOne
{
public static class MyFirstHttpTrigger
{
[FunctionName("MyFirstHttpTriggerFunctionName")]
public static async Task<HttpResponseMessage> Run([HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)]HttpRequestMessage req, TraceWriter log)
{
log.Info("C# HTTP trigger function MyFirstHttpTriggerFunctionName about to process a request.");
try
{
string jsonSchemaText = #"{
'description': 'A person',
'type': 'object',
'properties':
{
'name': {'type':'string'},
'hobbies': {
'type': 'array',
'items': {'type':'string'}
}
}
}";
JSchema schema = JSchema.Parse(jsonSchemaText);
var content = req.Content;
string jsonContent = content.ReadAsStringAsync().Result;
JObject jobj = JObject.Parse(jsonContent);
IList<string> messages;
bool valid = jobj.IsValid(schema, out messages);
if (!valid)
{
string errorMsg = string.Join(",", messages);
throw new ArgumentOutOfRangeException(string.Format("Bad Json. ({0})", errorMsg));
}
}
catch (Exception ex)
{
string errorMsg = ex.Message; //// ExceptionHelper.GenerateFullFlatMessage(ex);
log.Error(errorMsg);
return req.CreateResponse(HttpStatusCode.BadRequest, errorMsg);
}
log.Info("C# HTTP trigger function MyFirstHttpTriggerFunctionName processed a request.");
return req.CreateResponse(HttpStatusCode.OK);
}
}
}
I then "published" this azure function to the cloud.
My issue is now........how do I wire this into the Logic App Designer to be the trigger?
In the below, I'm able to add the generic-request-trigger.
In the below, I've also looked for ~my~ azure http trigger that I published, and no luck.
So I can't figure out how to get my custom Http-Trigger to be available in the Logic App designer so it can be the entry-point-trigger.
Am I missing some basic concept?
My end game is:
I want a third-party to POST some json to my azure-logic-app as an http-request. That should be the trigger. But I only want the trigger to keep running if they submit valid json. (This I know can be done via the generic request trigger). My caveat (and thus my custom http-trigger) is that I want the third-party to get schema violation messages so they know what they did wrong.
If I understand this correctly, you have a workflow you want 3rd party to invoke via HTTP request, and when the request body isn't well formatted, you want to return a friendly error.
So you coded up an Azure Function that expose itself as a request endpoint, and does the validation.
If that's the case, you will just need to have the Azure Function to invoke Logic App after success validation, and pass the original payload to Logic App. So you can create the Logic App with a request trigger, save and get the Url, and have Function call that Url.

Error sending request from Azure Function

I have an Azure Function that I have configured that listens for incoming messages to an Azure Service Bus. I can receive the messages without a problem. But when I try to route the request onto another service for processing, I am getting an error stating that the POST data is empty.
public static void Run(BrokeredMessage message, TraceWriter log)
{
log.Info($"C# ServiceBus queue trigger function processed message: {message.MessageId}");
if (message != null)
{
//MessageObjectEntity is a custom object
Common.Entities.MessageObjectEntity messageObject = message?.GetBody<Common.Entities.MessageObjectEntity>();
string msgType = messageObject?.MessageType;
var msgContent = messageObject?.MessageContent; // MessageContent is of type object to allow any object to be sent
using (var client = new HttpClient())
{
string url = $"http://mycompany.azurewebsites.net/api/routingtasks?formname={msgType}";
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(subscriber, token);
HttpContent content = new StringContent((string)msgContent, Encoding.UTF8, "application/json");
var response = client.PostAsync(new Uri(url), content); // at this point content is valid
// I am getting a BadRequest returned here as the target service has not received the POST data
// that was sent in via the content variable
}
log.Info("Completing message.");
}
It appears that the POST data sent in the variable content is not received despite it being sent.
UPDATE
When I inspect the JSON sent to my Azure Function in the logger it looks like this.
{"FormName":"UpdateMileage","FormData":[{"Key":"enteredmileage","Value":100},{"Key":"todaysdate","Value":"01/01/2017"}],"Profile":{"EmailAddress":"unittest#mycompany.co.uk","ID":9999999}}
Which doesn't work.
But if I hard code the following JSON from my Azure Function it works correctly (the double quotes are needed to escape the back-slashes).
"\"{\\\"FormName\\\":\\\"UpdateMileage\\\","\\\"FormData\\\":"[{\\\"Key\\\":\\\"enteredmileage\\\",\\\"Value\\\":100},"{\\\"Key\\\":\\\"todaysdate\\\",\\\"Value\\\":\\\"01/01/2017\\\"}],"\\\"Profile\\\":"{\\\"EmailAddress\\\":\\\"unittest#mycompany.co.uk\\\","\\\"ID\\\":9999999}}\""
The problem therefore appears to be the formatting of the JSON that is being sent from my Azure Function, but I don't how I would convert my JSON into this format.
The problem was caused by the fact that I was sending JSON to my ASP.NET Web API service, but sending it as a string type. This is wrong.
The following article explains the correct approach when sending JSON data as a POST request.

Resources