загрузка файлов веб-API частями с сервера SQL - PullRequest
0 голосов
/ 30 августа 2018

Я хочу скачать файл из Sqlserver в чанках и отправить его моему клиенту, используя pushstreamcontent или streamcontent из моего веб-API. Какой правильный подход для достижения этой цели?

У меня в голове два подхода

  1. Несколько вызовов: вызов WEB API с клиента и получение метаданных файла при первом вызове. Передайте параметры Chunksize и Contentstart и загрузите порции.
  2. Single Call: загрузка файла в Tempfolder на стороне сервера и передача потокового контента клиенту за один вызов.

1 Ответ

0 голосов
/ 31 августа 2018

Я верю, что это поможет вам:

public HttpResponseMessage Get([FromUri]string filename)
        {
            string path = HttpContext.Current.Server.MapPath("~/" + filename);
            if (!File.Exists(path))
            {
                throw new HttpResponseException("The file does not exist.", HttpStatusCode.NotFound);
            }

            try
            {
                MemoryStream responseStream = new MemoryStream();
                Stream fileStream = File.Open(path, FileMode.Open);
                bool fullContent = true;
                if (this.Request.Headers.Range != null)
                {
                    fullContent = false;

                    // Currently we only support a single range.
                    RangeItemHeaderValue range = this.Request.Headers.Range.Ranges.First();


                    // From specified, so seek to the requested position.
                    if (range.From != null)
                    {
                        fileStream.Seek(range.From.Value, SeekOrigin.Begin);

                        // In this case, actually the complete file will be returned.
                        if (range.From == 0 && (range.To == null || range.To >= fileStream.Length))
                        {
                            fileStream.CopyTo(responseStream);
                            fullContent = true;
                        }
                    }
                    if (range.To != null)
                    {
                        // 10-20, return the range.
                        if (range.From != null)
                        {
                            long? rangeLength = range.To - range.From;
                            int length = (int)Math.Min(rangeLength.Value, fileStream.Length - range.From.Value);
                            byte[] buffer = new byte[length];
                            fileStream.Read(buffer, 0, length);
                            responseStream.Write(buffer, 0, length);
                        }
                        // -20, return the bytes from beginning to the specified value.
                        else
                        {
                            int length = (int)Math.Min(range.To.Value, fileStream.Length);
                            byte[] buffer = new byte[length];
                            fileStream.Read(buffer, 0, length);
                            responseStream.Write(buffer, 0, length);
                        }
                    }
                    // No Range.To
                    else
                    {
                        // 10-, return from the specified value to the end of file.
                        if (range.From != null)
                        {
                            if (range.From < fileStream.Length)
                            {
                                int length = (int)(fileStream.Length - range.From.Value);
                                byte[] buffer = new byte[length];
                                fileStream.Read(buffer, 0, length);
                                responseStream.Write(buffer, 0, length);
                            }
                        }
                    }
                }
                // No Range header. Return the complete file.
                else
                {
                    fileStream.CopyTo(responseStream);
                }
                fileStream.Close();
                responseStream.Position = 0;

                HttpResponseMessage response = new HttpResponseMessage();
                response.StatusCode = fullContent ? HttpStatusCode.OK : HttpStatusCode.PartialContent;
                response.Content = new StreamContent(responseStream);
                return response;
            }
            catch (IOException)
            {
                throw new HttpResponseException("A generic error occured. Please try again later.", HttpStatusCode.InternalServerError);
            }
        }

Обратите внимание, что при использовании Web API вам не нужно вручную анализировать заголовок Range в виде текста. Веб-API автоматически анализирует его и предоставляет свойства From и To для каждого диапазона. Тип From и To является Nullable, так как эти свойства могут быть нулевыми (например, bytes = -100 и bytes = 300-). Эти особые случаи должны быть обработаны осторожно.

Другой особый случай, который следует рассмотреть, - это где To больше, чем размер ресурса. В этом случае это эквивалентно To is null, где вам нужно вернуть, начиная с From, до конца ресурса. Если полный ресурс возвращается, обычно код состояния устанавливается на 200 OK. Если возвращается только часть ресурса, обычно код состояния устанавливается равным 206. PartialContent.

Это решение является частью статьи, которая охватывает множество других вещей, и я призываю вас проверить это: https://blogs.msdn.microsoft.com/codefx/2012/02/23/more-about-rest-file-upload-download-service-with-asp-net-web-api-and-windows-phone-background-file-transfer/

...