Статичні файли в ASP.NET Core
Статичні файли в ASP.NET Core
Будь-який сучасний веб-додаток, окрім динамічних даних (JSON з бази даних), потребує віддавати клієнту так звані статичні файли. Це HTML-сторінки, CSS-стилі, JavaScript-скрипти, зображення (PNG, JPG) та шрифти, які лежать на диску сервера і не змінюються при кожному запиті.
За замовчуванням ASP.NET Core не віддає жодних файлів з міркувань безпеки. Уявіть, якби користувач міг написати GET /appsettings.json і завантажити ваші паролі від бази даних! Тому роздачу файлів потрібно явно вмикати.
У цьому розділі ми розглянемо традиційний підхід до роботи зі статичними файлами за допомогою Middleware-компонентів.
Тека wwwroot (Web Root)
В ASP.NET Core існує спеціальне місце для зберігання статичних файлів, до яких матиме доступ зовнішній світ — це папка wwwroot, яка знаходиться в корені вашого проєкту.
Структура проєкту зазвичай виглядає так:
MyProject/
├── Program.cs
├── appsettings.json
└── wwwroot/
├── css/
│ └── style.css
├── js/
│ └── app.js
├── images/
│ └── logo.png
└── index.html
Все, що лежить поза wwwroot, клієнт ніколи не зможе завантажити через браузер (якщо ви спеціально це не дозволите кодом).
Middleware UseStaticFiles
Щоб дозволити серверу віддавати файли з wwwroot, потрібно додати до конвеєра обробки запитів StaticFileMiddleware. Це робиться за допомогою методу UseStaticFiles().
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
// Вмикаємо роздачу статичних файлів з папки wwwroot
app.UseStaticFiles();
app.MapGet("/", () => "Hello World!");
app.Run();
Анатомія коду:
- Коли приходить запит
GET /css/style.css, Middleware перевіряє, чи існує файлMyProject/wwwroot/css/style.css. - Якщо файл є, він відразу завантажується клієнту з правильним HTTP-заголовком
Content-Type(наприклад,text/cssдля.cssабоimage/pngдля.png), і наступні Middleware не викликаються. - Якщо файлу немає, запит передається далі по конвеєру (наприклад, до роутингу, який поверне маршрут
"/").
UseStaticFilesпередMapGet("/"). Це означає, що спочатку ми шукаємо файл на диску, а вже потім шукаємо програмовані маршрути.
Зазвичай статику ставлять якомога вище у пайплайні, відразу після перенаправлення на HTTPS, щоб швидко віддавати зображення та уникати запуску логіки аутентифікації для файлів (якщо вони публічні).Файли за замовчуванням: UseDefaultFiles
Що відбувається, коли користувач просто вводить вашу адресу https://mysite.com/ (кореневий маршрут)?
Зазвичай, він очікує побачити головну HTML-сторінку.
Щоб сервер автоматично шукав index.html або default.html (коли шлях є просто назвою папки), потрібно використати метод UseDefaultFiles().
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
// Змушує запити до папок шукати в них файли за замовчуванням (наприклад, index.html)
app.UseDefaultFiles();
// Віддає ці файли
app.UseStaticFiles();
app.Run();
Анатомія коду:
- Запит:
GET / UseDefaultFilesперехоплює його, бачить, що це перегляд папки, шукає вwwwrootфайлindex.htmlі внутрішньо переписує (rewrite) запит з/на/index.html.- Запит іде далі.
UseStaticFilesбачить запит/index.htmlі, оскільки файл існує вwwwroot, віддає його.
Важливо:
UseDefaultFilesповинен викликатися передUseStaticFiles. Перший переписує URL, а другий фізично віддає файл.
За замовчуванням UseDefaultFiles шукає такі імена файлів у вказаному порядку:
default.htmdefault.htmlindex.htmindex.html
Перегляд каталогів: UseDirectoryBrowser
Іноді ви створюєте публічний архів документів (наприклад, /downloads/), і хочете, щоб користувачі бачили список усіх файлів у папці, як у провіднику Windows, якщо вони переходять за цією адресою.
З міркувань безпеки це вимкнено за замовчуванням. Щоб увімкнути, використовують UseDirectoryBrowser().
var builder = WebApplication.CreateBuilder(args);
// Потрібно явно додати сервіс перегляду директорій
builder.Services.AddDirectoryBrowser();
var app = builder.Build();
app.UseStaticFiles();
app.UseDirectoryBrowser(); // Дозволяє бачити список файлів
app.Run();
Якщо тепер зайти на http://localhost:5000/images/, браузер покаже красиву HTML-таблицю зі списком ресурсів в папці.
UseFileServer: все в одному
Оскільки UseDefaultFiles, UseStaticFiles та UseDirectoryBrowser часто використовуються разом і їх порядок важливий, фреймворк надає зручний метод UseFileServer, який поєднує в собі всі три!
Замість цього:
app.UseDefaultFiles();
app.UseStaticFiles();
// app.UseDirectoryBrowser();
Ви можете написати так:
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
// Вмикає Default Files + Static Files. (Directory Browser вимкнено за замовчуванням).
app.UseFileServer();
app.Run();
Щоб дозволити ще й перегляд каталогів, потрібно передати FileServerOptions:
app.UseFileServer(new FileServerOptions
{
EnableDirectoryBrowsing = true
});
Роздача файлів з інших папок
Що, як вам потрібно роздавати зображення з папки D:\MyImages, яка лежить поза вашим проєктом, але ви хочете, щоб вони були доступні за URL /pictures?
Це робиться за допомогою налаштування опцій (Options) для Middleware.
using Microsoft.Extensions.FileProviders;
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
// Стандартна папка wwwroot (шлях /)
app.UseStaticFiles();
// Кастомна папка десь на диску (шлях /pictures)
app.UseStaticFiles(new StaticFileOptions
{
// Фізичний шлях до папки на сервері
FileProvider = new PhysicalFileProvider(@"D:\MyImages"),
// URL префікс для доступу через браузер
RequestPath = "/pictures"
});
app.Run();
Анатомія коду:
- Якщо браузер запитує
GET /styles.css, спрацює першийUseStaticFilesі шукатиме файл уwwwroot/styles.css. - Якщо браузер запитує
GET /pictures/cat.jpg, перший Middleware його пропустить, але спрацює другийUseStaticFiles. Він зрозуміє префікс/pictures, відріже його, і почне шукатиcat.jpgу фізичній папціD:\MyImages\cat.jpg.
Практичні завдання
Запуск статичного сайту
- В корені вашого проєкту (поруч з
Program.cs) створіть папкуwwwroot. - У
wwwrootстворіть файлindex.htmlз текстом<h1>Ласкаво просимо!</h1>. - Налаштуйте пайплайн за допомогою одного єдиного рядка коду, щоб при запуску додатку і переході в корінь (
/), автоматично відкривався вашindex.html.
wwwroot текстовий файл info.txt з певним вмістом.
У Program.cs додайте:
app.MapGet("/info.txt", () => "Текст з C# коду");
Налаштуйте UseStaticFiles і зробіть запит на клієнті в /info.txt. Що ви побачите? Текст з файлу чи з C#? Поміняйте місцями виклики Middleware та роуту, і подивіться, як зміниться результат. Поясніть чому.main.html замість index.html.
Відкрийте документацію до UseDefaultFiles (або DefaultFilesOptions) та знайдіть спосіб зробити так, щоб при заході на / система автоматично шукала саме main.html, а не дефолтні файли.Маршрутизація в ASP.NET Core: Розширені можливості
У попередньому матеріалі ми дізналися, як створювати базові маршрути та приймати параметри. Однак реальні проєкти вимагають значно більшого контролю над тим, які запити має обробляти конкретна кінцева точка.
Статичні Активи: MapStaticAssets (ASP.NET Core 9.0)
Впродовж багатьох років в ASP.NET Core стандартом для роздачі файлів був підхід із UseStaticFiles(), який ми розглянули в попередньому розділі. Він працює добре: браузер запитує файл з папки wwwroot, сервер його знаходить (якщо він є) і відправляє.