Warm tip: This article is reproduced from serverfault.com, please click

Sending Multiple Files in a single Request to API

发布于 2020-12-22 14:27:41

I am fairly new to API's. I am writing a "simple" API that will convert .docx files to .pdf files and return the pdf's back to the client for saving. I have the code working for a single file but I wanted to code the API to handle multiple files in a single request. Now the API is not receiving the request. I can provide the working code with a single file if requested.

I am sure I am missing something simple. Please see below and see if anyone see's something that I could be doing better or why the API is not receiving the POST request.

Client:

        List<string> documents = new List<string>();

        private async void btnConvert_Click(object sender, EventArgs e)
        {
            using (var client = new HttpClient(new HttpClientHandler() { UseDefaultCredentials = true }))
            {
                client.BaseAddress = new Uri(BaseApiUrl);
                //client.DefaultRequestHeaders.Add("Accept", "application/json");

                // Add an Accept header for JSON format.    
                client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
                HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, BaseApiUrl + ApiUrl);

                foreach (string s in docPaths)
                {
                    byte[] bte;
                    bte = File.ReadAllBytes(docPath);

                    string data = JsonConvert.SerializeObject(Convert.ToBase64String(bte));
                    documents.Add(data);                    
                }

                using (var formData = new MultipartFormDataContent())
                {
                    foreach (string s in documents)
                    {
                        //add content to form data
                        formData.Add(new StringContent(s, Encoding.UTF8, "application/json"));
                    }

                    // List of Http Reponse Messages
                    var conversions = documents.Select(doc => client.PostAsync(BaseApiUrl + ApiUrl, formData)).ToList();

                    //Wait for all the requests to finish
                    await Task.WhenAll(conversions);

                    //Get the responses
                    var responses = conversions.Select
                        (
                            task => task.Result
                        );

                    foreach (var r in responses)
                    {
                        // Extract the message body
                        var s = await r.Content.ReadAsStringAsync();
                        SimpleResponse res = JsonConvert.DeserializeObject<SimpleResponse>(s);

                        if (res.Success)
                        {
                            byte[] pdf = Convert.FromBase64String(res.Result.ToString());

                            // Save the PDF here
                        }
                        else
                        {
                           // Log issue
                        }
                    }
                }
            }

API: This is not getting the request so this function is not complete. I need to figure out why it not being hit.

        [HttpPost]
        public async Task<List<SimpleResponse>> Post([FromBody]string request)
        {
            var response = new List<SimpleResponse>();
            Converter convert = new Converter();

            var provider = new MultipartMemoryStreamProvider();
            await Request.Content.ReadAsMultipartAsync(provider);
            foreach (var requestContents in provider.Contents)
            {
                try
                {
                    //var result = convert.CovertDocToPDF(requestContents, WebConfigurationManager.AppSettings["tempDocPath"], WebConfigurationManager.AppSettings["tempPdfPath"]);

                    //response.Add(new SimpleResponse() { Result = result, Success = true });
                }
                catch (Exception ex)
                {
                    response.Add(new SimpleResponse() { Success = false, Exception = ex, Errors = new List<string>() { string.Format("{0}, {1}", ex.Message, ex.InnerException?.Message ?? "") } });
                }
            }

            return response;
        }

SimpleResponse Model:

    public class SimpleResponse
    {
        public object Result { get; set; }
        public bool Success { get; set; }
        public Exception Exception { get; set; }
        public List<string> Errors { get; set; }
    }

UPDATE

Did suggestions made by @jdweng and I am getting a null response on the API POST

Client:

        public async void btnConvert_Click(object sender, EventArgs e)
        {
            using (var client = new HttpClient(new HttpClientHandler() { UseDefaultCredentials = true }))
            {
                client.BaseAddress = new Uri(BaseApiUrl);
                client.DefaultRequestHeaders.Add("Accept", "application/json");

                // Add an Accept header for JSON format.    
                client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));//application/json
                HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, BaseApiUrl + ApiUrl);

                List<string> requests = new List<string>();
                byte[] bte;

                // New Code per the suggestion
                foreach (string s in docPaths)
                {
                     bte = File.ReadAllBytes(s);

                    requests.Add(Convert.ToBase64String(bte));
                }
                // End new code

                string data = JsonConvert.SerializeObject(requests);

                request.Content = new StringContent(data, Encoding.UTF8, "application/json");

                HttpResponseMessage response1 = client.PostAsync(BaseApiUrl + ApiUrl, request.Content).Result;
                Task<string> json = response1.Content.ReadAsStringAsync();

                SimpleResponse response = JsonConvert.DeserializeObject<SimpleResponse>(json.Result);
                //result = JsonConvert.DeserializeObject(result).ToString();

                if (response.Success)
                {
                    bte = Convert.FromBase64String(response.Result.ToString());

                    if (File.Exists(tempPdfPath))
                    {
                        File.Delete(tempPdfPath);
                    }
                    System.IO.File.WriteAllBytes(tempPdfPath, bte);
                }
                else
                {

                }
            }
        }

Server:

        [HttpPost]
        public async Task<List<SimpleResponse>> Post([FromBody]string request)
        {
            // The request in NULL....

            List<SimpleResponse> responses = new List<SimpleResponse>();

            List<string> resp = JsonConvert.DeserializeObject(request) as List<string>;
            try
            {
                Converter convert = new Converter();

                foreach (string s in resp)
                {
                    var result = convert.CovertDocToPDF(request, WebConfigurationManager.AppSettings["tempDocPath"], WebConfigurationManager.AppSettings["tempPdfPath"]);

                    responses.Add(new SimpleResponse()
                    {
                        Result = result,
                        Success = true
                    });
                }

            }
            catch (Exception ex)
            {
                responses.Add(new SimpleResponse()
                {
                    Result = null,
                    Success = true,
                    Exception = ex,
                    Errors = new List<string>() { string.Format("{0}, {1}", ex.Message, ex.InnerException?.Message ?? "") }
                });
            }

            return responses;
        }

Questioner
Michael Brown
Viewed
0
Michael Brown 2021-01-06 23:13:32

I have finally solved the issues and can now successfully send multiple .docx files to the API and get the .pdf files back from the API. Now I want to figure out how to send each files on it's own thread instead of all together.

Client:

        public async void btnConvert_Click(object sender, EventArgs e)
        {
            using (var client = new HttpClient(new HttpClientHandler() { UseDefaultCredentials = true }))
            {
                client.BaseAddress = new Uri(BaseApiUrl);
                client.DefaultRequestHeaders.Add("Accept", "application/json");

                // Add an Accept header for JSON format.    
                client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
                HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, BaseApiUrl + ApiUrl);

                List<string> requests = new List<string>();
                byte[] bte;
                foreach (string s in docPaths)
                {
                     bte = File.ReadAllBytes(s);

                    requests.Add(Convert.ToBase64String(bte));
                }

                var data = JsonConvert.SerializeObject(requests);

                request.Content = new StringContent(data, Encoding.UTF8, "application/json");

                HttpResponseMessage response1 = await client.PostAsync(BaseApiUrl + ApiUrl, request.Content);
                Task<string> json = response1.Content.ReadAsStringAsync();

                var response = JsonConvert.DeserializeObject<List<SimpleResponse>>(json.Result);

                foreach (SimpleResponse sr in response)
                {
                    if (sr.Success)
                    {
                        bte = Convert.FromBase64String(sr.Result.ToString());

                        string rs = RandomString(16, true);
                        string pdfFileName = tempPdfPath + rs + ".pdf";
                        
                        if (File.Exists(pdfFileName))
                        {
                            File.Delete(pdfFileName);
                        }
                        System.IO.File.WriteAllBytes(pdfFileName, bte);
                    }
                    else
                    {
                    }
                }
            }
        }

API:

        [HttpPost]
        public async Task<List<SimpleResponse>> Post([FromBody] List<string> request)
        {
            List<SimpleResponse> responses = new List<SimpleResponse>();

            try
            {
                Converter convert = new Converter();

                foreach (string s in request)
                {
                    var result = convert.CovertDocToPDF(s, WebConfigurationManager.AppSettings["tempDocPath"], WebConfigurationManager.AppSettings["tempPdfPath"]);

                    responses.Add(new SimpleResponse()
                    {
                        Result = result,
                        Success = true
                    });
                }
            }
            catch (Exception ex)
            {
                responses.Add(new SimpleResponse()
                {
                    Result = null,
                    Success = true,
                    Exception = ex,
                    Errors = new List<string>() { string.Format("{0}, {1}", ex.Message, ex.InnerException?.Message ?? "") }
                });
            }

            return responses;
        }