16

I send a multipart form data to my Web API like this:

string example = "my string";
HttpContent stringContent = new StringContent(example);
HttpContent fileStreamContent = new StreamContent(stream);
using (var client = new HttpClient())
{
    using (var content = new MultipartFormDataContent())
    {
         content.Add(stringContent, "example", "example");
         content.Add(fileStreamContent, "stream", "stream");
         var uri = "http://localhost:58690/api/method";
         HttpResponseMessage response = await client.PostAsync(uri, content);

and this is the Web API:

[HttpPost]
[Route("api/method")]
public async Task<HttpResponseMessage> Method()
    {
         // take contents and do something
    }

How read the string and the stream from request body in my Web API?

7 Answers 7

17

This should help you get started:

 var uploadPath = HostingEnvironment.MapPath("/") + @"/Uploads";
 Directory.CreateDirectory(uploadPath);
 var provider = new MultipartFormDataStreamProvider(uploadPath);
 await Request.Content.ReadAsMultipartAsync(provider);

 // Files
 //
 foreach (MultipartFileData file in provider.FileData)
 {
     Debug.WriteLine(file.Headers.ContentDisposition.FileName);
     Debug.WriteLine("File path: " + file.LocalFileName);
 }

 // Form data
 //
 foreach (var key in provider.FormData.AllKeys)
 {
     foreach (var val in provider.FormData.GetValues(key))
     {
          Debug.WriteLine(string.Format("{0}: {1}", key, val));
     }
 }
Sign up to request clarification or add additional context in comments.

3 Comments

Thank you! If I don't need to save the parameters on the server where is my Web API, but only manipulate their, the procedure is the same?
@Giobbo...I'm not sure what you mean by save the parameters. Do you mean the request body's contents (files, etc.)? If so, no, you can keep them in memory, but be careful with large files.
Yes, sorry (my english is terrible). I mean the body contents, stream and string in my example. I want simply take from the body and do something with their.
13

This is code i've used before to receive json data + an optional file:

var result = await Request.Content.ReadAsMultipartAsync();

var requestJson = await result.Contents[0].ReadAsStringAsync();
var request = JsonConvert.DeserializeObject<MyRequestType>(requestJson);

if (result.Contents.Count > 1)
{
    var fileByteArray = await result.Contents[1].ReadAsByteArrayAsync();
    ...
}

Its really neat that you can combine different types of data in a request like this.

Edit: an example of how to send this request:

let serialisedJson = JSON.stringify(anyObject);
let formData = new FormData();
formData.append('initializationData', serialisedJson);
// fileObject is an instance of File
if (fileObject) {
    // the 'jsonFile' name might cause some confusion: 
    // in this case, the uploaded file is actually a textfile containing json data
    formData.append('jsonFile', fileObject);
}

return new Promise((resolve, reject) => {
    let xhr = new XMLHttpRequest();
    xhr.open('POST', 'http://somewhere.com', true);
    xhr.onload = function(e: any) {
        if (e.target.status === 200) {
            resolve(JSON.parse(e.target.response));
        }
        else {
            reject(JSON.parse(e.target.response));
        }
    };
    xhr.send(formData);
});

4 Comments

What does the request look like?
For this example, in my clientside code i instantiate a FormData class, to which i then add the serialized json (so not the object itself, but the stringified version), and optionally i might also add a File object, then i send the FormData instance with the XmlHttpRequest (im actually using angular2 to do this request, but the Http service of angular does not allow you to do this, so you need to handle the XmlHttpRequest yourself)
I actually just got sending a FormData object with some fields and a file via angular $http service working for my project last night. The main oddness was that I had to explicitly set the content-type to undefined.. and I didn't serialize anything, just set the body to the FormData object. Im using Angular 1.6 though.
Oh and you're using an xml request, mine ended up being a form/multi-part, interesting.. :)
8

You can read content and get all file information (in my example image) without copying to local disk in this way:

public async Task<IHttpActionResult> UploadFile()
{
    if (!Request.Content.IsMimeMultipartContent())
    {
        return StatusCode(HttpStatusCode.UnsupportedMediaType);
    }        

    var filesReadToProvider = await Request.Content.ReadAsMultipartAsync();

    foreach (var stream in filesReadToProvider.Contents)
    {
        // Getting of content as byte[], picture name and picture type
        var fileBytes = await stream.ReadAsByteArrayAsync();
        var pictureName = stream.Headers.ContentDisposition.FileName;
        var contentType = stream.Headers.ContentType.MediaType;
    }
}

Comments

1

For sending more than one file

        System.Web.HttpFileCollection hfc = System.Web.HttpContext.Current.Request.Files;

        //// CHECK THE FILE COUNT.
        for (int iCnt = 0; iCnt <= hfc.Count - 1; iCnt++)
        {
            System.Web.HttpPostedFile hpf = hfc[iCnt];
            string Image = UploadDocuments.GetDocumentorfileUri(hpf);
            UploadDocuments.UploadDocumentsIntoData(Image, hpf.FileName, id);

        }

Sending HTML Form Data in ASP.NET Web API: File Upload and Multipart MIME

Comments

0
 // read the file content without copying to local disk and write the content byte to file 
       try
       {
           var filesReadToProvider = await Request.Content.ReadAsMultipartAsync();
           JavaScriptSerializer json_serializer = new JavaScriptSerializer();

           foreach (var stream in filesReadToProvider.Contents)
           {

               //getting of content as byte[], picture name and picture type
               var fileBytes = await stream.ReadAsByteArrayAsync();
               var fileName = stream.Headers.ContentDisposition.Name;

               var pictureName = stream.Headers.ContentDisposition.FileName;
               var contentType = stream.Headers.ContentType.MediaType;
               var path = Path.Combine(HttpContext.Current.Server.MapPath("~/Images/Upload/"), json_serializer.Deserialize<string>(pictureName));

               File.WriteAllBytes(path, fileBytes);
           }

           return Request.CreateResponse(HttpStatusCode.OK);
       }catch(Exception ex)
       {
           return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, ex);
       }

Comments

0

//Web User Interface Method protected void btnPrescAdd_Click(object sender, EventArgs e) {

        NameValueCollection collection = new NameValueCollection();

        collection.Set("c1", Session["CredID"].ToString());
        collection.Set("p1", "");
        collection.Set("p2", Request.Form["ctl00$MainContent$hdnHlthId"]);
        collection.Set("p3", Request.Form["ctl00$MainContent$PresStartDate"]);
        collection.Set("p4", Request.Form["ctl00$MainContent$PrescEndDate"]);

        FileUpload fileUpload = PrescUpload;

        ApiServices<Status> obj = new ApiServices<Status>();
        Status objReturn = obj.FetchObjectUploadAPI("POSTUHRPL", collection, 
         fileUpload, ApiServices<Status>.ControllerType.DU);

    }

//Request Method

  public T1 FetchObjectUploadAPI(string strAPIMethod, NameValueCollection collection, FileUpload file, ControllerType enObj)
    {
        T1 objReturn;
        try
        {
            string url = strWebAPIUrl + getControllerName(enObj) + strAPIMethod;

            MultipartFormDataContent content = new MultipartFormDataContent();



            int count = collection.Count;
            List<string> Keys = new List<string>();
            List<string> Values = new List<string>();

            //MemoryStream filedata = new MemoryStream(file);
            //Stream  stream = filedata;
            for (int i = 0; i < count; i++)
            {
                Keys.Add(collection.AllKeys[i]);
                Values.Add(collection.Get(i));

            }

            for (int i = 0; i < count; i++)
            {
                content.Add(new StringContent(Values[i], Encoding.UTF8, "multipart/form-data"), Keys[i]);
            }

            int fileCount = file.PostedFiles.Count();

            HttpContent filecontent = new StreamContent(file.PostedFile.InputStream);


            content.Add(filecontent, "files");

            HttpClient client = new HttpClient();


            HttpResponseMessage response = client.PostAsync(url, content).Result;

            if (response.IsSuccessStatusCode)
            {
                objReturn = (new JavaScriptSerializer()).Deserialize<T1>(response.Content.ReadAsStringAsync().Result);
            }
            else
                objReturn = default(T1);

        }
        catch (Exception ex)
        {
            Logger.WriteLog("FetchObjectAPI", ex, log4net_vayam.Constants.levels.ERROR);
            throw (ex);
        }
        return objReturn;

    }

https://stackoverflow.com/users/9600164/gaurav-sharma

Comments

0

Super late to the party, but anyone else having to work with ASP.NET Web API (1/2):

    [HttpPost, Route("img/up")]
    public async Task<IHttpActionResult> ItemImage()
    {
        var data = HttpContext.Current.Request.Form["example"];
        var item = JsonConvert.DeserializeObject<Example>(data);
        if (item == null) return BadRequest("Invalid request: Example cannot be null");

        var path = HostingEnvironment.MapPath("/") + @"img";
        if (!Directory.Exists(path))
            Directory.CreateDirectory(path);

        try
        {
            var image = HttpContext.Current.Request.Files["stream"];
            if (image == null) return BadRequest("Invalid request: no image received.");
            path = $@"{path}\{DateTime.Now:MMddyyHHmmss}.png";
            image.SaveAs(path);
        }
        catch (Exception e)
        {
            // TODO: Document Exception
        }
        return Ok();
    }

Here you can see that we're accepting HttpPost requests to /api/img/up endpoint. Currently we're not checking Mime type but you can if desired.

First we get the Form Data for your "example" and deserialize it from json to the Example class (replace this with what you're using as your model)

Then we make sure the img directory exists (modify the path if you want it somewhere outside of your API files)

Then we get the stream object from the HttpContext.Current.Request.Files["stream"] I took this snippet from an endpoint where the filename is a timestamp (to support multiple images for the same identifier)

I tried to keep it simple and sweet, it can be a tad abstract because of the Client / Server layering.

If you need to test I recommend PostMan:

Sample Postman Test

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.