Содержание
Современные web-приложения активно используют в своей работе разного рода статические файлы, например, файлы css, js, html и другие. Кроме этого, web-приложения могут как получать файлы от пользователей, так и наоборот — отправлять какие-либо данные в виде файлов пользователю. В ASP.NET Core имеются как стандартные компоненты middleware для работы со статическими файлами, так и отдельные методы, определенные в классе HttpResponse
предназначенные для этих целей. Сегодня мы рассмотрим метод HttpResponse.SendFileAsync
для работы со статическими файлами в ASP.NET Core.
Отправка файлов клиенту
Метод SendFileAsync()
имеет ряд перегруженных версий. Для начала, воспользуемся наиболее простой из них, которая имеет следующий вид:
public static Task SendFileAsync(this HttpResponse response, string fileName, CancellationToken cancellationToken = default)
fileName
— путь к отправляемому файлу. Может указываться как полный путь, так и относительны (относительно папки приложения).
Допустим, нам необходимо отправить пользователю файл «c:\temp\wow.jpeg». Напишем следующий исходный код приложения:
public class Program { public static void Main(string[] args) { var builder = WebApplication.CreateBuilder(args); var app = builder.Build(); app.Run(async context => { await context.Response.SendFileAsync(@"c:\temp\wow.jpeg"); }); app.Run(); } }
Теперь запустим приложение и увидим:
ASP.NET Core по умолчанию пытается открыть файл в браузере, поэтому сразу после запуска мы видим отправленную сервером картинку. Что касается указания относительного пути к файлу, то продемонстрируем это следующим образом:
во-первых, создадим в корне проекта папкуwwwroot
(если она у вас ещё не создана) и в этой папке — ещё одну папку с именем img
:
В папку wwwroot/img
поместим наш файл с картинкой, выберем его в обозревателе решений и установим для свойства «Копировать в выходной каталог» значение «Всегда копировать»:
Таким образом, наш файл будет каждый раз при сборке приложения копироваться в указанную папку. Теперь мы можем использовать в методе
SendFileAsync
путь относительно корня приложения:
app.Run(async context => { await context.Response.SendFileAsync(@"wwwroot\img\wow.jpeg"); });
Результат работы приложения будет такой же, как и в предыдущем примере. Тот факт, что ASP.NET Core по умолчанию пытается открыть файл в браузере, позволяет нам без лишних движений открывать в браузере html-страницы. Например, создадим в корне проекта два html-файла:
первый файл
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>Главная</title> </head> <body> <h2>Главная страница приложения</h2> </body> </html>
второй файл:
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title></title> </head> <body> <h2>Data Page</h2> </body> </html>
В обозревателе решений Visual Studio должна получиться следующая структура
Теперь мы уже знаем как создавать конвейер обработки запросов в ASP.NET и можем написать следующий пример загрузки html-страниц:
public class Program { public static void Main(string[] args) { var builder = WebApplication.CreateBuilder(args); var app = builder.Build(); app.Run(async context => { context.Response.ContentType = "text/html; charset=utf-8"; if (context.Request.Path == "/") await context.Response.SendFileAsync("index.html"); else if (context.Request.Path == "/data") await context.Response.SendFileAsync("data.html"); else { context.Response.StatusCode = 404; await context.Response.WriteAsync("<h2>Not Found</h2>"); } }); app.Run(); } }
Здесь в middleware сопоставляется путь запроса с файлом, который необходимо отправить клиенту. Так, сразу после запуска приложения отправляется файл index.html, если путь /data, то отправляется файл data.html, а при любом другом пути запроса — возвращается код статуса 404 и текст Not Found. Также стоит обратить внимание на заголовок, который мы отправляем:
context.Response.ContentType = "text/html; charset=utf-8";
мы указываем, что отправляем текст в формате html. Если этого не сделать, то в браузере вместо странички мы увидим её исходный код. Таким образом, наше приложение будет работать как показано на рисунках ниже:
главная страница
/data
ошибка
Скачивание файла клиентом
Открытие файла в браузере по умолчанию полезно, когда мы хотим отправить клиенту готовую html-страницу, но становится неудобным, когда мы хотим, чтобы пользователь именно загружал файл себе на компьютер, например, ту же картинку wow.jpeg. Чтобы клиент начал загружать файл, нам необходимо задать значение HTTP-заголовка Content-Disposition следующим образом:
app.Run(async context => { context.Response.Headers.ContentDisposition = "attachment; filename=\"filename.jpeg\""; await context.Response.SendFileAsync(@"wwwroot\img\wow.jpeg"); });
здесь в заголовке мы указываем имя с которым будет загружаться файл, то есть наш файл wow.jpeg при запуске приложения будет загружен следующим образом:
Использование IFileInfo в методе SendFileAsync
Также, метод SendFileAsync()
в качестве параметра может принимать не строку с именем файла, а объект, реализующий интерфейс IFileInfo
.
app.Run(async context => { var provider = app.Environment.WebRootFileProvider; var file = provider.GetFileInfo(@"img\wow.jpeg"); if (file.Exists) { context.Response.Headers.ContentDisposition = "attachment; filename=\"filename.jpeg\""; await context.Response.SendFileAsync(file); } else { context.Response.ContentType = "text/html; charset=utf-8"; await context.Response.WriteAsync("<h2>Not Found</h2>"); } });
Здесь мы получили объект, реализующий интерфейс IFileProvider
, который уже настроен на работу с папкой wwwroot
нашего приложения (об этом свойстве рассказывалось здесь). Далее мы, используя метод GetFileInfo()
получили информацию о файле и проверили его существование:
if (file.Exists)
если файл был найден, то от загружается с именем filename.jpeg на компьютер. Результат работы приложения будет такой же, как и в предыдущем примере.
Итого
Сегодня мы научились работать со статическими файлами в ASP.NET Core используя метод SendFileAsync
объекта HttpResponse
. По умолчанию. отправляемые файлы открываются в браузере, что удобно в случае, если нам необходимо отправить уже готовый html-файл пользователю. При необходимости, мы можем определить заголовок Content-Disposition и указать, что файл должен не открываться в браузере, а загружаться на компьютер пользователя как вложение.