I would like some help on parsing HTTP POST requests in a C# console application. The app runs a 'web-server' using Owin. Details of the application are available here and the current 'stable version' of the relevant code is here.
I am extending the above application to enable configuration through the web UI. For example, the app currently reports a large number of parameters. I would like the end-user to be able to select which parameters get reported over the network. Towards this, I made some modifications to the code above:
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. */
}
}
}
........
}
Can anyone help me with how the POST data can be accessed in the above code structure?
Thanks in advance!
Since the data returns in KeyValuePair format you can cast it as IEnumerable which looks something like the following:
var formData = await context.Request.ReadFormAsync() as IEnumerable<KeyValuePair<string, string[]>>;
//now you have the list that you can query against
var formElementValue = formData.FirstOrDefault(x => x.Key == "NameOfYourHtmlFormElement").Value[0]);
You can use the ReadFormAsync() utility on the IOwinRequest object to read/parse the form parameters.
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");
});
}
To extract the body Parameters for each content type you can use a method like this:
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;
}
References: Most efficient way of reading data from a stream
The context.Request.Body is the right place to get POST values, but you need to include a name attribute on the form elements that you want to access. Without the name attribute everything is ignored, and I wasn't able to find a way to access the raw request although it might be possible - never used Owin before.
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 */
}
The following works, the trick is to reset the position of the stream.
context.Request.Body.Position = 0;
string content = new StreamReader(context.Request.Body).ReadToEnd();
来源:https://stackoverflow.com/questions/20578452/c-sharp-owin-webapp-parsing-post-requests