Bagikan melalui


File statik di ASP.NET Core

Catatan

Ini bukan versi terbaru dari artikel ini. Untuk rilis saat ini, lihat versi .NET 8 dari artikel ini.

Penting

Informasi ini berkaitan dengan produk pra-rilis yang mungkin dimodifikasi secara substansial sebelum dirilis secara komersial. Microsoft tidak memberikan jaminan, tersirat maupun tersurat, sehubungan dengan informasi yang diberikan di sini.

Untuk rilis saat ini, lihat versi .NET 8 dari artikel ini.

Oleh Rick Anderson

File statis, seperti HTML, CSS, gambar, dan JavaScript, adalah aset aplikasi ASP.NET Core berfungsi langsung ke klien secara default.

Sajikan file statis

File statis disimpan dalam direktori akar web proyek. Direktori default adalah {content root}/wwwroot, tetapi dapat diubah dengan UseWebRoot metode . Untuk informasi selengkapnya, lihat Akar konten dan akar Web.

Metode CreateBuilder ini mengatur akar konten ke direktori saat ini:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseAuthorization();

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

File statis dapat diakses melalui jalur yang relatif terhadap akar web. Misalnya, templat proyek Aplikasi Web berisi beberapa folder dalam wwwroot folder:

  • wwwroot
    • css
    • js
    • lib

Pertimbangkan untuk membuat folder wwwroot/images dan menambahkan wwwroot/images/MyImage.jpg file. Format URI untuk mengakses file di images folder adalah https://<hostname>/images/<image_file_name>. Misalnya: https://localhost:5001/images/MyImage.jpg

MapStaticAssets

MapStaticAssets adalah middleware yang membantu mengoptimalkan pengiriman aset statis dalam aplikasi. Untuk informasi selengkapnya, lihat Mengoptimalkan pengiriman aset web statis .

Menyajikan file di akar web

Templat aplikasi web default memanggil UseStaticFiles metode di Program.cs, yang memungkinkan file statis dilayani:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseAuthorization();

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

Overload metode tanpa UseStaticFiles parameter menandai file di akar web sebagai servable. Referensi wwwroot/images/MyImage.jpgmarkup berikut :

<img src="~/images/MyImage.jpg" class="img" alt="My image" />

Dalam markup sebelumnya, karakter ~ tilde menunjuk ke akar web.

Menyajikan file di luar akar web

Pertimbangkan hierarki direktori tempat file statis untuk dilayani berada di luar akar web:

  • wwwroot
    • css
    • images
    • js
  • MyStaticFiles
    • images
      • red-rose.jpg

Permintaan dapat mengakses red-rose.jpg file dengan mengonfigurasi Middleware File Statis sebagai berikut:

using Microsoft.Extensions.FileProviders;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();

app.UseStaticFiles(new StaticFileOptions
{
    FileProvider = new PhysicalFileProvider(
           Path.Combine(builder.Environment.ContentRootPath, "MyStaticFiles")),
    RequestPath = "/StaticFiles"
});

app.UseAuthorization();

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

Dalam kode sebelumnya, hierarki direktori MyStaticFiles diekspos secara publik melalui segmen URI StaticFiles . Permintaan untuk https://<hostname>/StaticFiles/images/red-rose.jpg melayani red-rose.jpg file.

Referensi MyStaticFiles/images/red-rose.jpgmarkup berikut :

<img src="~/StaticFiles/images/red-rose.jpg" class="img" alt="A red rose" />

Untuk menyajikan file dari beberapa lokasi, lihat Menyajikan file dari beberapa lokasi.

Mengatur header respons HTTP

Objek StaticFileOptions dapat digunakan untuk mengatur header respons HTTP. Selain mengonfigurasi penyajian file statis dari akar web, kode berikut mengatur header Cache-Control :

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();

var cacheMaxAgeOneWeek = (60 * 60 * 24 * 7).ToString();
app.UseStaticFiles(new StaticFileOptions
{
    OnPrepareResponse = ctx =>
    {
        ctx.Context.Response.Headers.Append(
             "Cache-Control", $"public, max-age={cacheMaxAgeOneWeek}");
    }
});

app.UseAuthorization();

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

Kode sebelumnya membuat file statis tersedia untuk umum di cache lokal selama satu minggu (604800 detik).

Otorisasi file statis

Templat ASP.NET Core memanggil UseStaticFiles sebelum memanggil UseAuthorization. Sebagian besar aplikasi mengikuti pola ini. Ketika Middleware File Statis dipanggil sebelum middleware otorisasi:

  • Tidak ada pemeriksaan otorisasi yang dilakukan pada file statis.
  • File statis yang dilayani oleh Middleware File Statis, seperti file di bawah wwwroot, dapat diakses secara publik.

Untuk menyajikan file statis berdasarkan otorisasi:

  • Simpan di luar wwwroot.
  • Panggil UseStaticFiles, menentukan jalur, setelah memanggil UseAuthorization.
  • Atur kebijakan otorisasi fallback.
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.FileProviders;
using StaticFileAuth.Data;

var builder = WebApplication.CreateBuilder(args);

var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
builder.Services.AddDbContext<ApplicationDbContext>(options =>
    options.UseSqlServer(connectionString));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();

builder.Services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
    .AddEntityFrameworkStores<ApplicationDbContext>();
builder.Services.AddRazorPages();

builder.Services.AddAuthorization(options =>
{
    options.FallbackPolicy = new AuthorizationPolicyBuilder()
        .RequireAuthenticatedUser()
        .Build();
});

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.UseMigrationsEndPoint();
}
else
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();

app.UseAuthentication();
app.UseAuthorization();

app.UseStaticFiles(new StaticFileOptions
{
    FileProvider = new PhysicalFileProvider(
           Path.Combine(builder.Environment.ContentRootPath, "MyStaticFiles")),
    RequestPath = "/StaticFiles"
});

app.MapRazorPages();

app.Run();

Dalam kode sebelumnya, kebijakan otorisasi fallback mengharuskan semua pengguna diautentikasi. Titik akhir seperti pengontrol, Razor Halaman, dll yang menentukan persyaratan otorisasi mereka sendiri tidak menggunakan kebijakan otorisasi fallback. Misalnya, Razor Halaman, pengontrol, atau metode tindakan dengan [AllowAnonymous] atau [Authorize(PolicyName="MyPolicy")] menggunakan atribut otorisasi yang diterapkan daripada kebijakan otorisasi fallback.

RequireAuthenticatedUser menambahkan ke instans DenyAnonymousAuthorizationRequirement saat ini, yang memberlakukan bahwa pengguna saat ini diautentikasi.

Aset statis di bawah wwwroot dapat diakses secara publik karena Middleware File Statis default (app.UseStaticFiles();) dipanggil sebelum UseAuthentication. Aset statis di folder MyStaticFiles memerlukan autentikasi. Kode sampel menunjukkan ini.

Pendekatan alternatif untuk melayani file berdasarkan otorisasi adalah dengan:

  • Simpan di luar wwwroot dan direktori apa pun yang dapat diakses oleh Middleware File Statis.

  • Sajikan melalui metode tindakan tempat otorisasi diterapkan dan mengembalikan FileResult objek:

    [Authorize]
    public class BannerImageModel : PageModel
    {
        private readonly IWebHostEnvironment _env;
    
        public BannerImageModel(IWebHostEnvironment env) =>
            _env = env;
    
        public PhysicalFileResult OnGet()
        {
            var filePath = Path.Combine(
                    _env.ContentRootPath, "MyStaticFiles", "images", "red-rose.jpg");
    
            return PhysicalFile(filePath, "image/jpeg");
        }
    }
    

Pendekatan sebelumnya memerlukan halaman atau titik akhir per file. Kode berikut mengembalikan file atau mengunggah file untuk pengguna terautentikasi:

app.MapGet("/files/{fileName}",  IResult (string fileName) => 
    {
        var filePath = GetOrCreateFilePath(fileName);

        if (File.Exists(filePath))
        {
            return TypedResults.PhysicalFile(filePath, fileDownloadName: $"{fileName}");
        }

        return TypedResults.NotFound("No file found with the supplied file name");
    })
    .WithName("GetFileByName")
    .RequireAuthorization("AuthenticatedUsers");

// IFormFile uses memory buffer for uploading. For handling large file use streaming instead.
// https://learn.microsoft.com/aspnet/core/mvc/models/file-uploads#upload-large-files-with-streaming
app.MapPost("/files", async (IFormFile file, LinkGenerator linker, HttpContext context) =>
    {
        // Don't rely on the file.FileName as it is only metadata that can be manipulated by the end-user
        // Take a look at the `Utilities.IsFileValid` method that takes an IFormFile and validates its signature within the AllowedFileSignatures
        
        var fileSaveName = Guid.NewGuid().ToString("N") + Path.GetExtension(file.FileName);
        await SaveFileWithCustomFileName(file, fileSaveName);
        
        context.Response.Headers.Append("Location", linker.GetPathByName(context, "GetFileByName", new { fileName = fileSaveName}));
        return TypedResults.Ok("File Uploaded Successfully!");
    })
    .RequireAuthorization("AdminsOnly");

app.Run();

Lihat folder StaticFileAuth GitHub untuk sampel lengkapnya.

Penjelajahan direktori

Penjelajahan direktori memungkinkan daftar direktori dalam direktori tertentu.

Penjelajahan direktori dinonaktifkan secara default karena alasan keamanan. Untuk informasi selengkapnya, lihat Pertimbangan keamanan untuk file statis.

Aktifkan penjelajahan direktori dengan AddDirectoryBrowser dan UseDirectoryBrowser:

using Microsoft.AspNetCore.StaticFiles;
using Microsoft.Extensions.FileProviders;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

builder.Services.AddDirectoryBrowser();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();

app.UseStaticFiles();

var fileProvider = new PhysicalFileProvider(Path.Combine(builder.Environment.WebRootPath, "images"));
var requestPath = "/MyImages";

// Enable displaying browser links.
app.UseStaticFiles(new StaticFileOptions
{
    FileProvider = fileProvider,
    RequestPath = requestPath
});

app.UseDirectoryBrowser(new DirectoryBrowserOptions
{
    FileProvider = fileProvider,
    RequestPath = requestPath
});

app.UseAuthorization();

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

Kode sebelumnya memungkinkan penjelajahan direktori folder wwwroot/images menggunakan URL https://<hostname>/MyImages, dengan tautan ke setiap file dan folder:

penjelajahan direktori

AddDirectoryBrowsermenambahkan layanan yang diperlukan oleh middleware penjelajahan direktori, termasuk HtmlEncoder. Layanan ini dapat ditambahkan oleh panggilan lain, seperti AddRazorPages, tetapi sebaiknya panggil AddDirectoryBrowser untuk memastikan layanan ditambahkan di semua aplikasi.

Melayani dokumen default

Mengatur halaman default memberi pengunjung titik awal di situs. Untuk melayani file default dari wwwroot tanpa memerlukan URL permintaan untuk menyertakan nama file, panggil UseDefaultFiles metode :

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();

app.UseDefaultFiles();

app.UseStaticFiles();
app.UseAuthorization();

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

UseDefaultFiles harus dipanggil sebelumnya UseStaticFiles untuk melayani file default. UseDefaultFiles adalah penulis ulang URL yang tidak melayani file.

Dengan UseDefaultFiles, permintaan ke folder untuk wwwroot mencari:

  • default.htm
  • default.html
  • index.htm
  • index.html

File pertama yang ditemukan dari daftar dilayani seolah-olah permintaan menyertakan nama file. URL browser terus mencerminkan URI yang diminta.

Kode berikut mengubah nama file default menjadi mydefault.html:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();

var options = new DefaultFilesOptions();
options.DefaultFileNames.Clear();
options.DefaultFileNames.Add("mydefault.html");
app.UseDefaultFiles(options);

app.UseStaticFiles();

app.UseAuthorization();

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

UseFileServer untuk dokumen default

UseFileServer menggabungkan fungsionalitas UseStaticFiles, UseDefaultFiles, dan secara UseDirectoryBrowseropsional .

Panggil app.UseFileServer untuk mengaktifkan penyajian file statis dan file default. Penjelajahan direktori tidak diaktifkan:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();

app.UseFileServer();

app.UseAuthorization();

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

Kode berikut memungkinkan penyajian file statis, file default, dan penjelajahan direktori:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

builder.Services.AddDirectoryBrowser();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();

app.UseFileServer(enableDirectoryBrowsing: true);

app.UseRouting();

app.UseAuthorization();

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

Pertimbangkan hierarki direktori berikut:

  • wwwroot
    • css
    • images
    • js
  • MyStaticFiles
    • images
      • MyImage.jpg
    • default.html

Kode berikut memungkinkan penyajian file statis, file default, dan penjelajahan direktori dari MyStaticFiles:

using Microsoft.Extensions.FileProviders;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

builder.Services.AddDirectoryBrowser();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();

app.UseStaticFiles();

app.UseFileServer(new FileServerOptions
{
    FileProvider = new PhysicalFileProvider(
           Path.Combine(builder.Environment.ContentRootPath, "MyStaticFiles")),
    RequestPath = "/StaticFiles",
    EnableDirectoryBrowsing = true
});

app.UseAuthorization();

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

AddDirectoryBrowser harus dipanggil ketika EnableDirectoryBrowsing nilai properti adalah true.

Menggunakan hierarki dan kode file sebelumnya, URL diselesaikan sebagai berikut:

URI Respons
https://<hostname>/StaticFiles/images/MyImage.jpg MyStaticFiles/images/MyImage.jpg
https://<hostname>/StaticFiles MyStaticFiles/default.html

Jika tidak ada file bernama default di direktori MyStaticFiles, https://<hostname>/StaticFiles mengembalikan daftar direktori dengan tautan yang dapat diklik:

Daftar file statis

UseDefaultFiles dan UseDirectoryBrowser lakukan pengalihan sisi klien dari URI target tanpa mengikuti / URI target dengan trailing /. Misalnya, dari https://<hostname>/StaticFiles ke https://<hostname>/StaticFiles/. URL relatif dalam direktori StaticFiles tidak valid tanpa garis miring berikutnya (/) kecuali RedirectToAppendTrailingSlash opsi DefaultFilesOptions digunakan.

FileExtensionContentTypeProvider

Kelas FileExtensionContentTypeProvider berisi Mappings properti yang berfungsi sebagai pemetaan ekstensi file ke jenis konten MIME. Dalam sampel berikut, beberapa ekstensi file dipetakan ke jenis MIME yang diketahui. Ekstensi .rtf diganti, dan .mp4 dihapus:

using Microsoft.AspNetCore.StaticFiles;
using Microsoft.Extensions.FileProviders;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();

// Set up custom content types - associating file extension to MIME type
var provider = new FileExtensionContentTypeProvider();
// Add new mappings
provider.Mappings[".myapp"] = "application/x-msdownload";
provider.Mappings[".htm3"] = "text/html";
provider.Mappings[".image"] = "image/png";
// Replace an existing mapping
provider.Mappings[".rtf"] = "application/x-msdownload";
// Remove MP4 videos.
provider.Mappings.Remove(".mp4");

app.UseStaticFiles(new StaticFileOptions
{
    ContentTypeProvider = provider
});

app.UseAuthorization();

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

Lihat Jenis konten MIME.

Jenis konten non-standar

Middleware File Statis memahami hampir 400 jenis konten file yang diketahui. Jika pengguna meminta file dengan jenis file yang tidak diketahui, Middleware File Statis meneruskan permintaan ke middleware berikutnya dalam alur. Jika tidak ada middleware yang menangani permintaan, respons 404 Tidak Ditemukan dikembalikan. Jika penjelajahan direktori diaktifkan, tautan ke file ditampilkan dalam daftar direktori.

Kode berikut memungkinkan penyajian jenis yang tidak diketahui dan merender file yang tidak diketahui sebagai gambar:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();

app.UseStaticFiles(new StaticFileOptions
{
    ServeUnknownFileTypes = true,
    DefaultContentType = "image/png"
});

app.UseAuthorization();

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

Dengan kode sebelumnya, permintaan untuk file dengan jenis konten yang tidak diketahui dikembalikan sebagai gambar.

Peringatan

Mengaktifkan ServeUnknownFileTypes adalah risiko keamanan. Ini dinonaktifkan secara default, dan penggunaannya tidak disarankan. FileExtensionContentTypeProvider menyediakan alternatif yang lebih aman untuk melayani file dengan ekstensi non-standar.

Menyajikan file dari beberapa lokasi

Pertimbangkan halaman berikut Razor yang menampilkan /MyStaticFiles/image3.png file:

@page

<p> Test /MyStaticFiles/image3.png</p>

<img src="~/image3.png" class="img" asp-append-version="true" alt="Test">

UseStaticFiles dan UseFileServer default ke penyedia file yang menunjuk ke wwwroot. Instans tambahan dan UseStaticFilesUseFileServer dapat disediakan dengan penyedia file lain untuk melayani file dari lokasi lain. Contoh berikut memanggil UseStaticFiles dua kali untuk melayani file dari dan wwwrootMyStaticFiles:

app.UseStaticFiles(); // Serve files from wwwroot
app.UseStaticFiles(new StaticFileOptions
{
    FileProvider = new PhysicalFileProvider(
        Path.Combine(builder.Environment.ContentRootPath, "MyStaticFiles"))
});

Menggunakan kode sebelumnya:

  • File /MyStaticFiles/image3.png ditampilkan.
  • Pembantu AppendVersionTag Gambar tidak diterapkan karena Pembantu Tag bergantung pada WebRootFileProvider. WebRootFileProvider belum diperbarui untuk menyertakan MyStaticFiles folder.

Kode berikut memperbarui WebRootFileProvider, yang memungkinkan Pembantu Tag Gambar untuk menyediakan versi:

var webRootProvider = new PhysicalFileProvider(builder.Environment.WebRootPath);
var newPathProvider = new PhysicalFileProvider(
  Path.Combine(builder.Environment.ContentRootPath, "MyStaticFiles"));

var compositeProvider = new CompositeFileProvider(webRootProvider,
                                                  newPathProvider);

// Update the default provider.
app.Environment.WebRootFileProvider = compositeProvider;

app.UseStaticFiles();

Pertimbangan keamanan untuk file statis

Peringatan

UseDirectoryBrowser dan UseStaticFiles dapat membocorkan rahasia. Menonaktifkan penjelajahan direktori dalam produksi sangat disarankan. Tinjau direktori mana yang diaktifkan dengan hati-hati melalui UseStaticFiles atau UseDirectoryBrowser. Seluruh direktori dan sub-direktorinya dapat diakses secara publik. Simpan file yang cocok untuk dilayani ke publik di direktori khusus, seperti <content_root>/wwwroot. Pisahkan file-file ini dari tampilan MVC, Razor Halaman, file konfigurasi, dll.

  • URL untuk konten yang diekspos dengan UseDirectoryBrowser dan UseStaticFiles tunduk pada sensitivitas kasus dan pembatasan karakter dari sistem file yang mendasar. Misalnya, Windows tidak peka huruf besar/kecil, tetapi macOS dan Linux tidak.

  • ASP.NET aplikasi Core yang dihosting di IIS menggunakan Modul Inti ASP.NET untuk meneruskan semua permintaan ke aplikasi, termasuk permintaan file statis. Handler file statis IIS tidak digunakan dan tidak memiliki kesempatan untuk menangani permintaan.

  • Selesaikan langkah-langkah berikut di Manajer IIS untuk menghapus handler file statis IIS di tingkat server atau situs web:

    1. Navigasi ke fitur Modul .
    2. Pilih StaticFileModule dalam daftar.
    3. Klik Hapus di bilah samping Tindakan .

Peringatan

Jika handler file statis IIS diaktifkan dan ASP.NET Core Module dikonfigurasi dengan salah, file statis dilayani. Ini terjadi, misalnya, jika file web.config tidak disebarkan.

  • Tempatkan file kode, termasuk .cs dan .cshtml, di luar akar web proyek aplikasi. Oleh karena itu, pemisahan logis dibuat antara konten sisi klien aplikasi dan kode berbasis server. Ini mencegah kode sisi server bocor.

Melayani file di luar wwwroot dengan memperbarui IWebHostEnvironment.WebRootPath

Kapan IWebHostEnvironment.WebRootPath diatur ke folder selain wwwroot:

  • Di lingkungan pengembangan, aset statis yang ditemukan di keduanya wwwroot dan yang diperbarui IWebHostEnvironment.WebRootPath disajikan dari wwwroot.
  • Di lingkungan apa pun selain pengembangan, aset statis duplikat disajikan dari folder yang diperbarui IWebHostEnvironment.WebRootPath .

Pertimbangkan aplikasi web yang dibuat dengan templat web kosong:

  • Berisi Index.html file di wwwroot dan wwwroot-custom.

  • Dengan file yang diperbarui Program.cs berikut yang menetapkan WebRootPath = "wwwroot-custom":

    var builder = WebApplication.CreateBuilder(new WebApplicationOptions
    {
        Args = args,
        // Look for static files in "wwwroot-custom"
        WebRootPath = "wwwroot-custom"
    });
    
    var app = builder.Build();
    
    app.UseDefaultFiles();
    app.UseStaticFiles();
    
    app.Run();
    

Dalam kode sebelumnya, permintaan ke /:

  • Dalam pengembalian lingkungan pengembangan wwwroot/Index.html
  • Di lingkungan apa pun selain pengembalian pengembangan wwwroot-custom/Index.html

Untuk memastikan aset dari wwwroot-custom dikembalikan, gunakan salah satu pendekatan berikut:

  • Hapus aset bernama duplikat di wwwroot.

  • Atur "ASPNETCORE_ENVIRONMENT" ke nilai apa pun selain "Development".Properties/launchSettings.json

  • Nonaktifkan aset web statis sepenuhnya dengan mengatur <StaticWebAssetsEnabled>false</StaticWebAssetsEnabled> dalam file proyek. PERINGATAN, menonaktifkan aset web statis menonaktifkan Razor Pustaka Kelas.

  • Tambahkan ON berikut JSke file proyek:

    <ItemGroup>
        <Content Remove="wwwroot\**" />
    </ItemGroup>
    

Kode berikut diperbarui IWebHostEnvironment.WebRootPath ke nilai non pengembangan, menjamin konten duplikat dikembalikan dari wwwroot-custom bukan wwwroot:

var builder = WebApplication.CreateBuilder(new WebApplicationOptions
{
    Args = args,
    // Examine Hosting environment: logging value
    EnvironmentName = Environments.Staging,
    WebRootPath = "wwwroot-custom"
});

var app = builder.Build();

app.Logger.LogInformation("ASPNETCORE_ENVIRONMENT: {env}",
      Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT"));

app.Logger.LogInformation("app.Environment.IsDevelopment(): {env}",
      app.Environment.IsDevelopment().ToString());

app.UseDefaultFiles();
app.UseStaticFiles();

app.Run();

Sumber Daya Tambahan:

Oleh Rick Anderson

File statis, seperti HTML, CSS, gambar, dan JavaScript, adalah aset aplikasi ASP.NET Core berfungsi langsung ke klien secara default.

Sajikan file statis

File statis disimpan dalam direktori akar web proyek. Direktori default adalah {content root}/wwwroot, tetapi dapat diubah dengan UseWebRoot metode . Untuk informasi selengkapnya, lihat Akar konten dan akar Web.

Metode CreateBuilder ini mengatur akar konten ke direktori saat ini:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseAuthorization();

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

File statis dapat diakses melalui jalur yang relatif terhadap akar web. Misalnya, templat proyek Aplikasi Web berisi beberapa folder dalam wwwroot folder:

  • wwwroot
    • css
    • js
    • lib

Pertimbangkan untuk membuat folder wwwroot/images dan menambahkan wwwroot/images/MyImage.jpg file. Format URI untuk mengakses file di images folder adalah https://<hostname>/images/<image_file_name>. Misalnya: https://localhost:5001/images/MyImage.jpg

Menyajikan file di akar web

Templat aplikasi web default memanggil UseStaticFiles metode di Program.cs, yang memungkinkan file statis dilayani:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseAuthorization();

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

Overload metode tanpa UseStaticFiles parameter menandai file di akar web sebagai servable. Referensi wwwroot/images/MyImage.jpgmarkup berikut :

<img src="~/images/MyImage.jpg" class="img" alt="My image" />

Dalam markup sebelumnya, karakter ~ tilde menunjuk ke akar web.

Menyajikan file di luar akar web

Pertimbangkan hierarki direktori tempat file statis untuk dilayani berada di luar akar web:

  • wwwroot
    • css
    • images
    • js
  • MyStaticFiles
    • images
      • red-rose.jpg

Permintaan dapat mengakses red-rose.jpg file dengan mengonfigurasi Middleware File Statis sebagai berikut:

using Microsoft.Extensions.FileProviders;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();

app.UseStaticFiles(new StaticFileOptions
{
    FileProvider = new PhysicalFileProvider(
           Path.Combine(builder.Environment.ContentRootPath, "MyStaticFiles")),
    RequestPath = "/StaticFiles"
});

app.UseAuthorization();

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

Dalam kode sebelumnya, hierarki direktori MyStaticFiles diekspos secara publik melalui segmen URI StaticFiles . Permintaan untuk https://<hostname>/StaticFiles/images/red-rose.jpg melayani red-rose.jpg file.

Referensi MyStaticFiles/images/red-rose.jpgmarkup berikut :

<img src="~/StaticFiles/images/red-rose.jpg" class="img" alt="A red rose" />

Untuk menyajikan file dari beberapa lokasi, lihat Menyajikan file dari beberapa lokasi.

Mengatur header respons HTTP

Objek StaticFileOptions dapat digunakan untuk mengatur header respons HTTP. Selain mengonfigurasi penyajian file statis dari akar web, kode berikut mengatur header Cache-Control :

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();

var cacheMaxAgeOneWeek = (60 * 60 * 24 * 7).ToString();
app.UseStaticFiles(new StaticFileOptions
{
    OnPrepareResponse = ctx =>
    {
        ctx.Context.Response.Headers.Append(
             "Cache-Control", $"public, max-age={cacheMaxAgeOneWeek}");
    }
});

app.UseAuthorization();

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

Kode sebelumnya membuat file statis tersedia untuk umum di cache lokal selama satu minggu (604800 detik).

Otorisasi file statis

Templat ASP.NET Core memanggil UseStaticFiles sebelum memanggil UseAuthorization. Sebagian besar aplikasi mengikuti pola ini. Ketika Middleware File Statis dipanggil sebelum middleware otorisasi:

  • Tidak ada pemeriksaan otorisasi yang dilakukan pada file statis.
  • File statis yang dilayani oleh Middleware File Statis, seperti file di bawah wwwroot, dapat diakses secara publik.

Untuk menyajikan file statis berdasarkan otorisasi:

  • Simpan di luar wwwroot.
  • Panggil UseStaticFiles, menentukan jalur, setelah memanggil UseAuthorization.
  • Atur kebijakan otorisasi fallback.
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.FileProviders;
using StaticFileAuth.Data;

var builder = WebApplication.CreateBuilder(args);

var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
builder.Services.AddDbContext<ApplicationDbContext>(options =>
    options.UseSqlServer(connectionString));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();

builder.Services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
    .AddEntityFrameworkStores<ApplicationDbContext>();
builder.Services.AddRazorPages();

builder.Services.AddAuthorization(options =>
{
    options.FallbackPolicy = new AuthorizationPolicyBuilder()
        .RequireAuthenticatedUser()
        .Build();
});

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.UseMigrationsEndPoint();
}
else
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();

app.UseAuthentication();
app.UseAuthorization();

app.UseStaticFiles(new StaticFileOptions
{
    FileProvider = new PhysicalFileProvider(
           Path.Combine(builder.Environment.ContentRootPath, "MyStaticFiles")),
    RequestPath = "/StaticFiles"
});

app.MapRazorPages();

app.Run();

Dalam kode sebelumnya, kebijakan otorisasi fallback mengharuskan semua pengguna diautentikasi. Titik akhir seperti pengontrol, Razor Halaman, dll yang menentukan persyaratan otorisasi mereka sendiri tidak menggunakan kebijakan otorisasi fallback. Misalnya, Razor Halaman, pengontrol, atau metode tindakan dengan [AllowAnonymous] atau [Authorize(PolicyName="MyPolicy")] menggunakan atribut otorisasi yang diterapkan daripada kebijakan otorisasi fallback.

RequireAuthenticatedUser menambahkan ke instans DenyAnonymousAuthorizationRequirement saat ini, yang memberlakukan bahwa pengguna saat ini diautentikasi.

Aset statis di bawah wwwroot dapat diakses secara publik karena Middleware File Statis default (app.UseStaticFiles();) dipanggil sebelum UseAuthentication. Aset statis di folder MyStaticFiles memerlukan autentikasi. Kode sampel menunjukkan ini.

Pendekatan alternatif untuk melayani file berdasarkan otorisasi adalah dengan:

  • Simpan di luar wwwroot dan direktori apa pun yang dapat diakses oleh Middleware File Statis.

  • Sajikan melalui metode tindakan tempat otorisasi diterapkan dan mengembalikan FileResult objek:

    [Authorize]
    public class BannerImageModel : PageModel
    {
        private readonly IWebHostEnvironment _env;
    
        public BannerImageModel(IWebHostEnvironment env) =>
            _env = env;
    
        public PhysicalFileResult OnGet()
        {
            var filePath = Path.Combine(
                    _env.ContentRootPath, "MyStaticFiles", "images", "red-rose.jpg");
    
            return PhysicalFile(filePath, "image/jpeg");
        }
    }
    

Pendekatan sebelumnya memerlukan halaman atau titik akhir per file. Kode berikut mengembalikan file atau mengunggah file untuk pengguna terautentikasi:

app.MapGet("/files/{fileName}",  IResult (string fileName) => 
    {
        var filePath = GetOrCreateFilePath(fileName);

        if (File.Exists(filePath))
        {
            return TypedResults.PhysicalFile(filePath, fileDownloadName: $"{fileName}");
        }

        return TypedResults.NotFound("No file found with the supplied file name");
    })
    .WithName("GetFileByName")
    .RequireAuthorization("AuthenticatedUsers");

// IFormFile uses memory buffer for uploading. For handling large file use streaming instead.
// https://learn.microsoft.com/aspnet/core/mvc/models/file-uploads#upload-large-files-with-streaming
app.MapPost("/files", async (IFormFile file, LinkGenerator linker, HttpContext context) =>
    {
        // Don't rely on the file.FileName as it is only metadata that can be manipulated by the end-user
        // Take a look at the `Utilities.IsFileValid` method that takes an IFormFile and validates its signature within the AllowedFileSignatures
        
        var fileSaveName = Guid.NewGuid().ToString("N") + Path.GetExtension(file.FileName);
        await SaveFileWithCustomFileName(file, fileSaveName);
        
        context.Response.Headers.Append("Location", linker.GetPathByName(context, "GetFileByName", new { fileName = fileSaveName}));
        return TypedResults.Ok("File Uploaded Successfully!");
    })
    .RequireAuthorization("AdminsOnly");

app.Run();

Lihat folder StaticFileAuth GitHub untuk sampel lengkapnya.

Penjelajahan direktori

Penjelajahan direktori memungkinkan daftar direktori dalam direktori tertentu.

Penjelajahan direktori dinonaktifkan secara default karena alasan keamanan. Untuk informasi selengkapnya, lihat Pertimbangan keamanan untuk file statis.

Aktifkan penjelajahan direktori dengan AddDirectoryBrowser dan UseDirectoryBrowser:

using Microsoft.AspNetCore.StaticFiles;
using Microsoft.Extensions.FileProviders;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

builder.Services.AddDirectoryBrowser();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();

app.UseStaticFiles();

var fileProvider = new PhysicalFileProvider(Path.Combine(builder.Environment.WebRootPath, "images"));
var requestPath = "/MyImages";

// Enable displaying browser links.
app.UseStaticFiles(new StaticFileOptions
{
    FileProvider = fileProvider,
    RequestPath = requestPath
});

app.UseDirectoryBrowser(new DirectoryBrowserOptions
{
    FileProvider = fileProvider,
    RequestPath = requestPath
});

app.UseAuthorization();

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

Kode sebelumnya memungkinkan penjelajahan direktori folder wwwroot/images menggunakan URL https://<hostname>/MyImages, dengan tautan ke setiap file dan folder:

penjelajahan direktori

AddDirectoryBrowsermenambahkan layanan yang diperlukan oleh middleware penjelajahan direktori, termasuk HtmlEncoder. Layanan ini dapat ditambahkan oleh panggilan lain, seperti AddRazorPages, tetapi sebaiknya panggil AddDirectoryBrowser untuk memastikan layanan ditambahkan di semua aplikasi.

Melayani dokumen default

Mengatur halaman default memberi pengunjung titik awal di situs. Untuk melayani file default dari wwwroot tanpa memerlukan URL permintaan untuk menyertakan nama file, panggil UseDefaultFiles metode :

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();

app.UseDefaultFiles();

app.UseStaticFiles();
app.UseAuthorization();

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

UseDefaultFiles harus dipanggil sebelumnya UseStaticFiles untuk melayani file default. UseDefaultFiles adalah penulis ulang URL yang tidak melayani file.

Dengan UseDefaultFiles, permintaan ke folder untuk wwwroot mencari:

  • default.htm
  • default.html
  • index.htm
  • index.html

File pertama yang ditemukan dari daftar dilayani seolah-olah permintaan menyertakan nama file. URL browser terus mencerminkan URI yang diminta.

Kode berikut mengubah nama file default menjadi mydefault.html:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();

var options = new DefaultFilesOptions();
options.DefaultFileNames.Clear();
options.DefaultFileNames.Add("mydefault.html");
app.UseDefaultFiles(options);

app.UseStaticFiles();

app.UseAuthorization();

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

UseFileServer untuk dokumen default

UseFileServer menggabungkan fungsionalitas UseStaticFiles, UseDefaultFiles, dan secara UseDirectoryBrowseropsional .

Panggil app.UseFileServer untuk mengaktifkan penyajian file statis dan file default. Penjelajahan direktori tidak diaktifkan:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();

app.UseFileServer();

app.UseAuthorization();

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

Kode berikut memungkinkan penyajian file statis, file default, dan penjelajahan direktori:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

builder.Services.AddDirectoryBrowser();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();

app.UseFileServer(enableDirectoryBrowsing: true);

app.UseRouting();

app.UseAuthorization();

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

Pertimbangkan hierarki direktori berikut:

  • wwwroot
    • css
    • images
    • js
  • MyStaticFiles
    • images
      • MyImage.jpg
    • default.html

Kode berikut memungkinkan penyajian file statis, file default, dan penjelajahan direktori dari MyStaticFiles:

using Microsoft.Extensions.FileProviders;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

builder.Services.AddDirectoryBrowser();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();

app.UseStaticFiles();

app.UseFileServer(new FileServerOptions
{
    FileProvider = new PhysicalFileProvider(
           Path.Combine(builder.Environment.ContentRootPath, "MyStaticFiles")),
    RequestPath = "/StaticFiles",
    EnableDirectoryBrowsing = true
});

app.UseAuthorization();

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

AddDirectoryBrowser harus dipanggil ketika EnableDirectoryBrowsing nilai properti adalah true.

Menggunakan hierarki dan kode file sebelumnya, URL diselesaikan sebagai berikut:

URI Respons
https://<hostname>/StaticFiles/images/MyImage.jpg MyStaticFiles/images/MyImage.jpg
https://<hostname>/StaticFiles MyStaticFiles/default.html

Jika tidak ada file bernama default di direktori MyStaticFiles, https://<hostname>/StaticFiles mengembalikan daftar direktori dengan tautan yang dapat diklik:

Daftar file statis

UseDefaultFiles dan UseDirectoryBrowser lakukan pengalihan sisi klien dari URI target tanpa mengikuti / URI target dengan trailing /. Misalnya, dari https://<hostname>/StaticFiles ke https://<hostname>/StaticFiles/. URL relatif dalam direktori StaticFiles tidak valid tanpa garis miring berikutnya (/) kecuali RedirectToAppendTrailingSlash opsi DefaultFilesOptions digunakan.

FileExtensionContentTypeProvider

Kelas FileExtensionContentTypeProvider berisi Mappings properti yang berfungsi sebagai pemetaan ekstensi file ke jenis konten MIME. Dalam sampel berikut, beberapa ekstensi file dipetakan ke jenis MIME yang diketahui. Ekstensi .rtf diganti, dan .mp4 dihapus:

using Microsoft.AspNetCore.StaticFiles;
using Microsoft.Extensions.FileProviders;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();

// Set up custom content types - associating file extension to MIME type
var provider = new FileExtensionContentTypeProvider();
// Add new mappings
provider.Mappings[".myapp"] = "application/x-msdownload";
provider.Mappings[".htm3"] = "text/html";
provider.Mappings[".image"] = "image/png";
// Replace an existing mapping
provider.Mappings[".rtf"] = "application/x-msdownload";
// Remove MP4 videos.
provider.Mappings.Remove(".mp4");

app.UseStaticFiles(new StaticFileOptions
{
    ContentTypeProvider = provider
});

app.UseAuthorization();

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

Lihat Jenis konten MIME.

Jenis konten non-standar

Middleware File Statis memahami hampir 400 jenis konten file yang diketahui. Jika pengguna meminta file dengan jenis file yang tidak diketahui, Middleware File Statis meneruskan permintaan ke middleware berikutnya dalam alur. Jika tidak ada middleware yang menangani permintaan, respons 404 Tidak Ditemukan dikembalikan. Jika penjelajahan direktori diaktifkan, tautan ke file ditampilkan dalam daftar direktori.

Kode berikut memungkinkan penyajian jenis yang tidak diketahui dan merender file yang tidak diketahui sebagai gambar:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();

app.UseStaticFiles(new StaticFileOptions
{
    ServeUnknownFileTypes = true,
    DefaultContentType = "image/png"
});

app.UseAuthorization();

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

Dengan kode sebelumnya, permintaan untuk file dengan jenis konten yang tidak diketahui dikembalikan sebagai gambar.

Peringatan

Mengaktifkan ServeUnknownFileTypes adalah risiko keamanan. Ini dinonaktifkan secara default, dan penggunaannya tidak disarankan. FileExtensionContentTypeProvider menyediakan alternatif yang lebih aman untuk melayani file dengan ekstensi non-standar.

Menyajikan file dari beberapa lokasi

Pertimbangkan halaman berikut Razor yang menampilkan /MyStaticFiles/image3.png file:

@page

<p> Test /MyStaticFiles/image3.png</p>

<img src="~/image3.png" class="img" asp-append-version="true" alt="Test">

UseStaticFiles dan UseFileServer default ke penyedia file yang menunjuk ke wwwroot. Instans tambahan dan UseStaticFilesUseFileServer dapat disediakan dengan penyedia file lain untuk melayani file dari lokasi lain. Contoh berikut memanggil UseStaticFiles dua kali untuk melayani file dari dan wwwrootMyStaticFiles:

app.UseStaticFiles(); // Serve files from wwwroot
app.UseStaticFiles(new StaticFileOptions
{
    FileProvider = new PhysicalFileProvider(
        Path.Combine(builder.Environment.ContentRootPath, "MyStaticFiles"))
});

Menggunakan kode sebelumnya:

  • File /MyStaticFiles/image3.png ditampilkan.
  • Pembantu AppendVersionTag Gambar tidak diterapkan karena Pembantu Tag bergantung pada WebRootFileProvider. WebRootFileProvider belum diperbarui untuk menyertakan MyStaticFiles folder.

Kode berikut memperbarui WebRootFileProvider, yang memungkinkan Pembantu Tag Gambar untuk menyediakan versi:

var webRootProvider = new PhysicalFileProvider(builder.Environment.WebRootPath);
var newPathProvider = new PhysicalFileProvider(
  Path.Combine(builder.Environment.ContentRootPath, "MyStaticFiles"));

var compositeProvider = new CompositeFileProvider(webRootProvider,
                                                  newPathProvider);

// Update the default provider.
app.Environment.WebRootFileProvider = compositeProvider;

app.UseStaticFiles();

Pertimbangan keamanan untuk file statis

Peringatan

UseDirectoryBrowser dan UseStaticFiles dapat membocorkan rahasia. Menonaktifkan penjelajahan direktori dalam produksi sangat disarankan. Tinjau direktori mana yang diaktifkan dengan hati-hati melalui UseStaticFiles atau UseDirectoryBrowser. Seluruh direktori dan sub-direktorinya dapat diakses secara publik. Simpan file yang cocok untuk dilayani ke publik di direktori khusus, seperti <content_root>/wwwroot. Pisahkan file-file ini dari tampilan MVC, Razor Halaman, file konfigurasi, dll.

  • URL untuk konten yang diekspos dengan UseDirectoryBrowser dan UseStaticFiles tunduk pada sensitivitas kasus dan pembatasan karakter dari sistem file yang mendasar. Misalnya, Windows tidak peka huruf besar/kecil, tetapi macOS dan Linux tidak.

  • ASP.NET aplikasi Core yang dihosting di IIS menggunakan Modul Inti ASP.NET untuk meneruskan semua permintaan ke aplikasi, termasuk permintaan file statis. Handler file statis IIS tidak digunakan dan tidak memiliki kesempatan untuk menangani permintaan.

  • Selesaikan langkah-langkah berikut di Manajer IIS untuk menghapus handler file statis IIS di tingkat server atau situs web:

    1. Navigasi ke fitur Modul .
    2. Pilih StaticFileModule dalam daftar.
    3. Klik Hapus di bilah samping Tindakan .

Peringatan

Jika handler file statis IIS diaktifkan dan ASP.NET Core Module dikonfigurasi dengan salah, file statis dilayani. Ini terjadi, misalnya, jika file web.config tidak disebarkan.

  • Tempatkan file kode, termasuk .cs dan .cshtml, di luar akar web proyek aplikasi. Oleh karena itu, pemisahan logis dibuat antara konten sisi klien aplikasi dan kode berbasis server. Ini mencegah kode sisi server bocor.

Melayani file di luar wwwroot dengan memperbarui IWebHostEnvironment.WebRootPath

Kapan IWebHostEnvironment.WebRootPath diatur ke folder selain wwwroot:

  • Di lingkungan pengembangan, aset statis yang ditemukan di keduanya wwwroot dan yang diperbarui IWebHostEnvironment.WebRootPath disajikan dari wwwroot.
  • Di lingkungan apa pun selain pengembangan, aset statis duplikat disajikan dari folder yang diperbarui IWebHostEnvironment.WebRootPath .

Pertimbangkan aplikasi web yang dibuat dengan templat web kosong:

  • Berisi Index.html file di wwwroot dan wwwroot-custom.

  • Dengan file yang diperbarui Program.cs berikut yang menetapkan WebRootPath = "wwwroot-custom":

    var builder = WebApplication.CreateBuilder(new WebApplicationOptions
    {
        Args = args,
        // Look for static files in "wwwroot-custom"
        WebRootPath = "wwwroot-custom"
    });
    
    var app = builder.Build();
    
    app.UseDefaultFiles();
    app.UseStaticFiles();
    
    app.Run();
    

Dalam kode sebelumnya, permintaan ke /:

  • Dalam pengembalian lingkungan pengembangan wwwroot/Index.html
  • Di lingkungan apa pun selain pengembalian pengembangan wwwroot-custom/Index.html

Untuk memastikan aset dari wwwroot-custom dikembalikan, gunakan salah satu pendekatan berikut:

  • Hapus aset bernama duplikat di wwwroot.

  • Atur "ASPNETCORE_ENVIRONMENT" ke nilai apa pun selain "Development".Properties/launchSettings.json

  • Nonaktifkan aset web statis sepenuhnya dengan mengatur <StaticWebAssetsEnabled>false</StaticWebAssetsEnabled> dalam file proyek. PERINGATAN, menonaktifkan aset web statis menonaktifkan Razor Pustaka Kelas.

  • Tambahkan ON berikut JSke file proyek:

    <ItemGroup>
        <Content Remove="wwwroot\**" />
    </ItemGroup>
    

Kode berikut diperbarui IWebHostEnvironment.WebRootPath ke nilai non pengembangan, menjamin konten duplikat dikembalikan dari wwwroot-custom bukan wwwroot:

var builder = WebApplication.CreateBuilder(new WebApplicationOptions
{
    Args = args,
    // Examine Hosting environment: logging value
    EnvironmentName = Environments.Staging,
    WebRootPath = "wwwroot-custom"
});

var app = builder.Build();

app.Logger.LogInformation("ASPNETCORE_ENVIRONMENT: {env}",
      Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT"));

app.Logger.LogInformation("app.Environment.IsDevelopment(): {env}",
      app.Environment.IsDevelopment().ToString());

app.UseDefaultFiles();
app.UseStaticFiles();

app.Run();

Sumber Daya Tambahan:

Oleh Rick Anderson dan Kirk Larkin

File statis, seperti HTML, CSS, gambar, dan JavaScript, adalah aset aplikasi ASP.NET Core berfungsi langsung ke klien secara default.

Sajikan file statis

File statis disimpan dalam direktori akar web proyek. Direktori default adalah {content root}/wwwroot, tetapi dapat diubah dengan UseWebRoot metode . Untuk informasi selengkapnya, lihat Akar konten dan akar Web.

Metode CreateBuilder ini mengatur akar konten ke direktori saat ini:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseAuthorization();

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

File statis dapat diakses melalui jalur yang relatif terhadap akar web. Misalnya, templat proyek Aplikasi Web berisi beberapa folder dalam wwwroot folder:

  • wwwroot
    • css
    • js
    • lib

Pertimbangkan untuk membuat folder wwwroot/images dan menambahkan wwwroot/images/MyImage.jpg file. Format URI untuk mengakses file di images folder adalah https://<hostname>/images/<image_file_name>. Misalnya: https://localhost:5001/images/MyImage.jpg

Menyajikan file di akar web

Templat aplikasi web default memanggil UseStaticFiles metode di Program.cs, yang memungkinkan file statis dilayani:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseAuthorization();

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

Overload metode tanpa UseStaticFiles parameter menandai file di akar web sebagai servable. Referensi wwwroot/images/MyImage.jpgmarkup berikut :

<img src="~/images/MyImage.jpg" class="img" alt="My image" />

Dalam markup sebelumnya, karakter ~ tilde menunjuk ke akar web.

Menyajikan file di luar akar web

Pertimbangkan hierarki direktori tempat file statis untuk dilayani berada di luar akar web:

  • wwwroot
    • css
    • images
    • js
  • MyStaticFiles
    • images
      • red-rose.jpg

Permintaan dapat mengakses red-rose.jpg file dengan mengonfigurasi Middleware File Statis sebagai berikut:

using Microsoft.Extensions.FileProviders;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();

app.UseStaticFiles(new StaticFileOptions
{
    FileProvider = new PhysicalFileProvider(
           Path.Combine(builder.Environment.ContentRootPath, "MyStaticFiles")),
    RequestPath = "/StaticFiles"
});

app.UseAuthorization();

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

Dalam kode sebelumnya, hierarki direktori MyStaticFiles diekspos secara publik melalui segmen URI StaticFiles . Permintaan untuk https://<hostname>/StaticFiles/images/red-rose.jpg melayani red-rose.jpg file.

Referensi MyStaticFiles/images/red-rose.jpgmarkup berikut :

<img src="~/StaticFiles/images/red-rose.jpg" class="img" alt="A red rose" />

Untuk menyajikan file dari beberapa lokasi, lihat Menyajikan file dari beberapa lokasi.

Mengatur header respons HTTP

Objek StaticFileOptions dapat digunakan untuk mengatur header respons HTTP. Selain mengonfigurasi penyajian file statis dari akar web, kode berikut mengatur header Cache-Control :

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();

var cacheMaxAgeOneWeek = (60 * 60 * 24 * 7).ToString();
app.UseStaticFiles(new StaticFileOptions
{
    OnPrepareResponse = ctx =>
    {
        ctx.Context.Response.Headers.Append(
             "Cache-Control", $"public, max-age={cacheMaxAgeOneWeek}");
    }
});

app.UseAuthorization();

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

Kode sebelumnya membuat file statis tersedia untuk umum di cache lokal selama satu minggu (604800 detik).

Otorisasi file statis

Templat ASP.NET Core memanggil UseStaticFiles sebelum memanggil UseAuthorization. Sebagian besar aplikasi mengikuti pola ini. Ketika Middleware File Statis dipanggil sebelum middleware otorisasi:

  • Tidak ada pemeriksaan otorisasi yang dilakukan pada file statis.
  • File statis yang dilayani oleh Middleware File Statis, seperti file di bawah wwwroot, dapat diakses secara publik.

Untuk menyajikan file statis berdasarkan otorisasi:

  • Simpan di luar wwwroot.
  • Panggil UseStaticFiles, menentukan jalur, setelah memanggil UseAuthorization.
  • Atur kebijakan otorisasi fallback.
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.FileProviders;
using StaticFileAuth.Data;

var builder = WebApplication.CreateBuilder(args);

var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
builder.Services.AddDbContext<ApplicationDbContext>(options =>
    options.UseSqlServer(connectionString));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();

builder.Services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
    .AddEntityFrameworkStores<ApplicationDbContext>();
builder.Services.AddRazorPages();

builder.Services.AddAuthorization(options =>
{
    options.FallbackPolicy = new AuthorizationPolicyBuilder()
        .RequireAuthenticatedUser()
        .Build();
});

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.UseMigrationsEndPoint();
}
else
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();

app.UseAuthentication();
app.UseAuthorization();

app.UseStaticFiles(new StaticFileOptions
{
    FileProvider = new PhysicalFileProvider(
           Path.Combine(builder.Environment.ContentRootPath, "MyStaticFiles")),
    RequestPath = "/StaticFiles"
});

app.MapRazorPages();

app.Run();

Dalam kode sebelumnya, kebijakan otorisasi fallback mengharuskan semua pengguna diautentikasi. Titik akhir seperti pengontrol, Razor Halaman, dll yang menentukan persyaratan otorisasi mereka sendiri tidak menggunakan kebijakan otorisasi fallback. Misalnya, Razor Halaman, pengontrol, atau metode tindakan dengan [AllowAnonymous] atau [Authorize(PolicyName="MyPolicy")] menggunakan atribut otorisasi yang diterapkan daripada kebijakan otorisasi fallback.

RequireAuthenticatedUser menambahkan ke instans DenyAnonymousAuthorizationRequirement saat ini, yang memberlakukan bahwa pengguna saat ini diautentikasi.

Aset statis di bawah wwwroot dapat diakses secara publik karena Middleware File Statis default (app.UseStaticFiles();) dipanggil sebelum UseAuthentication. Aset statis di folder MyStaticFiles memerlukan autentikasi. Kode sampel menunjukkan ini.

Pendekatan alternatif untuk melayani file berdasarkan otorisasi adalah dengan:

  • Simpan di luar wwwroot dan direktori apa pun yang dapat diakses oleh Middleware File Statis.
  • Sajikan melalui metode tindakan tempat otorisasi diterapkan dan mengembalikan FileResult objek:
[Authorize]
public class BannerImageModel : PageModel
{
    private readonly IWebHostEnvironment _env;

    public BannerImageModel(IWebHostEnvironment env) =>
        _env = env;

    public PhysicalFileResult OnGet()
    {
        var filePath = Path.Combine(
                _env.ContentRootPath, "MyStaticFiles", "images", "red-rose.jpg");

        return PhysicalFile(filePath, "image/jpeg");
    }
}

Penjelajahan direktori

Penjelajahan direktori memungkinkan daftar direktori dalam direktori tertentu.

Penjelajahan direktori dinonaktifkan secara default karena alasan keamanan. Untuk informasi selengkapnya, lihat Pertimbangan keamanan untuk file statis.

Aktifkan penjelajahan direktori dengan AddDirectoryBrowser dan UseDirectoryBrowser:

using Microsoft.AspNetCore.StaticFiles;
using Microsoft.Extensions.FileProviders;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

builder.Services.AddDirectoryBrowser();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();

app.UseStaticFiles();

var fileProvider = new PhysicalFileProvider(Path.Combine(builder.Environment.WebRootPath, "images"));
var requestPath = "/MyImages";

// Enable displaying browser links.
app.UseStaticFiles(new StaticFileOptions
{
    FileProvider = fileProvider,
    RequestPath = requestPath
});

app.UseDirectoryBrowser(new DirectoryBrowserOptions
{
    FileProvider = fileProvider,
    RequestPath = requestPath
});

app.UseAuthorization();

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

Kode sebelumnya memungkinkan penjelajahan direktori folder wwwroot/images menggunakan URL https://<hostname>/MyImages, dengan tautan ke setiap file dan folder:

penjelajahan direktori

AddDirectoryBrowsermenambahkan layanan yang diperlukan oleh middleware penjelajahan direktori, termasuk HtmlEncoder. Layanan ini dapat ditambahkan oleh panggilan lain, seperti AddRazorPages, tetapi sebaiknya panggil AddDirectoryBrowser untuk memastikan layanan ditambahkan di semua aplikasi.

Melayani dokumen default

Mengatur halaman default memberi pengunjung titik awal di situs. Untuk melayani file default dari wwwroot tanpa memerlukan URL permintaan untuk menyertakan nama file, panggil UseDefaultFiles metode :

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();

app.UseDefaultFiles();

app.UseStaticFiles();
app.UseAuthorization();

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

UseDefaultFiles harus dipanggil sebelumnya UseStaticFiles untuk melayani file default. UseDefaultFiles adalah penulis ulang URL yang tidak melayani file.

Dengan UseDefaultFiles, permintaan ke folder untuk wwwroot mencari:

  • default.htm
  • default.html
  • index.htm
  • index.html

File pertama yang ditemukan dari daftar dilayani seolah-olah permintaan menyertakan nama file. URL browser terus mencerminkan URI yang diminta.

Kode berikut mengubah nama file default menjadi mydefault.html:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();

var options = new DefaultFilesOptions();
options.DefaultFileNames.Clear();
options.DefaultFileNames.Add("mydefault.html");
app.UseDefaultFiles(options);

app.UseStaticFiles();

app.UseAuthorization();

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

UseFileServer untuk dokumen default

UseFileServer menggabungkan fungsionalitas UseStaticFiles, UseDefaultFiles, dan secara UseDirectoryBrowseropsional .

Panggil app.UseFileServer untuk mengaktifkan penyajian file statis dan file default. Penjelajahan direktori tidak diaktifkan:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();

app.UseFileServer();

app.UseAuthorization();

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

Kode berikut memungkinkan penyajian file statis, file default, dan penjelajahan direktori:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

builder.Services.AddDirectoryBrowser();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();

app.UseFileServer(enableDirectoryBrowsing: true);

app.UseRouting();

app.UseAuthorization();

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

Pertimbangkan hierarki direktori berikut:

  • wwwroot
    • css
    • images
    • js
  • MyStaticFiles
    • images
      • MyImage.jpg
    • default.html

Kode berikut memungkinkan penyajian file statis, file default, dan penjelajahan direktori dari MyStaticFiles:

using Microsoft.Extensions.FileProviders;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

builder.Services.AddDirectoryBrowser();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();

app.UseStaticFiles();

app.UseFileServer(new FileServerOptions
{
    FileProvider = new PhysicalFileProvider(
           Path.Combine(builder.Environment.ContentRootPath, "MyStaticFiles")),
    RequestPath = "/StaticFiles",
    EnableDirectoryBrowsing = true
});

app.UseAuthorization();

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

AddDirectoryBrowser harus dipanggil ketika EnableDirectoryBrowsing nilai properti adalah true.

Menggunakan hierarki dan kode file sebelumnya, URL diselesaikan sebagai berikut:

URI Respons
https://<hostname>/StaticFiles/images/MyImage.jpg MyStaticFiles/images/MyImage.jpg
https://<hostname>/StaticFiles MyStaticFiles/default.html

Jika tidak ada file bernama default di direktori MyStaticFiles, https://<hostname>/StaticFiles mengembalikan daftar direktori dengan tautan yang dapat diklik:

Daftar file statis

UseDefaultFiles dan UseDirectoryBrowser lakukan pengalihan sisi klien dari URI target tanpa mengikuti / URI target dengan trailing /. Misalnya, dari https://<hostname>/StaticFiles ke https://<hostname>/StaticFiles/. URL relatif dalam direktori StaticFiles tidak valid tanpa garis miring berikutnya (/) kecuali RedirectToAppendTrailingSlash opsi DefaultFilesOptions digunakan.

FileExtensionContentTypeProvider

Kelas FileExtensionContentTypeProvider berisi Mappings properti yang berfungsi sebagai pemetaan ekstensi file ke jenis konten MIME. Dalam sampel berikut, beberapa ekstensi file dipetakan ke jenis MIME yang diketahui. Ekstensi .rtf diganti, dan .mp4 dihapus:

using Microsoft.AspNetCore.StaticFiles;
using Microsoft.Extensions.FileProviders;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();

// Set up custom content types - associating file extension to MIME type
var provider = new FileExtensionContentTypeProvider();
// Add new mappings
provider.Mappings[".myapp"] = "application/x-msdownload";
provider.Mappings[".htm3"] = "text/html";
provider.Mappings[".image"] = "image/png";
// Replace an existing mapping
provider.Mappings[".rtf"] = "application/x-msdownload";
// Remove MP4 videos.
provider.Mappings.Remove(".mp4");

app.UseStaticFiles(new StaticFileOptions
{
    ContentTypeProvider = provider
});

app.UseAuthorization();

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

Lihat Jenis konten MIME.

Jenis konten non-standar

Middleware File Statis memahami hampir 400 jenis konten file yang diketahui. Jika pengguna meminta file dengan jenis file yang tidak diketahui, Middleware File Statis meneruskan permintaan ke middleware berikutnya dalam alur. Jika tidak ada middleware yang menangani permintaan, respons 404 Tidak Ditemukan dikembalikan. Jika penjelajahan direktori diaktifkan, tautan ke file ditampilkan dalam daftar direktori.

Kode berikut memungkinkan penyajian jenis yang tidak diketahui dan merender file yang tidak diketahui sebagai gambar:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();

app.UseStaticFiles(new StaticFileOptions
{
    ServeUnknownFileTypes = true,
    DefaultContentType = "image/png"
});

app.UseAuthorization();

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

Dengan kode sebelumnya, permintaan untuk file dengan jenis konten yang tidak diketahui dikembalikan sebagai gambar.

Peringatan

Mengaktifkan ServeUnknownFileTypes adalah risiko keamanan. Ini dinonaktifkan secara default, dan penggunaannya tidak disarankan. FileExtensionContentTypeProvider menyediakan alternatif yang lebih aman untuk melayani file dengan ekstensi non-standar.

Menyajikan file dari beberapa lokasi

Pertimbangkan halaman berikut Razor yang menampilkan /MyStaticFiles/image3.png file:

@page

<p> Test /MyStaticFiles/image3.png</p>

<img src="~/image3.png" class="img" asp-append-version="true" alt="Test">

UseStaticFiles dan UseFileServer default ke penyedia file yang menunjuk ke wwwroot. Instans tambahan dan UseStaticFilesUseFileServer dapat disediakan dengan penyedia file lain untuk melayani file dari lokasi lain. Contoh berikut memanggil UseStaticFiles dua kali untuk melayani file dari dan wwwrootMyStaticFiles:

app.UseStaticFiles(); // Serve files from wwwroot
app.UseStaticFiles(new StaticFileOptions
{
    FileProvider = new PhysicalFileProvider(
        Path.Combine(builder.Environment.ContentRootPath, "MyStaticFiles"))
});

Menggunakan kode sebelumnya:

  • File /MyStaticFiles/image3.png ditampilkan.
  • Pembantu AppendVersionTag Gambar tidak diterapkan karena Pembantu Tag bergantung pada WebRootFileProvider. WebRootFileProvider belum diperbarui untuk menyertakan MyStaticFiles folder.

Kode berikut memperbarui WebRootFileProvider, yang memungkinkan Pembantu Tag Gambar untuk menyediakan versi:

var webRootProvider = new PhysicalFileProvider(builder.Environment.WebRootPath);
var newPathProvider = new PhysicalFileProvider(
  Path.Combine(builder.Environment.ContentRootPath, "MyStaticFiles"));

var compositeProvider = new CompositeFileProvider(webRootProvider,
                                                  newPathProvider);

// Update the default provider.
app.Environment.WebRootFileProvider = compositeProvider;

app.UseStaticFiles();

Pertimbangan keamanan untuk file statis

Peringatan

UseDirectoryBrowser dan UseStaticFiles dapat membocorkan rahasia. Menonaktifkan penjelajahan direktori dalam produksi sangat disarankan. Tinjau direktori mana yang diaktifkan dengan hati-hati melalui UseStaticFiles atau UseDirectoryBrowser. Seluruh direktori dan sub-direktorinya dapat diakses secara publik. Simpan file yang cocok untuk dilayani ke publik di direktori khusus, seperti <content_root>/wwwroot. Pisahkan file-file ini dari tampilan MVC, Razor Halaman, file konfigurasi, dll.

  • URL untuk konten yang diekspos dengan UseDirectoryBrowser dan UseStaticFiles tunduk pada sensitivitas kasus dan pembatasan karakter dari sistem file yang mendasar. Misalnya, Windows tidak peka huruf besar/kecil, tetapi macOS dan Linux tidak.

  • ASP.NET aplikasi Core yang dihosting di IIS menggunakan Modul Inti ASP.NET untuk meneruskan semua permintaan ke aplikasi, termasuk permintaan file statis. Handler file statis IIS tidak digunakan dan tidak memiliki kesempatan untuk menangani permintaan.

  • Selesaikan langkah-langkah berikut di Manajer IIS untuk menghapus handler file statis IIS di tingkat server atau situs web:

    1. Navigasi ke fitur Modul .
    2. Pilih StaticFileModule dalam daftar.
    3. Klik Hapus di bilah samping Tindakan .

Peringatan

Jika handler file statis IIS diaktifkan dan ASP.NET Core Module dikonfigurasi dengan salah, file statis dilayani. Ini terjadi, misalnya, jika file web.config tidak disebarkan.

  • Tempatkan file kode, termasuk .cs dan .cshtml, di luar akar web proyek aplikasi. Oleh karena itu, pemisahan logis dibuat antara konten sisi klien aplikasi dan kode berbasis server. Ini mencegah kode sisi server bocor.

Melayani file di luar wwwroot dengan memperbarui IWebHostEnvironment.WebRootPath

Kapan IWebHostEnvironment.WebRootPath diatur ke folder selain wwwroot:

  • Di lingkungan pengembangan, aset statis yang ditemukan di keduanya wwwroot dan yang diperbarui IWebHostEnvironment.WebRootPath disajikan dari wwwroot.
  • Di lingkungan apa pun selain pengembangan, aset statis duplikat disajikan dari folder yang diperbarui IWebHostEnvironment.WebRootPath .

Pertimbangkan aplikasi web yang dibuat dengan templat web kosong:

  • Berisi Index.html file di wwwroot dan wwwroot-custom.

  • Dengan file yang diperbarui Program.cs berikut yang menetapkan WebRootPath = "wwwroot-custom":

    var builder = WebApplication.CreateBuilder(new WebApplicationOptions
    {
        Args = args,
        // Look for static files in "wwwroot-custom"
        WebRootPath = "wwwroot-custom"
    });
    
    var app = builder.Build();
    
    app.UseDefaultFiles();
    app.UseStaticFiles();
    
    app.Run();
    

Dalam kode sebelumnya, permintaan ke /:

  • Dalam pengembalian lingkungan pengembangan wwwroot/Index.html
  • Di lingkungan apa pun selain pengembalian pengembangan wwwroot-custom/Index.html

Untuk memastikan aset dari wwwroot-custom dikembalikan, gunakan salah satu pendekatan berikut:

  • Hapus aset bernama duplikat di wwwroot.

  • Atur "ASPNETCORE_ENVIRONMENT" ke nilai apa pun selain "Development".Properties/launchSettings.json

  • Nonaktifkan aset web statis sepenuhnya dengan mengatur <StaticWebAssetsEnabled>false</StaticWebAssetsEnabled> dalam file proyek. PERINGATAN, menonaktifkan aset web statis menonaktifkan Razor Pustaka Kelas.

  • Tambahkan ON berikut JSke file proyek:

    <ItemGroup>
        <Content Remove="wwwroot\**" />
    </ItemGroup>
    

Kode berikut diperbarui IWebHostEnvironment.WebRootPath ke nilai non pengembangan, menjamin konten duplikat dikembalikan dari wwwroot-custom bukan wwwroot:

var builder = WebApplication.CreateBuilder(new WebApplicationOptions
{
    Args = args,
    // Examine Hosting environment: logging value
    EnvironmentName = Environments.Staging,
    WebRootPath = "wwwroot-custom"
});

var app = builder.Build();

app.Logger.LogInformation("ASPNETCORE_ENVIRONMENT: {env}",
      Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT"));

app.Logger.LogInformation("app.Environment.IsDevelopment(): {env}",
      app.Environment.IsDevelopment().ToString());

app.UseDefaultFiles();
app.UseStaticFiles();

app.Run();

Sumber Daya Tambahan:

Oleh Rick Anderson dan Kirk Larkin

File statis, seperti HTML, CSS, gambar, dan JavaScript, adalah aset aplikasi ASP.NET Core berfungsi langsung ke klien secara default.

Melihat atau mengunduh kode sampel (cara mengunduh)

Sajikan file statis

File statis disimpan dalam direktori akar web proyek. Direktori default adalah {content root}/wwwroot, tetapi dapat diubah dengan UseWebRoot metode . Untuk informasi selengkapnya, lihat Akar konten dan akar Web.

Metode CreateDefaultBuilder ini mengatur akar konten ke direktori saat ini:

public class Program
{
    public static void Main(string[] args)
    {
        CreateHostBuilder(args).Build().Run();
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            });
}

Kode sebelumnya dibuat dengan templat aplikasi web.

File statis dapat diakses melalui jalur yang relatif terhadap akar web. Misalnya, templat proyek Aplikasi Web berisi beberapa folder dalam wwwroot folder:

  • wwwroot
    • css
    • js
    • lib

Pertimbangkan untuk membuat folder wwwroot/images dan menambahkan wwwroot/images/MyImage.jpg file. Format URI untuk mengakses file di images folder adalah https://<hostname>/images/<image_file_name>. Misalnya: https://localhost:5001/images/MyImage.jpg

Menyajikan file di akar web

Templat aplikasi web default memanggil UseStaticFiles metode di Startup.Configure, yang memungkinkan file statis dilayani:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
        app.UseHsts();
    }

    app.UseHttpsRedirection();

    app.UseStaticFiles();

    app.UseRouting();

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapDefaultControllerRoute();
    });
}

Overload metode tanpa UseStaticFiles parameter menandai file di akar web sebagai servable. Referensi wwwroot/images/MyImage.jpgmarkup berikut :

<img src="~/images/MyImage.jpg" class="img" alt="My image" />

Dalam kode sebelumnya, karakter ~/ tilde menunjuk ke akar web.

Menyajikan file di luar akar web

Pertimbangkan hierarki direktori tempat file statis untuk dilayani berada di luar akar web:

  • wwwroot
    • css
    • images
    • js
  • MyStaticFiles
    • images
      • red-rose.jpg

Permintaan dapat mengakses red-rose.jpg file dengan mengonfigurasi Middleware File Statis sebagai berikut:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
        app.UseHsts();
    }

    app.UseHttpsRedirection();

    // using Microsoft.Extensions.FileProviders;
    // using System.IO;
    app.UseStaticFiles(new StaticFileOptions
    {
        FileProvider = new PhysicalFileProvider(
            Path.Combine(env.ContentRootPath, "MyStaticFiles")),
        RequestPath = "/StaticFiles"
    });

    app.UseRouting();

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapDefaultControllerRoute();
    });
}

Dalam kode sebelumnya, hierarki direktori MyStaticFiles diekspos secara publik melalui segmen URI StaticFiles . Permintaan untuk https://<hostname>/StaticFiles/images/red-rose.jpg melayani red-rose.jpg file.

Referensi MyStaticFiles/images/red-rose.jpgmarkup berikut :

<img src="~/StaticFiles/images/red-rose.jpg" class="img" alt="A red rose" />

Mengatur header respons HTTP

Objek StaticFileOptions dapat digunakan untuk mengatur header respons HTTP. Selain mengonfigurasi penyajian file statis dari akar web, kode berikut mengatur Cache-Control header:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
        app.UseHsts();
    }

    app.UseHttpsRedirection();

    const string cacheMaxAge = "604800";
    app.UseStaticFiles(new StaticFileOptions
    {
        OnPrepareResponse = ctx =>
        {
            // using Microsoft.AspNetCore.Http;
            ctx.Context.Response.Headers.Append(
                 "Cache-Control", $"public, max-age={cacheMaxAge}");
        }
    });

    app.UseRouting();

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapDefaultControllerRoute();
    });
}

Kode sebelumnya menetapkan usia maksimal hingga 604800 detik (7 hari).

Header respons memperlihatkan header Cache-Control telah ditambahkan

Otorisasi file statis

Templat ASP.NET Core memanggil UseStaticFiles sebelum memanggil UseAuthorization. Sebagian besar aplikasi mengikuti pola ini. Ketika Middleware File Statis dipanggil sebelum middleware otorisasi:

  • Tidak ada pemeriksaan otorisasi yang dilakukan pada file statis.
  • File statis yang dilayani oleh Middleware File Statis, seperti file di bawah wwwroot, dapat diakses secara publik.

Untuk menyajikan file statis berdasarkan otorisasi:

  • Simpan di luar wwwroot.
  • Panggil UseStaticFiles, menentukan jalur, setelah memanggil UseAuthorization.
  • Atur kebijakan otorisasi fallback.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
        app.UseDatabaseErrorPage();
    }
    else
    {
        app.UseExceptionHandler("/Error");
        app.UseHsts();
    }

    app.UseHttpsRedirection();

    // wwwroot css, JavaScript, and images don't require authentication.
    app.UseStaticFiles();   

    app.UseRouting();

    app.UseAuthentication();
    app.UseAuthorization();

    app.UseStaticFiles(new StaticFileOptions
    {
        FileProvider = new PhysicalFileProvider(
                     Path.Combine(env.ContentRootPath, "MyStaticFiles")),
        RequestPath = "/StaticFiles"
    });

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapRazorPages();
    });
}
public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddDbContext<ApplicationDbContext>(options =>
            options.UseSqlServer(
                Configuration.GetConnectionString("DefaultConnection")));
        services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
            .AddEntityFrameworkStores<ApplicationDbContext>();

        services.AddRazorPages();

        services.AddAuthorization(options =>
        {
            options.FallbackPolicy = new AuthorizationPolicyBuilder()
                .RequireAuthenticatedUser()
                .Build();
        });
    }

    // Remaining code ommitted for brevity.

Dalam kode sebelumnya, kebijakan otorisasi fallback mengharuskan semua pengguna diautentikasi. Titik akhir seperti pengontrol, Razor Halaman, dll yang menentukan persyaratan otorisasi mereka sendiri tidak menggunakan kebijakan otorisasi fallback. Misalnya, Razor Halaman, pengontrol, atau metode tindakan dengan [AllowAnonymous] atau [Authorize(PolicyName="MyPolicy")] menggunakan atribut otorisasi yang diterapkan daripada kebijakan otorisasi fallback.

RequireAuthenticatedUser menambahkan ke instans DenyAnonymousAuthorizationRequirement saat ini, yang memberlakukan bahwa pengguna saat ini diautentikasi.

Aset statis di bawah wwwroot dapat diakses secara publik karena Middleware File Statis default (app.UseStaticFiles();) dipanggil sebelum UseAuthentication. Aset statis di folder MyStaticFiles memerlukan autentikasi. Kode sampel menunjukkan ini.

Pendekatan alternatif untuk melayani file berdasarkan otorisasi adalah dengan:

  • Simpan di luar wwwroot dan direktori apa pun yang dapat diakses oleh Middleware File Statis.
  • Sajikan melalui metode tindakan tempat otorisasi diterapkan dan mengembalikan FileResult objek:
[Authorize]
public IActionResult BannerImage()
{
    var filePath = Path.Combine(
        _env.ContentRootPath, "MyStaticFiles", "images", "red-rose.jpg");

    return PhysicalFile(filePath, "image/jpeg");
}

Penjelajahan direktori

Penjelajahan direktori memungkinkan daftar direktori dalam direktori tertentu.

Penjelajahan direktori dinonaktifkan secara default karena alasan keamanan. Untuk informasi selengkapnya, lihat Pertimbangan keamanan untuk file statis.

Aktifkan penjelajahan direktori dengan:

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllersWithViews();
    services.AddDirectoryBrowser();
}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
        app.UseHsts();
    }

    app.UseHttpsRedirection();

    // using Microsoft.Extensions.FileProviders;
    // using System.IO;
    app.UseStaticFiles(new StaticFileOptions
    {
        FileProvider = new PhysicalFileProvider(
            Path.Combine(env.WebRootPath, "images")),
        RequestPath = "/MyImages"
    });

    app.UseDirectoryBrowser(new DirectoryBrowserOptions
    {
        FileProvider = new PhysicalFileProvider(
            Path.Combine(env.WebRootPath, "images")),
        RequestPath = "/MyImages"
    });

    app.UseRouting();

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapDefaultControllerRoute();
    });
}

Kode sebelumnya memungkinkan penjelajahan direktori folder wwwroot/images menggunakan URL https://<hostname>/MyImages, dengan tautan ke setiap file dan folder:

penjelajahan direktori

Melayani dokumen default

Mengatur halaman default memberi pengunjung titik awal di situs. Untuk melayani file default dari wwwroot tanpa memerlukan URL permintaan untuk menyertakan nama file, panggil UseDefaultFiles metode :

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
        app.UseHsts();
    }

    app.UseHttpsRedirection();

    app.UseDefaultFiles();
    app.UseStaticFiles();

    app.UseRouting();

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapDefaultControllerRoute();
    });
}

UseDefaultFiles harus dipanggil sebelumnya UseStaticFiles untuk melayani file default. UseDefaultFiles adalah penulis ulang URL yang tidak melayani file.

Dengan UseDefaultFiles, permintaan ke folder untuk wwwroot mencari:

  • default.htm
  • default.html
  • index.htm
  • index.html

File pertama yang ditemukan dari daftar dilayani seolah-olah permintaan menyertakan nama file. URL browser terus mencerminkan URI yang diminta.

Kode berikut mengubah nama file default menjadi mydefault.html:

var options = new DefaultFilesOptions();
options.DefaultFileNames.Clear();
options.DefaultFileNames.Add("mydefault.html");
app.UseDefaultFiles(options);
app.UseStaticFiles();

Kode berikut menunjukkan Startup.Configure dengan kode sebelumnya:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
        app.UseHsts();
    }

    app.UseHttpsRedirection();

    var options = new DefaultFilesOptions();
    options.DefaultFileNames.Clear();
    options.DefaultFileNames.Add("mydefault.html");
    app.UseDefaultFiles(options);
    app.UseStaticFiles();

    app.UseRouting();

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapDefaultControllerRoute();
    });
}

UseFileServer untuk dokumen default

UseFileServer menggabungkan fungsionalitas UseStaticFiles, UseDefaultFiles, dan secara UseDirectoryBrowseropsional .

Panggil app.UseFileServer untuk mengaktifkan penyajian file statis dan file default. Penjelajahan direktori tidak diaktifkan. Kode berikut menunjukkan Startup.Configure dengan UseFileServer:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
        app.UseHsts();
    }

    app.UseHttpsRedirection();

    app.UseFileServer();

    app.UseRouting();

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapDefaultControllerRoute();
    });
}

Kode berikut memungkinkan penyajian file statis, file default, dan penjelajahan direktori:

app.UseFileServer(enableDirectoryBrowsing: true);

Kode berikut menunjukkan Startup.Configure dengan kode sebelumnya:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
        app.UseHsts();
    }

    app.UseHttpsRedirection();

    app.UseFileServer(enableDirectoryBrowsing: true);

    app.UseRouting();

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapDefaultControllerRoute();
    });
}

Pertimbangkan hierarki direktori berikut:

  • wwwroot
    • css
    • images
    • js
  • MyStaticFiles
    • images
      • MyImage.jpg
    • default.html

Kode berikut memungkinkan penyajian file statis, file default, dan penjelajahan direktori dari MyStaticFiles:

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllersWithViews();
    services.AddDirectoryBrowser();
}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
        app.UseHsts();
    }

    app.UseHttpsRedirection();

    app.UseStaticFiles(); // For the wwwroot folder.

    // using Microsoft.Extensions.FileProviders;
    // using System.IO;
    app.UseFileServer(new FileServerOptions
    {
        FileProvider = new PhysicalFileProvider(
            Path.Combine(env.ContentRootPath, "MyStaticFiles")),
        RequestPath = "/StaticFiles",
        EnableDirectoryBrowsing = true
    });

    app.UseRouting();

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapDefaultControllerRoute();
    });
}

AddDirectoryBrowser harus dipanggil ketika EnableDirectoryBrowsing nilai properti adalah true.

Menggunakan hierarki file dan kode sebelumnya, URL diselesaikan sebagai berikut:

URI Respons
https://<hostname>/StaticFiles/images/MyImage.jpg MyStaticFiles/images/MyImage.jpg
https://<hostname>/StaticFiles MyStaticFiles/default.html

Jika tidak ada file bernama default di direktori MyStaticFiles, https://<hostname>/StaticFiles mengembalikan daftar direktori dengan tautan yang dapat diklik:

Daftar file statis

UseDefaultFiles dan UseDirectoryBrowser lakukan pengalihan sisi klien dari URI target tanpa mengikuti / URI target dengan trailing /. Misalnya, dari https://<hostname>/StaticFiles ke https://<hostname>/StaticFiles/. URL relatif dalam direktori StaticFiles tidak valid tanpa garis miring berikutnya (/).

FileExtensionContentTypeProvider

Kelas FileExtensionContentTypeProvider berisi Mappings properti yang berfungsi sebagai pemetaan ekstensi file ke jenis konten MIME. Dalam sampel berikut, beberapa ekstensi file dipetakan ke jenis MIME yang diketahui. Ekstensi .rtf diganti, dan .mp4 dihapus:

// using Microsoft.AspNetCore.StaticFiles;
// using Microsoft.Extensions.FileProviders;
// using System.IO;

// Set up custom content types - associating file extension to MIME type
var provider = new FileExtensionContentTypeProvider();
// Add new mappings
provider.Mappings[".myapp"] = "application/x-msdownload";
provider.Mappings[".htm3"] = "text/html";
provider.Mappings[".image"] = "image/png";
// Replace an existing mapping
provider.Mappings[".rtf"] = "application/x-msdownload";
// Remove MP4 videos.
provider.Mappings.Remove(".mp4");

app.UseStaticFiles(new StaticFileOptions
{
    FileProvider = new PhysicalFileProvider(
        Path.Combine(env.WebRootPath, "images")),
    RequestPath = "/MyImages",
    ContentTypeProvider = provider
});

app.UseDirectoryBrowser(new DirectoryBrowserOptions
{
    FileProvider = new PhysicalFileProvider(
        Path.Combine(env.WebRootPath, "images")),
    RequestPath = "/MyImages"
});

Kode berikut menunjukkan Startup.Configure dengan kode sebelumnya:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
        app.UseHsts();
    }

    app.UseHttpsRedirection();

    // using Microsoft.AspNetCore.StaticFiles;
    // using Microsoft.Extensions.FileProviders;
    // using System.IO;

    // Set up custom content types - associating file extension to MIME type
    var provider = new FileExtensionContentTypeProvider();
    // Add new mappings
    provider.Mappings[".myapp"] = "application/x-msdownload";
    provider.Mappings[".htm3"] = "text/html";
    provider.Mappings[".image"] = "image/png";
    // Replace an existing mapping
    provider.Mappings[".rtf"] = "application/x-msdownload";
    // Remove MP4 videos.
    provider.Mappings.Remove(".mp4");

    app.UseStaticFiles(new StaticFileOptions
    {
        FileProvider = new PhysicalFileProvider(
            Path.Combine(env.WebRootPath, "images")),
        RequestPath = "/MyImages",
        ContentTypeProvider = provider
    });

    app.UseDirectoryBrowser(new DirectoryBrowserOptions
    {
        FileProvider = new PhysicalFileProvider(
            Path.Combine(env.WebRootPath, "images")),
        RequestPath = "/MyImages"
    });

    app.UseRouting();

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapDefaultControllerRoute();
    });
}

Lihat Jenis konten MIME.

Jenis konten non-standar

Middleware File Statis memahami hampir 400 jenis konten file yang diketahui. Jika pengguna meminta file dengan jenis file yang tidak diketahui, Middleware File Statis meneruskan permintaan ke middleware berikutnya dalam alur. Jika tidak ada middleware yang menangani permintaan, respons 404 Tidak Ditemukan dikembalikan. Jika penjelajahan direktori diaktifkan, tautan ke file ditampilkan dalam daftar direktori.

Kode berikut memungkinkan penyajian jenis yang tidak diketahui dan merender file yang tidak diketahui sebagai gambar:

app.UseStaticFiles(new StaticFileOptions
{
    ServeUnknownFileTypes = true,
    DefaultContentType = "image/png"
});

Kode berikut menunjukkan Startup.Configure dengan kode sebelumnya:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
        app.UseHsts();
    }

    app.UseHttpsRedirection();

    app.UseStaticFiles(new StaticFileOptions
    {
        ServeUnknownFileTypes = true,
        DefaultContentType = "image/png"
    });

    app.UseRouting();

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapDefaultControllerRoute();
    });
}

Dengan kode sebelumnya, permintaan untuk file dengan jenis konten yang tidak diketahui dikembalikan sebagai gambar.

Peringatan

Mengaktifkan ServeUnknownFileTypes adalah risiko keamanan. Ini dinonaktifkan secara default, dan penggunaannya tidak disarankan. FileExtensionContentTypeProvider menyediakan alternatif yang lebih aman untuk melayani file dengan ekstensi non-standar.

Menyajikan file dari beberapa lokasi

UseStaticFiles dan UseFileServer default ke penyedia file yang menunjuk ke wwwroot. Instans tambahan dan UseStaticFilesUseFileServer dapat disediakan dengan penyedia file lain untuk melayani file dari lokasi lain. Untuk informasi lebih lanjut, lihat masalah GitHub ini.

Pertimbangan keamanan untuk file statis

Peringatan

UseDirectoryBrowser dan UseStaticFiles dapat membocorkan rahasia. Menonaktifkan penjelajahan direktori dalam produksi sangat disarankan. Tinjau direktori mana yang diaktifkan dengan hati-hati melalui UseStaticFiles atau UseDirectoryBrowser. Seluruh direktori dan sub-direktorinya dapat diakses secara publik. Simpan file yang cocok untuk dilayani ke publik di direktori khusus, seperti <content_root>/wwwroot. Pisahkan file-file ini dari tampilan MVC, Razor Halaman, file konfigurasi, dll.

  • URL untuk konten yang diekspos dengan UseDirectoryBrowser dan UseStaticFiles tunduk pada sensitivitas kasus dan pembatasan karakter dari sistem file yang mendasar. Misalnya, Windows tidak peka huruf besar/kecil, tetapi macOS dan Linux tidak.

  • ASP.NET aplikasi Core yang dihosting di IIS menggunakan Modul Inti ASP.NET untuk meneruskan semua permintaan ke aplikasi, termasuk permintaan file statis. Handler file statis IIS tidak digunakan dan tidak memiliki kesempatan untuk menangani permintaan.

  • Selesaikan langkah-langkah berikut di Manajer IIS untuk menghapus handler file statis IIS di tingkat server atau situs web:

    1. Navigasi ke fitur Modul .
    2. Pilih StaticFileModule dalam daftar.
    3. Klik Hapus di bilah samping Tindakan .

Peringatan

Jika handler file statis IIS diaktifkan dan ASP.NET Core Module dikonfigurasi dengan salah, file statis dilayani. Ini terjadi, misalnya, jika file web.config tidak disebarkan.

  • Tempatkan file kode, termasuk .cs dan .cshtml, di luar akar web proyek aplikasi. Oleh karena itu, pemisahan logis dibuat antara konten sisi klien aplikasi dan kode berbasis server. Ini mencegah kode sisi server bocor.

Sumber Daya Tambahan: