如何使用Azure Functions解析表单数据

问题描述:

我正在尝试在Azure函数中获取表单数据.

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");
}

我遇到以下错误:

执行函数:System.Net.Http.Formatting时发生异常:没有MediaTypeFormatter可以从媒体类型为"multipart/form-data"的内容中读取"FormDataCollection"类型的对象.

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'.

我试图按此处所述通过SendGrid解析入站电子邮件. https://sendgrid.com/docs/Classroom/Basics/Inbound_Parse_Webhook/setting_up_the_inbound_par.

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

传入请求看起来正确.

-xYzZY内容处置:表单数据;name =附件"

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

0--xYzZY内容处置:表单数据;name ="text"

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

你好世界--xYzZY内容处置:表单数据;name ="subject"

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

主题--xYzZY内容处置:表单数据;name ="to"

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

由于似乎没有将 IFormCollection 转换为自定义模型/视图模型类型的好方法,所以我写了一篇扩展方法.

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.

Azure Functions v2/v3尚不支持此功能是很遗憾的.

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;
    }
}

这将尝试将 IFormCollection 绑定到您传递的任何模型类型.属性名称不区分大小写(即,您可以将 firstname = Bob 映射到 public字符串FirstName {get; set;} .

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; }.

用法:

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