Azure function does not accept XML, v4 net6.0 - c#

I am trying to create an azure function that will receive XML files and process them accordingly. I managed to achieve this on my local environment and everything works as intended but when I deployed it to Azure and testing, it comes back with the following 500 internal server error:
Data at the root level is invalid. Line 1, position 1.
Is the exact same xml that works on the local environment, I checked it on the online validators and on visual studio, there is no problem with the xml. Hoovering over the text brings:
Only content-type of application/json is accepted.
I have tried different approaches in code to go around reading the string but with no success:
public class Function1
{
[FunctionName("Function1")]
public static async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req,
ILogger log)
{
try
{
log.LogInformation("C# HTTP trigger function processed a request.");
//string msg = await new StreamReader(req.Body).ReadToEndAsync();
XmlDocument xmlDocumnet = new XmlDocument();
xmlDocumnet.LoadXml(await new StreamReader(req.Body).ReadToEndAsync());
and
string msg = await new StreamReader(req.Body).ReadToEndAsync();
using (var stream = new MemoryStream())
{
var writer = new StreamWriter(stream);
writer.Write(msg);
writer.Flush();
stream.Position = 0;
xmlDocumnet.Load(stream);
}
I tried to add a header to specify content-type : text/xml but it comes back with a 500:
Only content-type of application/json is accepted.
What would be the best approach in this case? I was thinking to create an intermediary storage which I then would load the file in the function without passing it into the body but that would increase the processing time.

Related

Sending list of images to azure function to upload image to blob in .Net

I am trying to upload images to blob from my android app. My current approach is uploading images using azureblobsdk which allows me to upload images directly to the blob but now what I am trying is creating an azure function that would accept data in stream or byte array and will store it to my blob.
while uploading the image from my app I used to send some metadata in the string to my app.
var blobClient = containerClient.GetBlobClient(fileName);
Dictionary<string, string> metadataProperties = new Dictionary<string, string>();
metadataProperties.Add(key, value);
await blobClient.SetMetadataAsync(metadataProperties);
here is what I am doing right now from the app
now I am trying this same thing to do from azure by sending those parameters to the azure function but the problem is I am unable to understand how would I send those streams and metadata to the azure function so that I can process them in my azure function
here is till now what I have done since I am new to azure function so need help to move forward with some approach
[FunctionName("UploadProductImages")]
public async Task<HttpResponseMessage> UploadProductImages([HttpTrigger(AuthorizationLevel.Function, "post", Route = "product/uploadimages")] HttpRequestMessage req, Microsoft.Extensions.Logging.ILogger log)
{
}
now with this function in place how do I access the data sent from my app which would be a list of images with metadata I am even confused about what should I send a stream or byte array
my final target is to get the list of images with some metadata of those images and upload to blob azure blob storage
If I understand the problem correctly, you can do something like this
Create a Model for you data and send it like this
HttpClient apiClient = new HttpClient();
using (var message = new HttpRequestMessage(HttpMethod.Post, functionAppLink))
{
message.Content = new StringContent(JsonConvert.SerializeObject(model),Encoding.UTF8, "application/json");
var response = await apiClient.SendAsync(message);
}
On Function app side just retrieve and deserialize
[FunctionName("UploadProductImages")]
public async Task<HttpResponseMessage> UploadProductImages([HttpTrigger(AuthorizationLevel.Function, "post", Route = "product/uploadimages")] HttpRequestMessage req, Microsoft.Extensions.Logging.ILogger log)
{
using var sr = new StreamReader(req.Body);
var input = await sr.ReadToEndAsync();
var model = JsonConvert.Deserialize<Model>(input);
// Do your thing
}

Error: Cannot convert from Microsoft.AspNetCore.Http.IFormFile to System.IO.Stream

I'm trying to create Azure function which takes image file from html form POST request and saves it to Blob Storage for further usage with another function. Here is my code:
public static class Function2
{
[FunctionName("Function2")]
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.");
foreach (var file in req.Form.Files)
{
using (var ms = new MemoryStream())
{
var file2 = req.Form.Files[0];
await file2.CopyToAsync(ms);
ms.Seek(0, SeekOrigin.Begin);
var connectionString = "DefaultEndpointsProtocol=https;" +
"AccountName=mystorageaccount;" +
"AccountKey=8Hk5k6j65j5j665j67k==;" +
"EndpointSuffix=core.windows.net";
// intialize BobClient
Azure.Storage.Blobs.BlobClient blobClient = new Azure.Storage.Blobs.BlobClient(
connectionString: connectionString,
blobContainerName: "image-storage",
blobName: "images");
// upload the file
blobClient.Upload(file2);
}
}
return new OkResult("Image uploaded successfully");
}
}
However this raises exception:
Error CS1503 Argument 1: cannot convert from
'Microsoft.AspNetCore.Http.IFormFile' to 'System.IO.Stream'
Any advise would be very highly appreciated.
Edit: I have previously created Blob Container "image-storage" to my storage account using Azure Portal.
BlobCients Upload method expects a Stream instead of an IFormFile.
Passing the MemoryStream you have in the ms variable will resolve the issue.
blobClient.Upload(ms);

How to do a durable post call in an ServiceBusTrigger azure function?

Hey I'm using a ServiceBusTrigger azure function to get the messages received in a queue, and then send them to my webapi which is going to do some stuff with that content
[FunctionName("MyAzureFunction")]
public async void Run(
[ServiceBusTrigger("<MyQueue>", Connection = "<MyConnectionString>")] Message myQueueItem, ILogger log)
{
log.LogInformation($"C# ServiceBus queue trigger function processed message: {myQueueItem.ToString()}");
var client = new HttpClient();
// Retrieving the string content from the message
var bodyMessage = Encoding.UTF8.GetString(myQueueItem.Body);
// Calling my API to do something based on the message content
var response = await client.PostAsync("<MyAPIUrl>", new StringContent(bodyMessage, Encoding.UTF8, "application/json"));
// doing something based on the response
}
I've been reading about azure functions and in order to it gets cheaper I read about durable functions, I'm looking forward how to use them so I can take decisions based on my response and I can get it working with this ServiceBusTrigger
Needs to be changed the current ServiceBusTrigger function so it calls another Function that will actually do the job:
[FunctionName("MyAzureFunction")] public async void Run(
[ServiceBusTrigger("<MyQueue>", Connection = "<MyConnectionString>")] Message myQueueItem,
[DurableClient] IDurableOrchestrationClient orchestratorClient,
ILogger log) {
log.LogInformation($"C# ServiceBus queue trigger function processed message: {myQueueItem.ToString()}");
// Here is where you need to specify in the first parameter the name of the function to be called
// and the last parameter are the params you'll send to that one
var instanceId = await orchestratorClient.StartNewAsync("MyPostFunction", null, myQueueItem);
log.LogInformation($"C# ServiceBus queue trigger function created an async instance of 'MyPostFunction' with the ID: {instanceId}");
}
Then is needed to create another function that will be OrchestrationTrigger type, that will look like this:
[FunctionName("MyPostFunction")] public async void RunOrchestrator([OrchestrationTrigger] IDurableOrchestrationContext context) {
// using the context can be retrieved the parammeters passed in the function above
// in this case I just specify the type of that one and that's it
var myQueueItem = context.GetInput<Message>();
var bodyMessage = Encoding.UTF8.GetString(myQueueItem.Body);
// Create a URI of your API url
var postUri = new Uri($"<MyAPIUrl>");
// depending on your WebAPI you'll need to specify the content type in the headers
var headers = new Dictionary<string, StringValues>() { { "Content-Type", "application/json" } };
// creating durable http request
var request = new DurableHttpRequest(HttpMethod.Post, postUri, headers, bodyMessage);
// Doing the http call async, in this context you'll save money since your function will not be completely waiting for a response
// this one will keep just checking to see if there's a response available or not
var response = await context.CallHttpAsync(request);
// do your stuffs depending in the response
}
In my case I had to specicify the headers in the request, otherwise I used to get 415 Unsupported Media Type can be done in that way, or just creating the request without specifying any header at the begining and then adding those like this:
var request = new DurableHttpRequest(HttpMethod.Post, postUri, null, bodyMessage);
request.Headers.Add("Content-Type", "application/json");
Both options work

How to receive large response from azure http trigger [duplicate]

This question already has an answer here:
Azure Function - HTTP trigger request length exceeded
(1 answer)
Closed 3 years ago.
My application will call a http trigger to read a blob file.
I was able to receive the response from my http trigger when the file size is small (around 30MB). When the file size is around 160MB then my application is receiving empty response.
Facing this issue is only when the Http trigger is deployed in azure environment. When run the http trigger from my local machine and call local http trigger in my app its working fine.
Calling App
string WebAddress = "https://MyfunctionApp.azurewebsites.net/api/Report";
//string WebAddress = "http://localhost:7071/api/FIComparisonReport";
string WebServiceUri = string.Format("{0}?groupcode={1}&domicile={2}&legalstructure={3}",
WebAddress,
Uri.EscapeDataString(groupCode),
Uri.EscapeDataString(domicile),
Uri.EscapeDataString(legalStructure));
WebRequest request = WebRequest.Create(WebServiceUri);
request.Method = "GET";
request.Timeout = 360000;
WebResponse response = request.GetResponse();
var encoding = Encoding.UTF8;
string responseText = "";
using (var reader = new System.IO.StreamReader(response.GetResponseStream(), encoding))
{
responseText = reader.ReadToEnd(); // empty for large files
}
Http trigger
public static async Task<HttpResponseMessage> Run(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequestMessage req,
ILogger log)
{
//read blob to stream
MemoryStream resultSets = myfunc();
var response = new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new ByteArrayContent(resultSets.GetBuffer())
};
response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
return response;
What am I missing here ?
The response size is limited to 100 MB max.
the runtime limit, which was just bumped up to 100MB.
https://github.com/Azure/azure-functions-host/issues/1063#issuecomment-288818131
This talks about HTTP requests but I believe the same limit is true for responses.

Azure Function Access CloudBlobContainer from HttpTriggerFunction

Very, very new to Azure Functions and getting very frustrated.
All I want to do is execute on a 'get' request from a HttpTriggerFunction and return stream content from the CloudBlobContainer.
I really don't see why this is so hard. Just trying to host a SPA using Azure Functions.
Something like this
public static class UIHandler
{
[FunctionName("UIHandler")]
public static async Task<HttpResponseMessage> Run(
[HttpTrigger(AuthorizationLevel.Function, "get", Route = null)]HttpRequest req,
TraceWriter log,
CloudBlobContainer container)
{
log.Info("C# HTTP trigger function processed a request.");
var stream = await container.GetBlockBlobReference({Infer file name from request here}).OpenReadAsync();
return new HttpResponseMessage()
{
StatusCode = HttpStatusCode.OK,
Content = new StreamContent(stream)
};
}
}
When I try to run this I get the following error.
Run: Microsoft.Azure.WebJobs.Host: Error indexing method
'UIHandler.Run'. Microsoft.Azure.WebJobs.Host: Cannot bind parameter
'container' to type CloudBlobContainer. Make sure the parameter Type
is supported by the binding. If you're using binding extensions (e.g.
ServiceBus, Timers, etc.) make sure you've called the registration
method for the extension(s) in your startup code (e.g.
config.UseServiceBus(), config.UseTimers(), etc.).
I'm using Azure Functions 2. I can't see from the web how to setup the browsing extensions for this. Iv'e also looked into Input and Output bindings. I don't understand what makes a parameter input or output bound when your using C# that only seems to exist in the JSON.
Do I need to corresponding JSON file ? If so what is it called where does it go.
Thanks in Advance
Have a look at Blob Storage Input Binding. The very first sample there shows how to read blob stream, just replace Queue Trigger with HTTP trigger, e.g.
[FunctionName("UIHandler")]
public static async Task<HttpResponseMessage> Run(
[HttpTrigger(AuthorizationLevel.Function, "get", Route = "{name}")] HttpRequest req,
string name,
TraceWriter log,
[Blob("samples-workitems/{name}", FileAccess.Read)] Stream stream)
{
log.Info($"C# HTTP trigger function processed a request for {name}.");
return new HttpResponseMessage()
{
StatusCode = HttpStatusCode.OK,
Content = new StreamContent(stream)
};
}

Categories

Resources