You can easily do this using the glorious HttpMultipartParser library. The source code and documentation are available on GitHub. Here is a sample route using Grapevine 5.0.0-rc.9:
[RestRoute("Post", "/submit-form")]
[Header("Content-Type", "multipart/form-data")]
public async Task ParseMultipartFormData(IHttpContext context)
{
var content = await MultipartFormDataParser.ParseAsync(context.Request.InputStream, context.Request.MultipartBoundary, context.Request.ContentEncoding);
var name = $"{content.GetParameterValue("FirstName")} {content.GetParameterValue("LastName")} : {content.Files.Count}";
await context.Response.SendResponseAsync(name);
}
The header filter on Content-Type
is optional, but it does ensure that this route doesn't get called unless there is actually multipart form data to parse.
Use Postman or some other tool, and pass FirstName
, LastName
, and one or more files, it will return the concatenated name and count of the files submitted. Put a breakpoint before the response is written and you can inspect the value of content
to see how to get at the file information. Writing the files to disk should be easy to do at that point.
IMPORTANT
The input stream on the request can only be read once! If you want this data to be available to other requests, add it to context.Locals
, or, better yet, use the following middleware to do that for you automatically!
public static class MultiPartFormData
{
public async static Task Parse(IHttpContext context, IRestServer server)
{
if (string.IsNullOrWhiteSpace(request.ContentType) || !request.ContentType.StartsWith("multipart/form-data; boundary=")) return;
context.Locals.TryAdd("FormData", await MultipartFormDataParser.ParseAsync(context.Request.InputStream, context.Request.MultipartBoundary, context.Request.ContentEncoding));
}
public static IRestServer AutoParseMultipartFormData(this IRestServer server)
{
server.OnRequestAsync -= MultiPartFormData.Parse;
server.OnRequestAsync += MultiPartFormData.Parse;
return server;
}
}
Then when configuring your server, you can make a simple call to server.AutoParseMultipartFormData()
, and the data will be available to you in all of your routes if it exists, without you having to parse it explicitly.