// 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.Threading.Tasks; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc.Internal; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Net.Http.Headers; namespace Microsoft.AspNetCore.Mvc { /// /// Represents an that when executed will /// write a file as the response. /// public abstract class FileResult : ActionResult { private string _fileDownloadName; /// /// Creates a new instance with /// the provided . /// /// The Content-Type header of the response. protected FileResult(string contentType) { if (contentType == null) { throw new ArgumentNullException(nameof(contentType)); } ContentType = contentType; } /// /// Gets the Content-Type header for the response. /// public string ContentType { get; } /// /// Gets the file name that will be used in the Content-Disposition header of the response. /// public string FileDownloadName { get { return _fileDownloadName ?? string.Empty; } set { _fileDownloadName = value; } } /// public override Task ExecuteResultAsync(ActionContext context) { if (context == null) { throw new ArgumentNullException(nameof(context)); } var loggerFactory = context.HttpContext.RequestServices.GetRequiredService(); var logger = loggerFactory.CreateLogger(); var response = context.HttpContext.Response; response.ContentType = ContentType.ToString(); if (!string.IsNullOrEmpty(FileDownloadName)) { // From RFC 2183, Sec. 2.3: // The sender may want to suggest a filename to be used if the entity is // detached and stored in a separate file. If the receiving MUA writes // the entity to a file, the suggested filename should be used as a // basis for the actual filename, where possible. var contentDisposition = new ContentDispositionHeaderValue("attachment"); contentDisposition.SetHttpFileName(FileDownloadName); context.HttpContext.Response.Headers[HeaderNames.ContentDisposition] = contentDisposition.ToString(); } logger.FileResultExecuting(FileDownloadName); return WriteFileAsync(response); } /// /// Writes the file to the specified . /// /// The . /// /// A that will complete when the file has been written to the response. /// protected abstract Task WriteFileAsync(HttpResponse response); } }