// 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.AspNet.FileProviders; using Microsoft.AspNet.Hosting; using Microsoft.AspNet.Http; using Microsoft.AspNet.Http.Features; using Microsoft.AspNet.Mvc.Core; using Microsoft.Framework.DependencyInjection; using Microsoft.Framework.Internal; using Microsoft.Net.Http.Headers; namespace Microsoft.AspNet.Mvc { /// /// A that on execution writes the file specified using a virtual path to the response /// using mechanisms provided by the host. /// public class VirtualFileProviderResult : 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 relative/virtual. /// The Content-Type header of the response. public VirtualFileProviderResult([NotNull] string fileName, [NotNull] string contentType) : this(fileName, new MediaTypeHeaderValue(contentType)) { } /// /// Creates a new instance with /// the provided and the /// provided . /// /// The path to the file. The path must be relative/virtual. /// The Content-Type header of the response. public VirtualFileProviderResult([NotNull] string fileName, [NotNull] MediaTypeHeaderValue contentType) : base(contentType) { FileName = fileName; } /// /// Gets or sets the path to the file that will be sent back as the response. /// public string FileName { get { return _fileName; } [param: NotNull] set { _fileName = value; } } /// /// Gets or sets the used to resolve paths. /// public IFileProvider FileProvider { get; set; } /// protected override async Task WriteFileAsync(HttpResponse response, CancellationToken cancellation) { var fileProvider = GetFileProvider(response.HttpContext.RequestServices); var normalizedPath = FileName; if (normalizedPath.StartsWith("~")) { normalizedPath = normalizedPath.Substring(1); } var fileInfo = fileProvider.GetFileInfo(normalizedPath); if (fileInfo.Exists) { var physicalPath = fileInfo.PhysicalPath; var sendFile = response.HttpContext.Features.Get(); if (sendFile != null && !string.IsNullOrEmpty(physicalPath)) { await sendFile.SendFileAsync( physicalPath, offset: 0, length: null, cancellation: cancellation); return; } else { var fileStream = GetFileStream(fileInfo); using (fileStream) { await fileStream.CopyToAsync(response.Body, DefaultBufferSize, cancellation); } return; } } throw new FileNotFoundException( Resources.FormatFileResult_InvalidPath(FileName), FileName); } /// /// Returns for the specified . /// /// The for which the stream is needed. /// for the specified . protected virtual Stream GetFileStream([NotNull]IFileInfo fileInfo) { return fileInfo.CreateReadStream(); } private IFileProvider GetFileProvider(IServiceProvider requestServices) { if (FileProvider != null) { return FileProvider; } var hostingEnvironment = requestServices.GetService(); FileProvider = hostingEnvironment.WebRootFileProvider; return FileProvider; } } }