C# Сохранение нескольких файлов на сервере в потоковой передаче

Рейтинг: 1Ответов: 1Опубликовано: 26.06.2023

Подскажите как я могу сделать чтобы в рамках одного запроса через httpclient я мог передать составной запрос из нескольких файлов в потоке. Сейчас я могу передать в потоке один файл и сохранить его на сервере.

Код для отправки файла со стороны клиента

public async Task SendFile(string filePath, string url)
        {
            using (FileStream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read))
            {
                using (HttpClient client = new HttpClient())
                {
                    client.Timeout = TimeSpan.FromMinutes(10);
                    // Создаем объект MultipartFormDataContent для передачи файла
                    using (MultipartFormDataContent content = new MultipartFormDataContent())
                    {
                        // Создаем объект StreamContent для передачи содержимого файла
                        using (StreamContent fileContent = new StreamContent(fileStream))
                        {
                            client.DefaultRequestHeaders.Add("Token", "1234");
                            content.Add(fileContent, "file", System.IO.Path.GetFileName(filePath));

                            // Отправляем запрос на сервер с помощью метода HTTP POST
                            HttpResponseMessage response = await client.PostAsync(url, content);

                            // Получаем ответ от сервера и проверяем его статусный код
                            if (response.IsSuccessStatusCode)
                            {
                                Console.WriteLine("Файл успешно передан.");
                            }
                            else
                            {
                                Console.WriteLine("Произошла ошибка при передаче файла.");
                            }
                        }
                    }
                }
            }
        }

Код для сохранения файла с потока

 [HttpPost("/uploadfile")]
        //[DisableRequestSizeLimit]
        [RequestSizeLimit((long)1e+10)]
        [RequestFormLimits(MultipartBodyLengthLimit = (long)1e+10)]
        public async Task<IActionResult> UploadFile()
        {
            if (!Request.HasFormContentType || !MediaTypeHeaderValue.TryParse(Request.ContentType, out var mediaTypeHeader) || string.IsNullOrEmpty(mediaTypeHeader.MediaType))
                return new UnsupportedMediaTypeResult();
            Stopwatch stopwatch = Stopwatch.StartNew();
            using var fileStream = new FileStream("test.rar", FileMode.Create);
            var buffer = new byte[1024 * 50];
            int bytesRead;
            while ((bytesRead = await Request.Body.ReadAsync(buffer, 0, buffer.Length)) > 0)
            {
                await fileStream.WriteAsync(buffer, 0, bytesRead);
            }
            stopwatch.Stop();
            Console.WriteLine($"Время работы сохранения файла: {stopwatch.ElapsedMilliseconds}");
            return Ok();
        }

Ответы

▲ 1

Может кому пригодится, сохранение нескольких файлов в потоковой передаче, также можно чередавать с json запрос и т.п. Статья на данную тему https://learn.microsoft.com/en-us/aspnet/core/mvc/models/file-uploads?view=aspnetcore-7.0

Код контролера

public class FileController : Controller
    {
        const long _RequestSizeLimit = (long)1e+10;
        [HttpPost("/uploadfile")]
        [RequestSizeLimit(_RequestSizeLimit)]
        [RequestFormLimits(MultipartBodyLengthLimit = _RequestSizeLimit)]
        public async Task<IActionResult> UploadPhysical()
        {
            if (!IsMultipartContentType(Request.ContentType))
                return BadRequest("File\",\r\n\"The request couldn't be processed (Error 1).");

            var boundary = GetBoundary(Microsoft.Net.Http.Headers.MediaTypeHeaderValue.Parse(Request.ContentType));
            var reader = new MultipartReader(boundary, HttpContext.Request.Body);
            var section = await reader.ReadNextSectionAsync();

            while (section != null)
            {
                var hasContentDispositionHeader = System.Net.Http.Headers.ContentDispositionHeaderValue.TryParse(section.ContentDisposition, out var contentDisposition);
                if (hasContentDispositionHeader)
                {
                    if (HasFileContentDisposition(contentDisposition))
                        await ProcessStreamedFile(section, contentDisposition);
                    if (HasJsonContentDisposition(contentDisposition, section))
                    { 
                        var json = await section.ReadAsStringAsync();
                        var example = await JsonSerializer.DeserializeAsync<MyObject>(json);
                    }
                }
                section = await reader.ReadNextSectionAsync();
            }
            return Ok();
        }
        string GetBoundary(Microsoft.Net.Http.Headers.MediaTypeHeaderValue contentType) => HeaderUtilities.RemoveQuotes(contentType.Boundary).Value;
        bool IsMultipartContentType(string contentType) => !string.IsNullOrEmpty(contentType) && contentType.IndexOf("multipart/", StringComparison.OrdinalIgnoreCase) >= 0;
        /// <summary>
        /// Проверка на наличие файла в потоке
        /// </summary>
        /// <param name="contentDisposition"></param>
        /// <returns></returns>
        bool HasFileContentDisposition(System.Net.Http.Headers.ContentDispositionHeaderValue contentDisposition)
        {
            // Content-Disposition: form-data; name="myfile1"; filename="Misc 002.jpg"
            return contentDisposition != null
                && contentDisposition.DispositionType.Equals("form-data")
                && (!string.IsNullOrEmpty(contentDisposition.FileName)
                    || !string.IsNullOrEmpty(contentDisposition.FileNameStar));
        }
        /// <summary>
        /// Проверка является на Json
        /// </summary>
        /// <param name="contentDisposition"></param>
        /// <param name="section"></param>
        /// <returns></returns>
        bool HasJsonContentDisposition(System.Net.Http.Headers.ContentDispositionHeaderValue contentDisposition, MultipartSection section)
        {
            return contentDisposition != null && contentDisposition.DispositionType.Equals("form-data") 
                && section.ContentType != null
                && section.ContentType.Contains("application/json");
        }
        /// <summary>
        /// Запись файла с удалением запрещенных символов из пути, в contentDisposition.FileName могут присутствовать кавычки 
        /// </summary>
        /// <param name="section"></param>
        /// <param name="contentDisposition"></param>
        /// <returns></returns>
        async Task ProcessStreamedFile(MultipartSection section, System.Net.Http.Headers.ContentDispositionHeaderValue contentDisposition)
        {
            string fileName = contentDisposition.FileName;
            string invalidChars = new string(Path.GetInvalidFileNameChars());
            fileName = new string(fileName.Where(c => !invalidChars.Contains(c)).ToArray());
            using (var memoryStream = new FileStream(fileName, FileMode.Create))
                await section.Body.CopyToAsync(memoryStream, 1024 * 50);
        }
    }

Код для отправки данных на стороне клиента

public async Task SendFiles(List<string> filePaths, string url)
        {
            using (HttpClient client = new HttpClient())
            {
                client.Timeout = TimeSpan.FromMinutes(10);
                client.DefaultRequestHeaders.Add("Token", "1234");

                // Создаем объект MultipartFormDataContent для передачи файлов
                using (MultipartFormDataContent content = new MultipartFormDataContent())
                {
                    var json = new StringContent("\"key\": \"Test\"", Encoding.UTF8, "application/json");
                    content.Add(json, "\"json\"");
                    foreach (var filePath in filePaths)
                    {
                        var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read);
                        var fileContent = new StreamContent(fileStream);
                        content.Add(fileContent, "files", System.IO.Path.GetFileName(filePath));
                    }

                    // Отправляем потоковый запрос на сервер с помощью метода HTTP POST
                    HttpResponseMessage response = await client.PostAsync(url, content);

                    // Получаем ответ от сервера и проверяем его статусный код
                    if (response.IsSuccessStatusCode)
                    {
                        Console.WriteLine($"{filePaths.Count} files have been sent successfully.");
                    }
                    else
                    {
                        Console.WriteLine("An error occurred while sending files.");
                    }
                }
            }
        }