Reputation: 587
I'm able to stream a PDF at a remote URI using the below code:
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("");
}
It creates a PDF file starting with a name of 'LoadPdfStream' at the temp inet location. How can I prevent it from creating a temp file. I just want to stream the PDF content on the browser window without having the app to save it as a temp file.
Thanks in advance!!!
Upvotes: 0
Views: 1626
Reputation: 240
Looks like this has nothing to do with MVC at all. It must your component/code converting PDF that creates temp file. Try to remove any response writing logic or just step with debug and stop it after ConvertPdfToStream()
call and I'm pretty sure you'll still see file created already.
But much better would be rewriting your code to work better with MVC architecture. Now you: 1. Explicitly set response data 2. Flush the response stream, close the response 3. And still return the new Content("") object to be handled by MVC routine. That`s weird and pretty unpredictable. In our WebApi (near same as MVC) project we're using something like this to send files (simplified and modified hardly to match your sample):
/// <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;
}
}
and then use it in you controller like this:
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);
}
This way you don`t need to take care about response flush and manually force request end. Also this streaming code is called only in case if client really waits for it and cancelled nicely on client stream close/request abort.
Upvotes: 1