Upload File with Other Body Parameters in ASP.Net Web API


I recently had a requirement in an angular application I was writing for a client to upload image with other body parameters via ASP.Net API. It look pretty easy to me at first, but I later realize that it's a little bit tricky.

In this article am going to walk you through how I finally got it done.


Upload Only File Without Parameter

Let's see how it can be done if we want to upload an image without any additional form information in web api,

Web API Controller

The code below is all we need to get an image from an incoming request from the API consumer.

        [HttpPost]
        public HttpResponseMessage UploadImage()
        {
            var exMessage = string.Empty;
            try
            {
                string uploadPath = "~/content/upload";
                HttpPostedFile file = null;
                if (HttpContext.Current.Request.Files.Count > 0)
                {
                    file = HttpContext.Current.Request.Files.Get("file");
                }
                // Check if we have a file
                if (null == file)
                    return Request.CreateResponse(HttpStatusCode.BadRequest, new
                    {
                        error = true,
                        message = "Image file not found"
                    });

                // Make sure the file has content
                if (!(file.ContentLength > 0))
                    return Request.CreateResponse(HttpStatusCode.BadRequest, new
                    {
                        error = true,
                        message = "Image file not found"
                    });

                if (!Directory.Exists(HttpContext.Current.Server.MapPath(uploadPath)))
                {
                    // If it doesn't exist, create the directory
                    Directory.CreateDirectory(HttpContext.Current.Server.MapPath(uploadPath));
                }

                //Upload File
                file.SaveAs(HttpContext.Current.Server.MapPath($"{uploadPath}/{file.FileName}"));

            }
            catch (Exception ex)
            {
                exMessage = ex.Message;
            }
            return Request.CreateResponse(HttpStatusCode.BadRequest, new { error = true, message = exMessage == string.Empty ? "An unknown error occured" : exMessage });
        }


In the code above all I have done is to check if we have file in the request, and if exist check if there anyone with the key of file.


Angular Service Method

We only need the below code in the angular app that we send the image to our API:

    uploadImage(url: string, params: any, file: File) {
        return new Promise((resolve, reject) => {
            var formData: any = new FormData();
            var xhr = new XMLHttpRequest();
            formData.append("file", file, file.name);
           
            xhr.onreadystatechange = function () {
                if (xhr.readyState == 4) {
                    if (xhr.status == 201) {
                        resolve(JSON.parse(xhr.response));

                    } else {
                        reject(JSON.parse(xhr.response));
                    }
                }
            }
            xhr.open("POST", url, true);
            xhr.send(formData);
        });
    }

Upload with more parameters

As you can see that what have done so far is fairly straight forward. But what if we want to send some more fields with the image - say for example, we want to upload a product image and we need to send the productId and description in the request.

What I have to do to accomplish this task is to modify the uploadImage method in the angular service by adding this two lines:


formData.append("productId", params.productId);
formData.append("description", params.description);

Now the uploadImage method should look like this:

    
    uploadImage(url: string, params: any, file: File) {
        return new Promise((resolve, reject) => {
            var formData: any = new FormData();
            var xhr = new XMLHttpRequest();
            formData.append("file", file, file.name);
            
            formData.append("productId", params.productId);
            formData.append("description", params.description);

            xhr.onreadystatechange = function () {
                if (xhr.readyState == 4) {
                    if (xhr.status == 201) {
                        resolve(JSON.parse(xhr.response));

                    } else {
                        reject(JSON.parse(xhr.response));
                    }
                }
            }
            xhr.open("POST", url, true);
            xhr.send(formData);
        });
    }
As you can see, I have added productId and description as part of the request paramters.

Those parameters now will be available as part of the incoming request in the web api.


Web API Modified code

We can now get the additional parameters by adding this to our api method:

int productId = int.Parse(HttpContext.Current.Request.Params.Get("productId"));
string description = HttpContext.Current.Request.Params.Get("description")
The full code will now look like this:
        [HttpPost]
        public HttpResponseMessage UploadImage()
        {
            var exMessage = string.Empty;
            try
            {
                string uploadPath = "~/content/upload";
                HttpPostedFile file = null;
                if (HttpContext.Current.Request.Files.Count > 0)
                {
                    file = HttpContext.Current.Request.Files.Get("file");
                }
                // Check if we have a file
                if (null == file)
                    return Request.CreateResponse(HttpStatusCode.BadRequest, new
                    {
                        error = true,
                        message = "Image file not found"
                    });

                // Make sure the file has content
                if (!(file.ContentLength > 0))
                    return Request.CreateResponse(HttpStatusCode.BadRequest, new
                    {
                        error = true,
                        message = "Image file not found"
                    });

                int productId = int.Parse(HttpContext.Current.Request.Params.Get("productId"));
                string description = HttpContext.Current.Request.Params.Get("description")

                if (!Directory.Exists(HttpContext.Current.Server.MapPath(uploadPath)))
                {
                    // If it doesn't exist, create the directory
                    Directory.CreateDirectory(HttpContext.Current.Server.MapPath(uploadPath));
                }

                //Upload File
                file.SaveAs(HttpContext.Current.Server.MapPath($"{uploadPath}/{file.FileName}"));

            }
            catch (Exception ex)
            {
                exMessage = ex.Message;
            }
            return Request.CreateResponse(HttpStatusCode.BadRequest, new { error = true, message = exMessage == string.Empty ? "An unknown error occured" : exMessage });
        }

That is all we have to do. Let us know if you have a better way of doing this. I hope this helps. Thanks for your time.

No comments:

Powered by Blogger.