How to parse form data using Azure Functions

对着背影说爱祢 提交于 2021-01-27 05:38:33

问题


I am trying to get form data within an Azure function.

public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, TraceWriter log)
{
    log.Info("C# HTTP trigger function processed a request.");
    NameValueCollection col = req.Content.ReadAsFormDataAsync().Result;   
    return req.CreateResponse(HttpStatusCode.OK, "OK");
}

I am getting the following error:

Exception while executing function: System.Net.Http.Formatting: No MediaTypeFormatter is available to read an object of type 'FormDataCollection' from content with media type 'multipart/form-data'.

I am trying to parse inbound emails via SendGrid as described here. https://sendgrid.com/docs/Classroom/Basics/Inbound_Parse_Webhook/setting_up_the_inbound_parse_webhook.html

The incoming request looks correct.

--xYzZY Content-Disposition: form-data; name="attachments"

0 --xYzZY Content-Disposition: form-data; name="text"

Hello world --xYzZY Content-Disposition: form-data; name="subject"

Subject --xYzZY Content-Disposition: form-data; name="to"


回答1:


Based on the error message, you are using multipart/form-data as your request content type. But you haven't post any media type data to server.

If you just want to send some plain data to server, you could change the content type to application/x-www-form-urlencoded and modify your request body as following format.

name=attachments&anothername=anothervalue

If you want to get the form data from multi part post, you could using MultipartFormDataStreamProvider.

string filePath = "set a temp path to store the uploaded file";
var provider = new MultipartFormDataStreamProvider(filePath);
var multipartProvider = await req.Content.ReadAsMultipartAsync(provider);
var formData = multipartProvider.FormData;

Manually parse the content of request body.

string content = await req.Content.ReadAsStringAsync();
string formdata = content.Split(';')[1];
string[] namevalues = formdata.Split('&');
NameValueCollection col = new NameValueCollection();
foreach (string item in namevalues)
{
    string[] nameValueItem = item.Split('=');
    col.Add(nameValueItem[0], nameValueItem[1]);
}



回答2:


Since there doesn't appear to be a good way to convert an IFormCollection to a custom model / viewmodel type, I wrote an extension method for this.

It's a shame that Azure Functions v2/v3 doesn't support this out of the box yet.

public static class FormCollectionExtensions
{
    /// <summary>
    /// Attempts to bind a form collection to a model of type <typeparamref name="T" />.
    /// </summary>
    /// <typeparam name="T">The model type. Must have a public parameterless constructor.</typeparam>
    /// <param name="form">The form data to bind.</param>
    /// <returns>A new instance of type <typeparamref name="T" /> containing the form data.</returns>
    public static T BindToModel<T>(this IFormCollection form) where T : new()
    {
        var props = typeof(T).GetProperties();
        var instance = Activator.CreateInstance<T>();
        var formKeyMap = form.Keys.ToDictionary(k => k.ToUpper(), k => k);

        foreach (var p in props)
        {
            if (p.CanWrite && formKeyMap.ContainsKey(p.Name.ToUpper()))
            {
                p.SetValue(instance, form[formKeyMap[p.Name.ToUpper()]].FirstOrDefault());
            }
        }

        return instance;
    }
}

This will attempt to bind an IFormCollection to whatever model type you pass in. Property names are case insensitive (i.e. you can map firstname=Bob to public string FirstName { get; set; }.

Usage:

var myModel = (await httpReq.ReadFormAsync()).BindToModel<MyModel>();



回答3:


To read form data, you should use the method ReadAsMultipartAsync:

data = await req.Content.ReadAsMultipartAsync().ConfigureAwait(false);


来源:https://stackoverflow.com/questions/45364128/how-to-parse-form-data-using-azure-functions

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!