Reputation: 6926
First Step: On my MVC project I have a Div that allow to upload a file.
<div id="modalUpload" style="display:none">
Select a file:
<input id="upload" type="file" name="upload" /><br />
Description:
<input id="documentDescription" type="text" /><br />
<input type="button" value="Submit" id="submitUpload" data-bind="click:function(){ $root.upload() }">
</div>
Second Step: In JavaScript I upload the Document to the web API with a POST request: (for example, with the XMLHttpRequest method)
self.upload = function () {
var file = document.getElementById("upload").files[0];
var xhr = new XMLHttpRequest();
xhr.open('post', "/API/document/addDocument/", true);
xhr.send(file);
}
Third Step: This is my addDocument function on the Web API that expects a Document object, like this:
[HttpPost]
[Route("{controller}/addDocument")]
public string Post([FromBody]Document doc)
{
.......
}
My question is, how can I post the Document to the API as a Document object? Is it possible to set the type of the POST data?
On my JavaScript code, I have a Document object:
var Document = function (data) {
this.id = ko.observable(data.id);
this.name= ko.observable(data.name);
this.size= ko.observable(data.zise);
}
But I'm not sure how to connect between them.
When I tried this:
var file = new Document(document.getElementById("upload").files[0]);
I got the following error:
415 (Unsupported Media Type)
Any help would be very much appreciated.
Upvotes: 1
Views: 9398
Reputation: 6926
Finally, I didn't send the document as an object, and this is what I ended up doing,
self.upload = function () {
if (document.getElementById("upload").value != "") {
var file = document.getElementById("upload").files[0];
var filePath = "....";
if (window.FormData !== undefined) {
var data = new FormData();
data.append("file", file);
var encodedString = Base64.encode(filePath);
$.ajax({
type: "POST",
url: "/API/document/upload/" + file.name + "/" + encodedString ,
contentType: false,
processData: false,
data: data,
success: function (result) {
console.log(result);
},
error: function (xhr, status, p3, p4) {
var err = "Error " + " " + status + " " + p3 + " " + p4;
if (xhr.responseText && xhr.responseText[0] == "{")
err = JSON.parse(xhr.responseText).Message;
console.log(err);
}
});
}
}
}
And this is my API function:
[HttpPost]
[Route("{controller}/upload/{fileName}/{filePath}")]
public async Task<HttpResponseMessage> UploadFile(string fileName, string filePath)
{
if (!Request.Content.IsMimeMultipartContent())
{
return Request.CreateErrorResponse(HttpStatusCode.UnsupportedMediaType, "The request doesn't contain valid content!");
}
byte[] data = Convert.FromBase64String(filePath);
filePath = Encoding.UTF8.GetString(data);
try
{
var provider = new MultipartMemoryStreamProvider();
await Request.Content.ReadAsMultipartAsync(provider);
foreach (var file in provider.Contents)
{
var dataStream = await file.ReadAsStreamAsync();
// use the data stream to persist the data to the server (file system etc)
using (var fileStream = File.Create(filePath + fileName))
{
dataStream.Seek(0, SeekOrigin.Begin);
dataStream.CopyTo(fileStream);
}
var response = Request.CreateResponse(HttpStatusCode.OK);
response.Content = new StringContent("Successful upload", Encoding.UTF8, "text/plain");
response.Content.Headers.ContentType = new MediaTypeWithQualityHeaderValue(@"text/html");
return response;
}
return Request.CreateResponse(HttpStatusCode.ExpectationFailed);
}
catch (Exception e)
{
return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, e.Message);
}
}
That works perfectly, I got the idea from here.
Upvotes: 1
Reputation: 439
You could try getting it as an HttpPostedFileBase
[HttpPost]
[Route("{controller}/addDocument")]
public string Post(HttpPostedFileBase doc)
{
//Parse it to a doc and do what you gotta do
}
Upvotes: 1
Reputation: 1521
One possible issue is that you'll need to make sure your XHR request declares the correct MIME type in the accept header.
Using XHR directly can be a bit of a pain. You may want to consider using a client-side library (such as jquery) to make things easier and handle any cross-browser inconsistencies.
Upvotes: 2