Как я могу выполнять потоковую передачу PDF-файла ASP.NET MVC, не сохраняя его во временной папке?

Я могу передавать PDF-файл на удаленный URI, используя следующий код:

    public ActionResult LoadPdfStream(string url)
    {
        // this gets me the memory stream from the PDF file
        MemoryStream memBuffer = _pdfViewerLogic.ConvertPdfToStream(url);

        byte[] bytes = memBuffer.GetBuffer();

        Response.ClearContent();
        Response.ContentType = "application/pdf";
        Response.AddHeader("Content-Disposition", "inline");
        Response.AddHeader("Content-Length", bytes.Length.ToString());
        foreach(byte b in bytes)
        { Response.OutputStream.WriteByte(b); }

        Response.Flush();
        Response.Clear();
        Response.Close();

        HttpContext.ApplicationInstance.CompleteRequest();

        return Content("");
    }

Он создает файл PDF, начинающийся с имени «LoadPdfStream» во временной папке в сети. Как я могу предотвратить создание временного файла. Я просто хочу транслировать содержимое PDF в окне браузера, не имея приложения для сохранения его в виде временного файла.

Заранее спасибо!!!


person Anshuman    schedule 28.08.2015    source источник
comment
Вы пробовали это, удалив заголовок Content-Disposition?   -  person Eser    schedule 28.08.2015
comment
да. Даже комментирование Content-Disposition создает файлы во временной папке.   -  person Anshuman    schedule 28.08.2015


Ответы (1)


Похоже, это вообще не имеет ничего общего с MVC. Это должен быть ваш компонент/код, конвертирующий PDF, который создает временный файл. Попробуйте удалить любую логику написания ответа или просто выполните отладку и остановите ее после вызова ConvertPdfToStream(), и я почти уверен, что вы все равно увидите уже созданный файл.

Но гораздо лучше было бы переписать свой код, чтобы он лучше работал с архитектурой MVC. Теперь вы: 1. Явно задаете данные ответа 2. Сбрасываете поток ответов, закрываете ответ 3. И по-прежнему возвращаете новый объект Content("") для обработки подпрограммой MVC. Это странно и довольно непредсказуемо. В нашем проекте WebApi (почти так же, как MVC) мы используем что-то подобное для отправки файлов (упрощенное и модифицированное, чтобы почти не соответствовать вашему образцу):

/// <summary>
/// Custom <see cref="IHttpActionResult"/> that sends files using <see cref="StreamContent"/>
/// </summary>
public class FileResult : IHttpActionResult
{
    ILogger Log = LogManager.GetLogger();

    /// <summary>
    /// Write buffer size. We use it for our internal services so 8MB buffer size - is the size tested and approved to be fine for our 1Gbps LAN transfers ;) you might want to change it
    /// </summary>
    private const int BUFFER_SIZE = 8388608;

    /// <summary>
    /// Initializer
    /// </summary>
    /// <param name="data">File data</param>
    public FileResult(byte[] data)
    {
        Data = data;
    }

    /// <summary>
    /// File data
    /// </summary>
    public byte[] Data
    { get; private set; }


    /// <inheritdoc cref="IHttpActionResult.ExecuteAsync(CancellationToken)"/>
    public async Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
    {

        var response = new HttpResponseMessage();
        response.Content = new PushStreamContent(async (responseStream, content, context) =>
            {
                using (var source = new MemoryStream(Data))
                {
                    try
                    {
                        if (source != null)
                            await source.CopyToAsync(responseStream, BUFFER_SIZE, cancellationToken);
                    }
                    catch (Exception e)
                    {
                        if (cancellationToken.IsCancellationRequested)
                            Log.Info("Data stream read operation aborted by client.");
                        else
                        {
                            Log.Warn(e);
                            throw;
                        }
                    }
                    responseStream.Close();
                }
            },
            new MediaTypeHeaderValue("application/pdf"));

        response.Content.Headers.ContentLength = Data.Length;
        response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
        {
            FileName = "file.pdf",
            Size = Data.Length,
        };

        return response;
    }
}

а затем используйте его в своем контроллере следующим образом:

public IHttpActionResult LoadPdfStream(string url)
{
    // this gets me the memory stream from the PDF file
    MemoryStream memBuffer = _pdfViewerLogic.ConvertPdfToStream(url);

    byte[] bytes = memBuffer.GetBuffer();

    return new FileResult(bytes);
}

Таким образом, вам не нужно заботиться о сбросе ответа и вручную принудительно завершать запрос. Также этот код потоковой передачи вызывается только в том случае, если клиент действительно ждет его и хорошо отменяется при закрытии/запросе прерывания клиентского потока.

person justmara    schedule 28.08.2015
comment
Нет, кажется, файл создается после оператора Response.Flush(). - person Anshuman; 30.08.2015