C#Owin WebApp:解析POST请求?

时间:2013-12-14 00:53:30

标签: c# jquery html post owin

我想在C#控制台应用程序中解析HTTP POST请求方面的一些帮助。该应用程序使用Owin运行“网络服务器”。该应用程序的详细信息可用here,相关代码的当前“稳定版本”为here

我正在扩展上述应用程序以通过Web UI启用配置。例如,app当前报告了大量参数。我希望最终用户能够选择通过网络报告哪些参数。为此,我对上面的代码做了一些修改:

    using Microsoft.Owin;
    using Owin;
    .........
    [assembly: OwinStartup(typeof(SensorMonHTTP.WebIntf))]
    .........
    .........
    namespace SensorMonHTTP
    {
      ...
      public class WebIntf
      {
        public void Configuration(IAppBuilder app)
        {
          app.Run(context =>
          {
            var ConfigPath = new Microsoft.Owin.PathString("/config");
            var ConfigApplyPath = new Microsoft.Owin.PathString("/apply_config");
            var SensorPath = new Microsoft.Owin.PathString("/");
            if (context.Request.Path == SensorPath) 
            { 
              return context.Response.WriteAsync(GetSensorInfo()); 
              /* Returns JSON string with sensor information */
            }
            else if (context.Request.Path == ConfigPath)
            {
              /* Generate HTML dynamically to list out available sensor 
                 information with checkboxes using Dynatree: Tree3 under 
                 'Checkbox & Select' along with code to do POST under 
                 'Embed in forms' in 
                 http://wwwendt.de/tech/dynatree/doc/samples.html */
              /* Final segment of generated HTML is as below:
              <script>
              .....
              $("form").submit(function() {
                var formData = $(this).serializeArray();
                var tree = $("#tree3").dynatree("getTree");
                formData = formData.concat(tree.serializeArray());
                // alert("POST this:\n" + jQuery.param(formData)); 
                // -- This gave the expected string in an alert when testing out
                $.post("apply_config", formData);
                return true ;
              });
              ......
              </script></head>
              <body>
              <form action="apply_config" method="POST">
              <input type="submit" value="Log Selected Parameters">
              <div id="tree3" name="selNodes"></div>
              </body>
              </html>
              End of generated HTML code */
            }
            else if (context.Request.Path == ConfigApplyPath)
            {
              /* I want to access and parse the POST data here */
              /* Tried looking into context.Request.Body as a MemoryStream, 
                 but not getting any data in it. */
            }
          }
        }
        ........
      }

任何人都可以帮助我了解如何在上面的代码结构中访问POST数据吗?

提前致谢!

5 个答案:

答案 0 :(得分:9)

由于数据以KeyValuePair格式返回,您可以将其转换为IEnumerable,如下所示:

var formData = await context.Request.ReadFormAsync() as IEnumerable<KeyValuePair<string, string[]>>;

//现在你有了可以查询的列表

var formElementValue = formData.FirstOrDefault(x => x.Key == "NameOfYourHtmlFormElement").Value[0]);

答案 1 :(得分:4)

您可以使用IOwinRequest对象上的ReadFormAsync()实用程序来读取/解析表单参数。

public void Configuration(IAppBuilder app)
        {
            app.Run(async context =>
                {
                    //IF your request method is 'POST' you can use ReadFormAsync() over request to read the form 
                    //parameters
                    var formData = await context.Request.ReadFormAsync();
                    //Do the necessary operation here. 
                    await context.Response.WriteAsync("Hello");
                });
        }

答案 2 :(得分:1)

要为每种内容类型提取body参数,您可以使用以下方法:

    public async static Task<IDictionary<string, string>> GetBodyParameters(this IOwinRequest request)
    {
        var dictionary = new Dictionary<string, string>(StringComparer.CurrentCultureIgnoreCase);

        if (request.ContentType != "application/json")
        {
            var formCollectionTask = await request.ReadFormAsync();

            foreach (var pair in formCollectionTask)
            {
                var value = GetJoinedValue(pair.Value);
                dictionary.Add(pair.Key, value);
            }
        }
        else
        {
            using (var stream = new MemoryStream())
            {
                byte[] buffer = new byte[2048]; // read in chunks of 2KB
                int bytesRead;
                while ((bytesRead = request.Body.Read(buffer, 0, buffer.Length)) > 0)
                {
                    stream.Write(buffer, 0, bytesRead);
                }
                var result = Encoding.UTF8.GetString(stream.ToArray());
                // TODO: do something with the result
                var dict = JsonConvert.DeserializeObject<Dictionary<string, object>>(result);

                foreach(var pair in dict)
                {
                    string value = (pair.Value is string) ? Convert.ToString(pair.Value) : JsonConvert.SerializeObject(pair.Value);
                    dictionary.Add(pair.Key, value);
                }
            }
        }

        return dictionary;
    }

    private static string GetJoinedValue(string[] value)
    {
        if (value != null)
            return string.Join(",", value);

        return null;
    }

参考文献: Most efficient way of reading data from a stream

答案 3 :(得分:0)

context.Request.Body是获取POST值的正确位置,但您需要在要访问的表单元素上包含name属性。如果没有name属性,一切都会被忽略,虽然有可能,但我无法找到访问原始请求的方法 - 之前从未使用过Owin。

if (context.Request.Path == ConfigPath)
{
    StringBuilder sb = new StringBuilder();

    sb.Append("<html><head></head><body><form action=\"apply_config\" method=\"post\">");
    sb.Append("<input type=\"submit\" value=\"Log Selected Parameters\">");
    sb.Append("<input type=\"text\" value=\"helloworld\" name=\"test\"></input>");
    sb.Append("</body>");
    sb.Append("</html>");

    return context.Response.WriteAsync(sb.ToString());
}
else if (context.Request.Path == ConfigApplyPath)
{
    /* I want to access and parse the POST data here */
    /* Tried looking into context.Request.Body as a MemoryStream, 
        but not getting any data in it. */
    StringBuilder sb = new StringBuilder();
    byte[] buffer = new byte[8000];
    int read = 0;

    read = context.Request.Body.Read(buffer, 0, buffer.Length);
    while (read > 0)
    {
        sb.Append(Encoding.UTF8.GetString(buffer));
        buffer = new byte[8000];
        read = context.Request.Body.Read(buffer, 0, buffer.Length);
    }


    return context.Response.WriteAsync(sb.ToString());
}
else 
{
    return context.Response.WriteAsync(GetSensorInfo());
    /* Returns JSON string with sensor information */
}

答案 4 :(得分:0)

以下工作,诀窍是重置流的位置。

context.Request.Body.Position = 0;
string content = new StreamReader(context.Request.Body).ReadToEnd();