Содержание
Современные 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 и указать, что файл должен не открываться в браузере, а загружаться на компьютер пользователя как вложение.






