// Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.IO; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.Mvc.Core; using Microsoft.Net.Http.Headers; namespace Microsoft.AspNetCore.Mvc { /// /// A on execution will write a file from disk to the response /// using mechanisms provided by the host. /// public class PhysicalFileResult : FileResult { private const int DefaultBufferSize = 0x1000; private string _fileName; /// /// Creates a new instance with /// the provided and the provided . /// /// The path to the file. The path must be an absolute path. /// The Content-Type header of the response. public PhysicalFileResult(string fileName, string contentType) : this(fileName, MediaTypeHeaderValue.Parse(contentType)) { if (fileName == null) { throw new ArgumentNullException(nameof(fileName)); } } /// /// Creates a new instance with /// the provided and the provided . /// /// The path to the file. The path must be an absolute path. /// The Content-Type header of the response. public PhysicalFileResult(string fileName, MediaTypeHeaderValue contentType) : base(contentType?.ToString()) { if (fileName == null) { throw new ArgumentNullException(nameof(fileName)); } FileName = fileName; } /// /// Gets or sets the path to the file that will be sent back as the response. /// public string FileName { get { return _fileName; } set { if (value == null) { throw new ArgumentNullException(nameof(value)); } _fileName = value; } } /// protected override async Task WriteFileAsync(HttpResponse response) { if (!Path.IsPathRooted(FileName)) { throw new NotSupportedException(Resources.FormatFileResult_PathNotRooted(FileName)); } var sendFile = response.HttpContext.Features.Get(); if (sendFile != null) { await sendFile.SendFileAsync( FileName, offset: 0, count: null, cancellation: default(CancellationToken)); } else { var fileStream = GetFileStream(FileName); using (fileStream) { await fileStream.CopyToAsync(response.Body, DefaultBufferSize); } } } /// /// Returns for the specified . /// /// The path for which the is needed. /// for the specified . protected virtual Stream GetFileStream(string path) { if (path == null) { throw new ArgumentNullException(nameof(path)); } return new FileStream( path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, DefaultBufferSize, FileOptions.Asynchronous | FileOptions.SequentialScan); } } }