user3378165
user3378165

Reputation: 6926

Upload Document to Web API

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

Answers (3)

user3378165
user3378165

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

MasterJohn
MasterJohn

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

kevintechie
kevintechie

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

Related Questions