问题
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