Отправка нескольких файлов в одном запросе к API

Я довольно новичок в API. Я пишу «простой» API, который будет преобразовывать файлы .docx в файлы .pdf и возвращать pdf обратно клиенту для сохранения. У меня есть код, работающий с одним файлом, но я хотел закодировать API для обработки нескольких файлов в одном запросе. Теперь API не получает запрос. По запросу могу предоставить рабочий код одним файлом.

Я уверен, что упускаю что-то простое. Пожалуйста, смотрите ниже и посмотрите, видит ли кто-нибудь что-то, что я мог бы сделать лучше, или почему API не получает запрос POST.

Клиент:

        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: запрос не получен, поэтому эта функция не завершена. Мне нужно выяснить, почему он не попал.

        [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;
        }

Модель простого ответа:

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

ОБНОВЛЯТЬ

Были ли предложения, сделанные @jdweng, и я получаю нулевой ответ на API POST

Клиент:

        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
                {

                }
            }
        }

Сервер:

        [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;
        }

Вам нужно отправить запрос mime. Вложения пантомимы начинаются с двух тире (строка заголовка), за которыми следует возврат каретки. См.: stackoverflow.com/questions/23289602/…

jdweng 22.12.2020 16:21

@jdweng - я попробовал ваше предложение, но API все еще не получает почтовый запрос.

Michael Brown 22.12.2020 21:12

Вы получаете какие-либо ошибки?

jdweng 23.12.2020 02:22

@jdweng Никаких ошибок вообще

Michael Brown 04.01.2021 15:22

Код подчеркивания использует XmlSerialization. по умолчанию при использовании массива/списка библиотека Net генерирует два тега xml, например <SimpleResponses><<SimpleResponse></SimpleResponse><SimpleRe‌​sponse></SimpleRespo‌​nse><SimpleResponse>‌​</SimpleResponse ></S‌​impleResponses>. Итак, вам нужно добавить еще один класс в С#, чтобы у вас было два класса SimpleResponses и SimpleResponse.

jdweng 04.01.2021 18:32

@jdweng У клиента и сервера есть класс SimpleResponse.

Michael Brown 04.01.2021 18:54

Сетевая библиотека не поддерживает сериализацию XML, если корневой тег представляет собой список. Я думаю, что простым решением является создание класса С# для SimpleResponses, а затем добавление одного свойства, которое представляет собой List<SimpleResponse>.

jdweng 04.01.2021 19:03

@jdweng - Итак, вы говорите, что создаете класс SimpleResponses, в котором просто есть List<SimpleResponse>?

Michael Brown 04.01.2021 19:17

Точно. Затем отправьте SimpleResponses как Post/Response.

jdweng 04.01.2021 19:47

@jdweng - Все еще не работает функция Server Post.

Michael Brown 04.01.2021 22:28

Можете ли вы вернуться к тому времени, когда он работал без списка? Не должно быть никакой разницы между тем, что работало, и тем, что у вас есть сейчас, за исключением того, что раньше у вас был SimpleResponse в качестве корня, а теперь у вас есть SimpleResponses в качестве корня.

jdweng 04.01.2021 23:47

@jdweng - функция публикации в the4 API получает запрос, но запрос недействителен.

Michael Brown 05.01.2021 19:08

Похоже, JSON десериализуется. Массив не нравится. Вам нужно захватить строку JSON и Post. Я не настолько хорошо разбираюсь в проблемах с массивом JSON.

jdweng 05.01.2021 19:53
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
13
1 327
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Я, наконец, решил проблемы и теперь могу успешно отправлять несколько файлов .docx в API и получать файлы .pdf обратно из API. Теперь я хочу выяснить, как отправлять каждый файл в отдельный поток, а не все вместе.

Клиент:

        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;
        }

Другие вопросы по теме