hi - suppose i have a form where the user is required to enter text into several fields and also browse to and select an image file for upload. any ideas on how that might be implemented? i have tried various things, including the usual suspects from the
jquery file upload plugins, and cannot get it to work.
You can use the MultipartFormDataStreamProvider. Following is a sample FileUploadController and corresponding html form.
public class FileUploadController : ApiController
{
[HttpPost]
public List<FileResult> UploadFile()
{
// Verify that this is an HTML Form file upload request
if (!Request.Content.IsMimeMultipartContent("form-data"))
{
throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
}
// Create a stream provider for setting up output streams
MultipartFormDataStreamProvider streamProvider = new MultipartFormDataStreamProvider();
// Read the MIME multipart content using the stream provider we just created.
IEnumerable<HttpContent> bodyparts = Request.Content.ReadAsMultipartAsync(streamProvider).Result;
// The submitter field is the entity with a Content-Disposition header field with a "name" parameter with value "submitter"
string submitter;
if (!bodyparts.TryGetFormFieldValue("submitter", out submitter))
{
submitter = "unknown";
}
// Get a dictionary of local file names from stream provider.
// The filename parameters provided in Content-Disposition header fields are the keys.
// The local file names where the files are stored are the values.
IDictionary<string, string> bodyPartFileNames = streamProvider.BodyPartFileNames;
// Create response containing information about the stored files.
return bodyPartFileNames.Select(kv =>
{
FileInfo fileinfo = new FileInfo(kv.Value);
return new FileResult
{
FileName = kv.Key,
LocalPath = fileinfo.FullName,
LastModifiedTime = fileinfo.LastWriteTimeUtc,
Length = fileinfo.Length,
Submitter = submitter
};
}).ToList();
}
private static bool TryGetFormFieldValue(IEnumerable<HttpContent> contents, string dispositionName, out string formFieldValue)
{
HttpContent content = contents.FirstDispositionNameOrDefault(dispositionName);
if (content != null)
{
formFieldValue = content.ReadAsStringAsync().Result;
return true;
}
formFieldValue = null;
return false;
}
}
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>File Service Sample Upload Data Form</title> </head> <body> <h1> File Service Sample Upload Data Form</h1> <p> This sample WCF service reads the contents of an HTML file upload and writes one or more body parts to a local file.</p> <form action="http://localhost:8081/fileservice" enctype="multipart/form-data" method="POST"> What is your name? <input name="submitter" size="40" type="text"><br> What file are you uploading? <input name="data" size="40" type="file"> (please use the file <b>SampleData.random</b>)<br> <br> <input type="submit"> </form> </body> </html>
Consider using the HTML5 File APIs. Your JavaScript can read the file and then submit it along with whatever other JSON data the REST endpoint wants. Something like this:
$("#file").change(function () {
var file = document.getElementById("file").files[0];
if (file) {
var rdr = new FileReader();
rdr.onload = function (e) {
var imageData = e.target.result;
};
rdr.readAsDataURL(file);
}
});
that would be nice brockallen but the computer says "no" :(
if (window.File && window.FileReader && window.FileList && window.Blob) {
// Great success! All the File APIs are supported.
}
else {
alert(
'The File APIs are not fully supported in this browser.');}
i revisited your code troy (FileUploadController). it works well ( after a couple of tweaks ;) ) so i guess a way forward would be to submit the file first, get back file data and include that data when submitting the rest of the form. i'm now using html5 (building on your
suggestions b/allen, cheers) at the front end and it all seems to hang together quite well. many thanks guys.
You can use the MultipartFormDataStreamProvider. Following is a sample FileUploadController and corresponding html form.
public class FileUploadController : ApiController
{
[HttpPost]
public List<FileResult> UploadFile()
{
// Verify that this is an HTML Form file upload request
if (!Request.Content.IsMimeMultipartContent("form-data"))
{
throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
}
// Create a stream provider for setting up output streams
MultipartFormDataStreamProvider streamProvider = new MultipartFormDataStreamProvider();
// Read the MIME multipart content using the stream provider we just created.
IEnumerable<HttpContent> bodyparts = Request.Content.ReadAsMultipartAsync(streamProvider).Result;
// The submitter field is the entity with a Content-Disposition header field with a "name" parameter with value "submitter"
string submitter;
if (!bodyparts.TryGetFormFieldValue("submitter", out submitter))
{
submitter = "unknown";
}
// Get a dictionary of local file names from stream provider.
// The filename parameters provided in Content-Disposition header fields are the keys.
// The local file names where the files are stored are the values.
IDictionary<string, string> bodyPartFileNames = streamProvider.BodyPartFileNames;
// Create response containing information about the stored files.
return bodyPartFileNames.Select(kv =>
{
FileInfo fileinfo = new FileInfo(kv.Value);
return new FileResult
{
FileName = kv.Key,
LocalPath = fileinfo.FullName,
LastModifiedTime = fileinfo.LastWriteTimeUtc,
Length = fileinfo.Length,
Submitter = submitter
};
}).ToList();
}
private static bool TryGetFormFieldValue(IEnumerable<HttpContent> contents, string dispositionName, out string formFieldValue)
{
HttpContent content = contents.FirstDispositionNameOrDefault(dispositionName);
if (content != null)
{
formFieldValue = content.ReadAsStringAsync().Result;
return true;
}
formFieldValue = null;
return false;
}
}
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>File Service Sample Upload Data Form</title> </head> <body> <h1> File Service Sample Upload Data Form</h1> <p> This sample WCF service reads the contents of an HTML file upload and writes one or more body parts to a local file.</p> <form action="http://localhost:8081/fileservice" enctype="multipart/form-data" method="POST"> What is your name? <input name="submitter" size="40" type="text"><br> What file are you uploading? <input name="data" size="40" type="file"> (please use the file <b>SampleData.random</b>)<br> <br> <input type="submit"> </form> </body> </html>
Hi, is there a sample file for MultipartFileStreamProvider?
As we try to upload a file (image more precisly) not from a form but from a mobile app (ios).
WindKnot
Member
24 Points
10 Posts
submitting files to a web api
Feb 22, 2012 04:04 PM|LINK
hi - suppose i have a form where the user is required to enter text into several fields and also browse to and select an image file for upload. any ideas on how that might be implemented? i have tried various things, including the usual suspects from the jquery file upload plugins, and cannot get it to work.
SixiS
Member
50 Points
16 Posts
Re: submitting files to a web api
Feb 22, 2012 04:27 PM|LINK
on the client side the easiest way is to use the jquery-form plugin. on the server side you can use alex's solution http://blog.alexonasp.net/post/2011/07/27/POSTing-Uploading-Files-using-the-WCF-Web-API.aspx . the example is for wcf web api. but it is easy to rewrite the code for asp.net web api.
Troy Dai
Member
8 Points
4 Posts
Microsoft
Re: submitting files to a web api
Feb 22, 2012 04:46 PM|LINK
Hi Windknot,
You can use the MultipartFormDataStreamProvider. Following is a sample FileUploadController and corresponding html form.
public class FileUploadController : ApiController { [HttpPost] public List<FileResult> UploadFile() { // Verify that this is an HTML Form file upload request if (!Request.Content.IsMimeMultipartContent("form-data")) { throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType); } // Create a stream provider for setting up output streams MultipartFormDataStreamProvider streamProvider = new MultipartFormDataStreamProvider(); // Read the MIME multipart content using the stream provider we just created. IEnumerable<HttpContent> bodyparts = Request.Content.ReadAsMultipartAsync(streamProvider).Result; // The submitter field is the entity with a Content-Disposition header field with a "name" parameter with value "submitter" string submitter; if (!bodyparts.TryGetFormFieldValue("submitter", out submitter)) { submitter = "unknown"; } // Get a dictionary of local file names from stream provider. // The filename parameters provided in Content-Disposition header fields are the keys. // The local file names where the files are stored are the values. IDictionary<string, string> bodyPartFileNames = streamProvider.BodyPartFileNames; // Create response containing information about the stored files. return bodyPartFileNames.Select(kv => { FileInfo fileinfo = new FileInfo(kv.Value); return new FileResult { FileName = kv.Key, LocalPath = fileinfo.FullName, LastModifiedTime = fileinfo.LastWriteTimeUtc, Length = fileinfo.Length, Submitter = submitter }; }).ToList(); } private static bool TryGetFormFieldValue(IEnumerable<HttpContent> contents, string dispositionName, out string formFieldValue) { HttpContent content = contents.FirstDispositionNameOrDefault(dispositionName); if (content != null) { formFieldValue = content.ReadAsStringAsync().Result; return true; } formFieldValue = null; return false; } }WindKnot
Member
24 Points
10 Posts
Re: submitting files to a web api
Feb 22, 2012 05:29 PM|LINK
thanks for the replies.
i have tried the jquery-form plugin to no avail. i can't get it to work within the api context.
troy, how would your solution work via an ajax submission?
BrockAllen
All-Star
28042 Points
4991 Posts
MVP
Re: submitting files to a web api
Feb 22, 2012 06:13 PM|LINK
Consider using the HTML5 File APIs. Your JavaScript can read the file and then submit it along with whatever other JSON data the REST endpoint wants. Something like this:
$("#file").change(function () { var file = document.getElementById("file").files[0]; if (file) { var rdr = new FileReader(); rdr.onload = function (e) { var imageData = e.target.result; }; rdr.readAsDataURL(file); } });DevelopMentor | http://www.develop.com
thinktecture | http://www.thinktecture.com/
WindKnot
Member
24 Points
10 Posts
Re: submitting files to a web api
Feb 22, 2012 07:37 PM|LINK
that would be nice brockallen but the computer says "no" :(
if (window.File && window.FileReader && window.FileList && window.Blob) { // Great success! All the File APIs are supported. } else { alert( 'The File APIs are not fully supported in this browser.');}BrockAllen
All-Star
28042 Points
4991 Posts
MVP
Re: submitting files to a web api
Feb 22, 2012 07:51 PM|LINK
Yea, that's why I linked the caniuse.com page to show which browsers supported it. Too bad.
DevelopMentor | http://www.develop.com
thinktecture | http://www.thinktecture.com/
WindKnot
Member
24 Points
10 Posts
Re: submitting files to a web api
Feb 24, 2012 01:02 PM|LINK
i revisited your code troy (FileUploadController ). it works well ( after a couple of tweaks ;) ) so i guess a way forward would be to submit the file first, get back file data and include that data when submitting the rest of the form. i'm now using html5 (building on your suggestions b/allen, cheers) at the front end and it all seems to hang together quite well. many thanks guys.
ozba1
Member
12 Points
51 Posts
Re: submitting files to a web api
May 22, 2012 03:18 PM|LINK
Hi, is there a sample file for MultipartFileStreamProvider?
As we try to upload a file (image more precisly) not from a form but from a mobile app (ios).
Thanks