Будь-який сучасний веб-додаток, окрім динамічних даних (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, клієнт ніколи не зможе завантажити через браузер (якщо ви спеціально це не дозволите кодом).
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.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.htmlUseDirectoryBrowserІноді ви створюєте публічний архів документів (наприклад, /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, сервер його знаходить (якщо він є) і відправляє.