Archivos estáticos en ASP.NET Core
Nota
Esta no es la versión más reciente de este artículo. Para la versión actual, consulta la versión .NET 8 de este artículo.
Advertencia
Esta versión de ASP.NET Core ya no se admite. Para obtener más información, consulta la Directiva de soporte técnico de .NET y .NET Core. Para la versión actual, consulta la versión .NET 8 de este artículo.
Importante
Esta información hace referencia a un producto en versión preliminar, el cual puede sufrir importantes modificaciones antes de que se publique la versión comercial. Microsoft no proporciona ninguna garantía, expresa o implícita, con respecto a la información proporcionada aquí.
Para la versión actual, consulta la versión .NET 8 de este artículo.
Por Rick Anderson
Los archivos estáticos, como HTML, CSS, imágenes y JavaScript, son activos que una aplicación de ASP.NET Core proporciona directamente a los clientes de forma predeterminada.
Para obtener una guía sobre archivos estáticos de Blazor, que se agregue o reemplace la guía de este artículo, consulta Archivos estáticos de Blazor en ASP.NET Core.
Proporcionar archivos estáticos
Los archivos estáticos se almacenan en el directorio raíz web del proyecto. El directorio predeterminado es {content root}/wwwroot
, pero se puede cambiar con el método UseWebRoot. Para obtener más información, consulta Raíz del contenido y Raíz web.
El método CreateBuilder establece la raíz de contenido en el directorio actual:
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.MapStaticAssets();
app.UseAuthorization();
app.MapDefaultControllerRoute().WithStaticAssets();
app.MapRazorPages().WithStaticAssets();
app.Run();
Se puede acceder a los archivos estáticos a través de una ruta de acceso relativa a la raíz web. Por ejemplo, las plantillas de proyecto Aplicación web contienen varias carpetas dentro de la carpeta wwwroot
:
wwwroot
css
js
lib
Considera la posibilidad de usar una aplicación con el archivo wwwroot/images/MyImage.jpg
. El formato del URI para acceder a un archivo en la carpeta images
es https://<hostname>/images/<image_file_name>
. Por ejemplo: https://localhost:5001/images/MyImage.jpg
MapStaticAssets
La creación de aplicaciones web de rendimiento requiere la optimización de la entrega de recursos al explorador. Entre las posibles optimizaciones se incluyen:
- Servir un recurso determinado una vez hasta que el archivo cambie o el explorador borre su caché. Establecer el encabezado ETag.
- Impedir que el explorador use activos antiguos u obsoletos después de actualizar una aplicación. Establecer el encabezado Última modificación.
- Configurar los encabezados de almacenamiento en caché adecuados.
- Usar middleware de almacenamiento en caché.
- Servir versiones comprimidas de los recursos siempre que sea posible.
- Usar una red CDN para atender los recursos más cerca del usuario.
- Minimizar el tamaño de los recursos servidos al explorador. Esta optimización no incluye la minificación.
MapStaticAssets
es un middleware que ayuda a optimizar la entrega de recursos estáticos en una aplicación. Está diseñado para trabajar con todos los marcos de interfaz de usuario, como Blazor, Razor Pages y MVC.
UseStaticFiles
también proporciona archivos estáticos, pero no proporciona el mismo nivel de optimización que MapStaticAssets
. Para obtener una comparación de UseStaticFiles
y MapStaticAssets
, consulta Optimización de la entrega de recursos web estáticos .
Suministro de archivos en la raíz web
Las plantillas de aplicación web predeterminadas llaman al método MapStaticAssets
en Program.cs
, que permite proporcionar archivos estáticos:
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.MapStaticAssets();
app.UseAuthorization();
app.MapDefaultControllerRoute().WithStaticAssets();
app.MapRazorPages().WithStaticAssets();
app.Run();
La sobrecarga del método UseStaticFiles
sin parámetros marca los archivos en la raíz web como que se pueden proporcionar. El siguiente marcado hace referencia a wwwroot/images/MyImage.jpg
:
<img src="~/images/MyImage.jpg" class="img" alt="My image" />
En el marcado anterior, el carácter de tilde de la ñ ~
apunta a la raíz web.
Proporcionar archivos fuera de la raíz web
Considere una jerarquía de directorios en la que residen fuera de la raíz web los archivos estáticos que se van a proporcionar:
wwwroot
css
images
js
MyStaticFiles
images
red-rose.jpg
Una solicitud puede acceder al archivo red-rose.jpg
configurando el middleware de archivos estáticos como se muestra a continuación:
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(); //Serve files from wwwroot
app.UseStaticFiles(new StaticFileOptions
{
FileProvider = new PhysicalFileProvider(
Path.Combine(builder.Environment.ContentRootPath, "MyStaticFiles")),
RequestPath = "/StaticFiles"
});
app.UseAuthorization();
app.MapDefaultControllerRoute().WithStaticAssets();
app.MapRazorPages().WithStaticAssets();
app.Run();
En el código anterior, la jerarquía del directorio MyStaticFiles se expone públicamente a través del segmento de URI StaticFiles. Una solicitud a https://<hostname>/StaticFiles/images/red-rose.jpg
sirve al archivo red-rose.jpg
.
El siguiente marcado hace referencia a MyStaticFiles/images/red-rose.jpg
:
<img src="~/StaticFiles/images/red-rose.jpg" class="img" alt="A red rose" />
Para entregar archivos desde varias ubicaciones, vea Entrega de archivos desde varias ubicaciones.
Establecer encabezados de respuesta HTTP
Se puede usar un objeto StaticFileOptions para establecer encabezados de respuesta HTTP. Además de configurar el servicio de archivos estáticos desde la raíz web, el código siguiente establece el encabezado 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().WithStaticAssets();
app.MapRazorPages().WithStaticAssets();
app.Run();
El código anterior hace que los archivos estáticos estén disponibles públicamente en la memoria caché local durante una semana.
Autorización de archivos estáticos
Las plantillas de ASP.NET Core llaman a MapStaticAssets
antes de llamar a UseAuthorization. La mayoría de las aplicaciones siguen este patrón. Cuando se llama al middleware de archivos estáticos antes de al middleware de autorización:
- No se realizan comprobaciones de autorización en los archivos estáticos.
- Los archivos estáticos que atiende el middleware de archivos estáticos, como los que están en
wwwroot
, son accesibles públicamente.
Para proporcionar archivos estáticos según su autorización:
- Almacénalos fuera de
wwwroot
. - Llama a
UseStaticFiles
, especificando una ruta de acceso, después de llamar aUseAuthorization
. - Establece la directiva de autorización de reserva.
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();
En el código anterior, la directiva de autorización de reserva requiere que se autentiquen todos los usuarios. Los puntos de conexión como los controladores, Razor Pages, etc. que especifican sus propios requisitos de autorización no usan la directiva de autorización de reserva. Por ejemplo, Razor Pages, controladores o métodos de acción con [AllowAnonymous]
o [Authorize(PolicyName="MyPolicy")]
usan el atributo de autorización aplicado en lugar de la directiva de autorización de reserva.
RequireAuthenticatedUser agrega DenyAnonymousAuthorizationRequirement a la instancia actual, lo que exige que el usuario actual se autentique.
Los recursos estáticos en wwwroot
son accesibles públicamente porque se llama al middleware de archivos estáticos predeterminado (app.UseStaticFiles();
) antes de a UseAuthentication
. Los recursos estáticos de la carpeta MyStaticFiles requieren autenticación. En el código de ejemplo se muestra esto.
Un enfoque alternativo a proporcionar archivos según la autorización es:
Almacénalos fuera de
wwwroot
y cualquier directorio al que el middleware de archivos estáticos tenga acceso.Proporciónalos a través de un método de acción al que se aplica la autorización y devuelva un objeto FileResult:
[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"); } }
El enfoque anterior requiere una página o un punto de conexión por archivo. El código siguiente devuelve archivos o carga archivos para usuarios autenticados:
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");
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. See 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();
IFormFile en el ejemplo anterior usa el búfer de memoria para la carga. Para controlar el streaming de uso de archivos de gran tamaño. Consulta Carga de archivos de gran tamaño con streaming.
Consulta la carpeta StaticFileAuth de GitHub para obtener el ejemplo completo.
Examen de directorios
El examen de directorios permite enumerar directorios dentro de los directorios especificados.
Por motivos de seguridad, el examen de directorios está deshabilitado de forma predeterminada. Para obtener más información, consulta Consideraciones de seguridad para archivos estáticos.
Habilita el examen de directorios con AddDirectoryBrowser y 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.MapStaticAssets();
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().WithStaticAssets();
app.MapRazorPages().WithStaticAssets();
app.Run();
El código anterior permite el examen de directorios de la carpeta wwwroot/images usando la dirección URL https://<hostname>/MyImages
, con vínculos a cada archivo y carpeta:
AddDirectoryBrowser
agrega servicios requeridos por el middleware de examen de directorios, incluido HtmlEncoder. Estos servicios se pueden agregar mediante otras llamadas, como AddRazorPages, pero se recomienda llamar a AddDirectoryBrowser
para asegurarse de que los servicios se agregan en todas las aplicaciones.
Suministro de documentos predeterminados
El establecimiento de una página predeterminada proporciona a los visitantes un punto inicial en un sitio. Para servir un archivo predeterminado desde wwwroot
sin necesidad de que la dirección URL de la solicitud incluya el nombre del archivo, llame al método UseDefaultFiles:
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().WithStaticAssets();
app.MapRazorPages().WithStaticAssets();
app.Run();
Debe llamarse a UseDefaultFiles
antes de a UseStaticFiles
para proporcionar el archivo predeterminado. UseDefaultFiles
es un sistema de reescritura de direcciones URL que no proporciona el archivo.
Con UseDefaultFiles
, las solicitudes a una carpeta en wwwroot
buscan:
default.htm
default.html
index.htm
index.html
El primer archivo que se encuentra en la lista se sirve como si la solicitud incluyera el nombre de archivo. La dirección URL del explorador sigue reflejando el URI solicitado. Por ejemplo, en la aplicación de ejemplo, una solicitud para https://localhost:<port>/def/
atiende default.html
desde wwwroot/def
.
El código siguiente cambia el nombre de archivo predeterminado a 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().WithStaticAssets();
app.MapRazorPages().WithStaticAssets();
app.Run();
UseFileServer para documentos predeterminados
UseFileServer combina la funcionalidad de UseStaticFiles
y UseDefaultFiles
y, opcionalmente, la de UseDirectoryBrowser
.
Llama a app.UseFileServer
para poder proporcionar archivos estáticos y el archivo predeterminado. El examen de directorios no está habilitado:
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().WithStaticAssets();
app.MapRazorPages().WithStaticAssets();
app.Run();
El código siguiente permite proporcionar archivos estáticos, el archivo predeterminado y el examen de directorios:
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().WithStaticAssets();
app.MapRazorPages().WithStaticAssets();
app.Run();
Ten en cuenta la siguiente jerarquía de directorios:
wwwroot
css
images
js
MyStaticFiles
defaultFiles
default.html
image3.png
images
MyImage.jpg
El código siguiente permite proporcionar archivos estáticos, el archivo predeterminado y el examen de directorios de 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().WithStaticAssets();
app.MapRazorPages().WithStaticAssets();
app.Run();
Se debe llamar a AddDirectoryBrowser cuando el valor de la propiedad EnableDirectoryBrowsing
es true
.
Al usar la jerarquía de archivos y el código anteriores, las direcciones URL se resuelven como se indica a continuación:
Identificador URI | Respuesta |
---|---|
https://<hostname>/StaticFiles/images/MyImage.jpg |
MyStaticFiles/images/MyImage.jpg |
https://<hostname>/StaticFiles |
lista de directorios |
https://<hostname>/StaticFiles/defaultFiles |
MyStaticFiles/defaultFiles/default.html |
https://<hostname>/StaticFiles/defaultFiles/image3.png |
MyStaticFiles/defaultFiles//image3.png |
Si no existe ningún archivo con el nombre predeterminado en el directorio MyStaticFiles, https://<hostname>/StaticFiles
devuelve la lista de directorios con vínculos activos:
UseDefaultFiles y UseDirectoryBrowser realizan un redireccionamiento del lado cliente desde el URI de destino sin una /
final hasta el URI de destino una /
final. Por ejemplo, desde https://<hostname>/StaticFiles
hasta https://<hostname>/StaticFiles/
. Las direcciones URL relativas dentro del directorio StaticFiles no son válidas sin una barra diagonal final (/
), a menos que se use la opción RedirectToAppendTrailingSlash de DefaultFilesOptions.
FileExtensionContentTypeProvider
La clase FileExtensionContentTypeProvider contiene una propiedad Mappings que actúa como una asignación de extensiones de archivo para tipos de contenido MIME. En el ejemplo siguiente, se asignan varias extensiones de archivo a los tipos MIME conocidos. Se reemplaza la extensión .rtf y se quita .mp4:
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().WithStaticAssets();
app.MapRazorPages().WithStaticAssets();
app.Run();
Consulta Tipos de contenido MIME.
Tipos de contenido no estándar
El middleware de archivos estáticos entiende casi 400 tipos de contenido de archivo conocidos. Si el usuario solicita un archivo con un tipo de archivo desconocido, el middleware de archivos estáticos pasa la solicitud al siguiente middleware de la canalización. Si ningún middleware se ocupa de la solicitud, se devuelve una respuesta 404 No encontrado. Si se habilita la exploración de directorios, se muestra un vínculo al archivo en una lista de directorios.
El código siguiente permite proporcionar tipos desconocidos y procesa el archivo desconocido como una imagen:
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().WithStaticAssets();
app.MapRazorPages().WithStaticAssets();
app.Run();
Con el código anterior, una solicitud para un archivo con un tipo de contenido desconocido se devuelve como una imagen.
Advertencia
Habilitar ServeUnknownFileTypes supone un riesgo para la seguridad. Está deshabilitado de forma predeterminada y no se recomienda su uso. FileExtensionContentTypeProvider proporciona una alternativa más segura a ofrecer archivos con extensiones no estándar.
Entrega de archivos desde varias ubicaciones
Tenga en cuenta la página Razor siguiente que muestra el archivo /MyStaticFiles/image3.png
:
@page
<p> Test /MyStaticFiles/image3.png</p>
<img src="~/image3.png" class="img" asp-append-version="true" alt="Test">
UseStaticFiles
y UseFileServer
tienen como valor predeterminado el proveedor de archivos que apunta a wwwroot
. Se pueden proporcionar instancias adicionales de UseStaticFiles
y UseFileServer
con otros proveedores de archivos para proporcionar archivos desde otras ubicaciones. En el ejemplo siguiente se llama a UseStaticFiles
dos veces para entregar archivos desde wwwroot
y MyStaticFiles
:
app.UseStaticFiles();
app.UseStaticFiles(new StaticFileOptions
{
FileProvider = new PhysicalFileProvider(
Path.Combine(builder.Environment.ContentRootPath, "MyStaticFiles"))
});
Con el código anterior:
- Se muestra el archivo
/MyStaticFiles/image3.png
. - El AppendVersion Asistentes de etiquetas de imagen no se aplica porque los asistentes de etiquetas dependen de WebRootFileProvider.
WebRootFileProvider
no se ha actualizado para incluir la carpetaMyStaticFiles
.
El código siguiente actualiza WebRootFileProvider
, que permite al asistente de etiquetas de imagen proporcionar una versión:
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.MapStaticAssets();
Nota:
El enfoque anterior se aplica a las aplicaciones de Razor Pages y MVC. Para obtener guías que se aplican a Blazor Web App, consulta Archivos estáticos Blazor de ASP.NET Core.
Consideraciones de seguridad para archivos estáticos
Advertencia
UseDirectoryBrowser
y UseStaticFiles
pueden producir pérdidas de información confidencial. Se recomienda deshabilitar el examen de directorios en producción. Revisa cuidadosamente los directorios que se habilitan mediante UseStaticFiles
o UseDirectoryBrowser
. Todo el directorio y sus subdirectorios pasan a ser accesibles públicamente. Almacena los archivos adecuados para proporcionarlos al público en un directorio dedicado, como <content_root>/wwwroot
. Separa estos archivos de las vistas MVC, de Razor Pages, de los archivos de configuración, etc.
Las direcciones URL para el contenido que se expone a través de
UseDirectoryBrowser
,UseStaticFiles
yMapStaticAssets
están sujetas a la distinción entre mayúsculas y minúsculas, y a restricciones de caracteres del sistema de archivos subyacente. Por ejemplo, Windows no distingue entre mayúsculas y minúsculas, pero macOS y Linux sí.Las aplicaciones de ASP.NET Core hospedadas en IIS usan el módulo de ASP.NET Core para reenviar todas las solicitudes a la aplicación, incluidas las solicitudes de archivos estáticos. No se utiliza el controlador de archivos estáticos de IIS y no tiene la posibilidad de controlar las solicitudes.
Completa los pasos siguientes en el Administrador de IIS para quitar el controlador de archivos estáticos de IIS en el nivel de servidor o de sitio web:
- Navega hasta la característica Módulos.
- En la lista, selecciona StaticFileModule.
- Haz clic en Quitar en la barra lateral Acciones.
Advertencia
Si el controlador de archivos estáticos de IIS está habilitado y el módulo de ASP.NET Core no está configurado correctamente, se proporcionan archivos estáticos. Esto sucede, por ejemplo, si el archivo web.config no está implementado.
- Coloca los archivos de código (incluidos
.cs
y.cshtml
) fuera de la raíz web del proyecto de la aplicación. Por lo tanto, se crea una separación lógica entre el contenido del lado cliente de la aplicación y el código basado en servidor. Esto impide que se filtre el código del lado servidor.
Proporcionar archivos fuera de wwwroot mediante la actualización de IWebHostEnvironment.WebRootPath
Cuando IWebHostEnvironment.WebRootPath se establece en una carpeta distinta de wwwroot
:
- En el entorno de desarrollo, los recursos estáticos que se encuentran en
wwwroot
y en la propiedadIWebHostEnvironment.WebRootPath
actualizada se proporcionan desdewwwroot
. - En cualquier entorno distinto del de desarrollo, los recursos estáticos duplicados se proporcionan desde la carpeta
IWebHostEnvironment.WebRootPath
actualizada.
Considera una aplicación web creada con la plantilla web vacía:
Que contenga un archivo
Index.html
enwwwroot
ywwwroot-custom
.Con el siguiente archivo
Program.cs
actualizado que estableceWebRootPath = "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.MapStaticAssets(); app.Run();
En el código anterior, las solicitudes a /
:
- En el entorno de desarrollo, devuelven
wwwroot/Index.html
- En cualquier entorno distinto del de desarrollo, devuelven
wwwroot-custom/Index.html
Para asegurarte de que se devuelven los recursos de wwwroot-custom
, usa uno de los enfoques siguientes:
Elimina los recursos con nombre duplicado en
wwwroot
.Establece
"ASPNETCORE_ENVIRONMENT"
deProperties/launchSettings.json
en cualquier valor distinto de"Development"
.Deshabilita completamente los recursos web estáticos estableciendo
<StaticWebAssetsEnabled>false</StaticWebAssetsEnabled>
en el archivo del proyecto. ADVERTENCIA, al deshabilitar los recursos web estáticos, se deshabilitan las bibliotecas de clases de Razor.Agrega el siguiente XML al archivo del proyecto:
<ItemGroup> <Content Remove="wwwroot\**" /> </ItemGroup>
El código siguiente actualiza IWebHostEnvironment.WebRootPath
a un valor que no es de desarrollo, lo que garantiza que se devuelva contenido duplicado de wwwroot-custom
en lugar de 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.MapStaticAssets();
app.Run();
Recursos adicionales
Por Rick Anderson
Los archivos estáticos, como HTML, CSS, imágenes y JavaScript, son activos que una aplicación de ASP.NET Core proporciona directamente a los clientes de forma predeterminada.
Proporcionar archivos estáticos
Los archivos estáticos se almacenan en el directorio raíz web del proyecto. El directorio predeterminado es {content root}/wwwroot
, pero se puede cambiar con el método UseWebRoot. Para obtener más información, consulta Raíz del contenido y Raíz web.
El método CreateBuilder establece la raíz de contenido en el directorio actual:
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();
Se puede acceder a los archivos estáticos a través de una ruta de acceso relativa a la raíz web. Por ejemplo, las plantillas de proyecto Aplicación web contienen varias carpetas dentro de la carpeta wwwroot
:
wwwroot
css
js
lib
Considere la posibilidad de crear la carpeta wwwroot/images y agregar el archivo wwwroot/images/MyImage.jpg
. El formato del URI para acceder a un archivo en la carpeta images
es https://<hostname>/images/<image_file_name>
. Por ejemplo, https://localhost:5001/images/MyImage.jpg
.
Suministro de archivos en la raíz web
Las plantillas de aplicación web predeterminadas llaman al método UseStaticFiles en Program.cs
, que permite proporcionar archivos estáticos:
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();
La sobrecarga del método UseStaticFiles
sin parámetros marca los archivos en la raíz web como que se pueden proporcionar. El siguiente marcado hace referencia a wwwroot/images/MyImage.jpg
:
<img src="~/images/MyImage.jpg" class="img" alt="My image" />
En el marcado anterior, el carácter de tilde de la ñ ~
apunta a la raíz web.
Proporcionar archivos fuera de la raíz web
Considere una jerarquía de directorios en la que residen fuera de la raíz web los archivos estáticos que se van a proporcionar:
wwwroot
css
images
js
MyStaticFiles
images
red-rose.jpg
Una solicitud puede acceder al archivo red-rose.jpg
configurando el middleware de archivos estáticos como se muestra a continuación:
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();
En el código anterior, la jerarquía del directorio MyStaticFiles se expone públicamente a través del segmento de URI StaticFiles. Una solicitud a https://<hostname>/StaticFiles/images/red-rose.jpg
sirve al archivo red-rose.jpg
.
El siguiente marcado hace referencia a MyStaticFiles/images/red-rose.jpg
:
<img src="~/StaticFiles/images/red-rose.jpg" class="img" alt="A red rose" />
Para entregar archivos desde varias ubicaciones, vea Entrega de archivos desde varias ubicaciones.
Establecer encabezados de respuesta HTTP
Se puede usar un objeto StaticFileOptions para establecer encabezados de respuesta HTTP. Además de configurar el servicio de archivos estáticos desde la raíz web, el código siguiente establece el encabezado 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();
El código anterior hace que los archivos estáticos estén disponibles públicamente en la memoria caché local durante una semana (604800 segundos).
Autorización de archivos estáticos
Las plantillas de ASP.NET Core llaman a UseStaticFiles antes de llamar a UseAuthorization. La mayoría de las aplicaciones siguen este patrón. Cuando se llama al middleware de archivos estáticos antes de al middleware de autorización:
- No se realizan comprobaciones de autorización en los archivos estáticos.
- Los archivos estáticos que atiende el middleware de archivos estáticos, como los que están en
wwwroot
, son accesibles públicamente.
Para proporcionar archivos estáticos según su autorización:
- Almacénalos fuera de
wwwroot
. - Llama a
UseStaticFiles
, especificando una ruta de acceso, después de llamar aUseAuthorization
. - Establece la directiva de autorización de reserva.
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();
En el código anterior, la directiva de autorización de reserva requiere que se autentiquen todos los usuarios. Los puntos de conexión como los controladores, Razor Pages, etc. que especifican sus propios requisitos de autorización no usan la directiva de autorización de reserva. Por ejemplo, Razor Pages, controladores o métodos de acción con [AllowAnonymous]
o [Authorize(PolicyName="MyPolicy")]
usan el atributo de autorización aplicado en lugar de la directiva de autorización de reserva.
RequireAuthenticatedUser agrega DenyAnonymousAuthorizationRequirement a la instancia actual, lo que exige que el usuario actual se autentique.
Los recursos estáticos en wwwroot
son accesibles públicamente porque se llama al middleware de archivos estáticos predeterminado (app.UseStaticFiles();
) antes de a UseAuthentication
. Los recursos estáticos de la carpeta MyStaticFiles requieren autenticación. En el código de ejemplo se muestra esto.
Un enfoque alternativo a proporcionar archivos según la autorización es:
Almacénalos fuera de
wwwroot
y cualquier directorio al que el middleware de archivos estáticos tenga acceso.Proporciónalos a través de un método de acción al que se aplica la autorización y devuelva un objeto FileResult:
[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"); } }
El enfoque anterior requiere una página o un punto de conexión por archivo. El código siguiente devuelve archivos o carga archivos para usuarios autenticados:
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();
Consulte la carpeta StaticFileAuth de GitHub para obtener el ejemplo completo.
Examen de directorios
El examen de directorios permite enumerar directorios dentro de los directorios especificados.
Por motivos de seguridad, el examen de directorios está deshabilitado de forma predeterminada. Para obtener más información, consulta Consideraciones de seguridad para archivos estáticos.
Habilita el examen de directorios con AddDirectoryBrowser y 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();
El código anterior permite el examen de directorios de la carpeta wwwroot/images usando la dirección URL https://<hostname>/MyImages
, con vínculos a cada archivo y carpeta:
AddDirectoryBrowser
agrega servicios requeridos por el middleware de examen de directorios, incluido HtmlEncoder. Estos servicios se pueden agregar mediante otras llamadas, como AddRazorPages, pero se recomienda llamar a AddDirectoryBrowser
para asegurarse de que los servicios se agregan en todas las aplicaciones.
Suministro de documentos predeterminados
El establecimiento de una página predeterminada proporciona a los visitantes un punto inicial en un sitio. Para servir un archivo predeterminado desde wwwroot
sin necesidad de que la dirección URL de la solicitud incluya el nombre del archivo, llame al método UseDefaultFiles:
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();
Debe llamarse a UseDefaultFiles
antes de a UseStaticFiles
para proporcionar el archivo predeterminado. UseDefaultFiles
es un sistema de reescritura de direcciones URL que no proporciona el archivo.
Con UseDefaultFiles
, las solicitudes a una carpeta en wwwroot
buscan:
default.htm
default.html
index.htm
index.html
El primer archivo que se encuentra en la lista se sirve como si la solicitud incluyera el nombre de archivo. La dirección URL del explorador sigue reflejando el URI solicitado.
El código siguiente cambia el nombre de archivo predeterminado a 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 para documentos predeterminados
UseFileServer combina la funcionalidad de UseStaticFiles
y UseDefaultFiles
y, opcionalmente, la de UseDirectoryBrowser
.
Llama a app.UseFileServer
para poder proporcionar archivos estáticos y el archivo predeterminado. El examen de directorios no está habilitado:
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();
El código siguiente permite proporcionar archivos estáticos, el archivo predeterminado y el examen de directorios:
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();
Ten en cuenta la siguiente jerarquía de directorios:
wwwroot
css
images
js
MyStaticFiles
images
MyImage.jpg
default.html
El código siguiente permite proporcionar archivos estáticos, el archivo predeterminado y el examen de directorios de 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();
Se debe llamar a AddDirectoryBrowser cuando el valor de la propiedad EnableDirectoryBrowsing
es true
.
Al usar la jerarquía de archivos y el código anteriores, las direcciones URL se resuelven como se indica a continuación:
Identificador URI | Respuesta |
---|---|
https://<hostname>/StaticFiles/images/MyImage.jpg |
MyStaticFiles/images/MyImage.jpg |
https://<hostname>/StaticFiles |
MyStaticFiles/default.html |
Si no existe ningún archivo con el nombre predeterminado en el directorio MyStaticFiles, https://<hostname>/StaticFiles
devuelve la lista de directorios con vínculos activos:
UseDefaultFiles y UseDirectoryBrowser realizan un redireccionamiento del lado cliente desde el URI de destino sin una /
final hasta el URI de destino una /
final. Por ejemplo, desde https://<hostname>/StaticFiles
hasta https://<hostname>/StaticFiles/
. Las direcciones URL relativas dentro del directorio StaticFiles no son válidas sin una barra diagonal final (/
), a menos que se use la opción RedirectToAppendTrailingSlash de DefaultFilesOptions.
FileExtensionContentTypeProvider
La clase FileExtensionContentTypeProvider contiene una propiedad Mappings
que actúa como una asignación de extensiones de archivo para tipos de contenido MIME. En el ejemplo siguiente, se asignan varias extensiones de archivo a los tipos MIME conocidos. Se reemplaza la extensión .rtf y se quita .mp4:
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();
Consulta Tipos de contenido MIME.
Tipos de contenido no estándar
El middleware de archivos estáticos entiende casi 400 tipos de contenido de archivo conocidos. Si el usuario solicita un archivo con un tipo de archivo desconocido, el middleware de archivos estáticos pasa la solicitud al siguiente middleware de la canalización. Si ningún middleware se ocupa de la solicitud, se devuelve una respuesta 404 No encontrado. Si se habilita la exploración de directorios, se muestra un vínculo al archivo en una lista de directorios.
El código siguiente permite proporcionar tipos desconocidos y procesa el archivo desconocido como una imagen:
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();
Con el código anterior, una solicitud para un archivo con un tipo de contenido desconocido se devuelve como una imagen.
Advertencia
Habilitar ServeUnknownFileTypes supone un riesgo para la seguridad. Está deshabilitado de forma predeterminada y no se recomienda su uso. FileExtensionContentTypeProvider proporciona una alternativa más segura a ofrecer archivos con extensiones no estándar.
Entrega de archivos desde varias ubicaciones
Tenga en cuenta la página Razor siguiente que muestra el archivo /MyStaticFiles/image3.png
:
@page
<p> Test /MyStaticFiles/image3.png</p>
<img src="~/image3.png" class="img" asp-append-version="true" alt="Test">
UseStaticFiles
y UseFileServer
tienen como valor predeterminado el proveedor de archivos que apunta a wwwroot
. Se pueden proporcionar instancias adicionales de UseStaticFiles
y UseFileServer
con otros proveedores de archivos para proporcionar archivos desde otras ubicaciones. En el ejemplo siguiente se llama a UseStaticFiles
dos veces para entregar archivos desde wwwroot
y MyStaticFiles
:
app.UseStaticFiles(); // Serve files from wwwroot
app.UseStaticFiles(new StaticFileOptions
{
FileProvider = new PhysicalFileProvider(
Path.Combine(builder.Environment.ContentRootPath, "MyStaticFiles"))
});
Con el código anterior:
- Se muestra el archivo
/MyStaticFiles/image3.png
. - El AppendVersion Asistentes de etiquetas de imagen no se aplica porque los asistentes de etiquetas dependen de WebRootFileProvider.
WebRootFileProvider
no se ha actualizado para incluir la carpetaMyStaticFiles
.
El código siguiente actualiza WebRootFileProvider
, que permite al asistente de etiquetas de imagen proporcionar una versión:
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();
Nota:
El enfoque anterior se aplica a las aplicaciones de Razor Pages y MVC. Para obtener guías que se aplican a Blazor Web App, consulta Archivos estáticos Blazor de ASP.NET Core.
Consideraciones de seguridad para archivos estáticos
Advertencia
UseDirectoryBrowser
y UseStaticFiles
pueden producir pérdidas de información confidencial. Se recomienda deshabilitar el examen de directorios en producción. Revisa cuidadosamente los directorios que se habilitan mediante UseStaticFiles
o UseDirectoryBrowser
. Todo el directorio y sus subdirectorios pasan a ser accesibles públicamente. Almacena los archivos adecuados para proporcionarlos al público en un directorio dedicado, como <content_root>/wwwroot
. Separe estos archivos de las vistas MVC, de Razor Pages, de los archivos de configuración, etc.
Las direcciones URL para el contenido que se expone a través de
UseDirectoryBrowser
yUseStaticFiles
están sujetas a la distinción entre mayúsculas y minúsculas, y a restricciones de caracteres del sistema de archivos subyacente. Por ejemplo, Windows no distingue entre mayúsculas y minúsculas, pero macOS y Linux sí.Las aplicaciones de ASP.NET Core hospedadas en IIS usan el módulo de ASP.NET Core para reenviar todas las solicitudes a la aplicación, incluidas las solicitudes de archivos estáticos. No se utiliza el controlador de archivos estáticos de IIS y no tiene la posibilidad de controlar las solicitudes.
Completa los pasos siguientes en el Administrador de IIS para quitar el controlador de archivos estáticos de IIS en el nivel de servidor o de sitio web:
- Navega hasta la característica Módulos.
- En la lista, selecciona StaticFileModule.
- Haz clic en Quitar en la barra lateral Acciones.
Advertencia
Si el controlador de archivos estáticos de IIS está habilitado y el módulo de ASP.NET Core no está configurado correctamente, se proporcionan archivos estáticos. Esto sucede, por ejemplo, si el archivo web.config no está implementado.
- Coloca los archivos de código (incluidos
.cs
y.cshtml
) fuera de la raíz web del proyecto de la aplicación. Por lo tanto, se crea una separación lógica entre el contenido del lado cliente de la aplicación y el código basado en servidor. Esto impide que se filtre el código del lado servidor.
Proporcionar archivos fuera de wwwroot mediante la actualización de IWebHostEnvironment.WebRootPath
Cuando IWebHostEnvironment.WebRootPath se establece en una carpeta distinta de wwwroot
:
- En el entorno de desarrollo, los recursos estáticos que se encuentran en
wwwroot
y en la propiedadIWebHostEnvironment.WebRootPath
actualizada se proporcionan desdewwwroot
. - En cualquier entorno distinto del de desarrollo, los recursos estáticos duplicados se proporcionan desde la carpeta
IWebHostEnvironment.WebRootPath
actualizada.
Considera una aplicación web creada con la plantilla web vacía:
Que contenga un archivo
Index.html
enwwwroot
ywwwroot-custom
.Con el siguiente archivo
Program.cs
actualizado que estableceWebRootPath = "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();
En el código anterior, las solicitudes a /
:
- En el entorno de desarrollo, devuelven
wwwroot/Index.html
- En cualquier entorno distinto del de desarrollo, devuelven
wwwroot-custom/Index.html
Para asegurarte de que se devuelven los recursos de wwwroot-custom
, usa uno de los enfoques siguientes:
Elimina los recursos con nombre duplicado en
wwwroot
.Establece
"ASPNETCORE_ENVIRONMENT"
deProperties/launchSettings.json
en cualquier valor distinto de"Development"
.Deshabilita completamente los recursos web estáticos estableciendo
<StaticWebAssetsEnabled>false</StaticWebAssetsEnabled>
en el archivo del proyecto. ADVERTENCIA, al deshabilitar los recursos web estáticos, se deshabilitan las bibliotecas de clases de Razor.Agregue el siguiente JSON al archivo del proyecto:
<ItemGroup> <Content Remove="wwwroot\**" /> </ItemGroup>
El código siguiente actualiza IWebHostEnvironment.WebRootPath
a un valor que no es de desarrollo, lo que garantiza que se devuelva contenido duplicado de wwwroot-custom
en lugar de 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();
Recursos adicionales
Por Rick Anderson y Kirk Larkin
Los archivos estáticos, como HTML, CSS, imágenes y JavaScript, son activos que una aplicación de ASP.NET Core proporciona directamente a los clientes de forma predeterminada.
Proporcionar archivos estáticos
Los archivos estáticos se almacenan en el directorio raíz web del proyecto. El directorio predeterminado es {content root}/wwwroot
, pero se puede cambiar con el método UseWebRoot. Para obtener más información, consulta Raíz del contenido y Raíz web.
El método CreateBuilder establece la raíz de contenido en el directorio actual:
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();
Se puede acceder a los archivos estáticos a través de una ruta de acceso relativa a la raíz web. Por ejemplo, las plantillas de proyecto Aplicación web contienen varias carpetas dentro de la carpeta wwwroot
:
wwwroot
css
js
lib
Considere la posibilidad de crear la carpeta wwwroot/images y agregar el archivo wwwroot/images/MyImage.jpg
. El formato del URI para acceder a un archivo en la carpeta images
es https://<hostname>/images/<image_file_name>
. Por ejemplo, https://localhost:5001/images/MyImage.jpg
.
Suministro de archivos en la raíz web
Las plantillas de aplicación web predeterminadas llaman al método UseStaticFiles en Program.cs
, que permite proporcionar archivos estáticos:
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();
La sobrecarga del método UseStaticFiles
sin parámetros marca los archivos en la raíz web como que se pueden proporcionar. El siguiente marcado hace referencia a wwwroot/images/MyImage.jpg
:
<img src="~/images/MyImage.jpg" class="img" alt="My image" />
En el marcado anterior, el carácter de tilde de la ñ ~
apunta a la raíz web.
Proporcionar archivos fuera de la raíz web
Considere una jerarquía de directorios en la que residen fuera de la raíz web los archivos estáticos que se van a proporcionar:
wwwroot
css
images
js
MyStaticFiles
images
red-rose.jpg
Una solicitud puede acceder al archivo red-rose.jpg
configurando el middleware de archivos estáticos como se muestra a continuación:
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();
En el código anterior, la jerarquía del directorio MyStaticFiles se expone públicamente a través del segmento de URI StaticFiles. Una solicitud a https://<hostname>/StaticFiles/images/red-rose.jpg
sirve al archivo red-rose.jpg
.
El siguiente marcado hace referencia a MyStaticFiles/images/red-rose.jpg
:
<img src="~/StaticFiles/images/red-rose.jpg" class="img" alt="A red rose" />
Para entregar archivos desde varias ubicaciones, vea Entrega de archivos desde varias ubicaciones.
Establecer encabezados de respuesta HTTP
Se puede usar un objeto StaticFileOptions para establecer encabezados de respuesta HTTP. Además de configurar el servicio de archivos estáticos desde la raíz web, el código siguiente establece el encabezado 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();
El código anterior hace que los archivos estáticos estén disponibles públicamente en la memoria caché local durante una semana (604800 segundos).
Autorización de archivos estáticos
Las plantillas de ASP.NET Core llaman a UseStaticFiles antes de llamar a UseAuthorization. La mayoría de las aplicaciones siguen este patrón. Cuando se llama al middleware de archivos estáticos antes de al middleware de autorización:
- No se realizan comprobaciones de autorización en los archivos estáticos.
- Los archivos estáticos que atiende el middleware de archivos estáticos, como los que están en
wwwroot
, son accesibles públicamente.
Para proporcionar archivos estáticos según su autorización:
- Almacénalos fuera de
wwwroot
. - Llama a
UseStaticFiles
, especificando una ruta de acceso, después de llamar aUseAuthorization
. - Establece la directiva de autorización de reserva.
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();
En el código anterior, la directiva de autorización de reserva requiere que se autentiquen todos los usuarios. Los puntos de conexión como los controladores, Razor Pages, etc. que especifican sus propios requisitos de autorización no usan la directiva de autorización de reserva. Por ejemplo, Razor Pages, controladores o métodos de acción con [AllowAnonymous]
o [Authorize(PolicyName="MyPolicy")]
usan el atributo de autorización aplicado en lugar de la directiva de autorización de reserva.
RequireAuthenticatedUser agrega DenyAnonymousAuthorizationRequirement a la instancia actual, lo que exige que el usuario actual se autentique.
Los recursos estáticos en wwwroot
son accesibles públicamente porque se llama al middleware de archivos estáticos predeterminado (app.UseStaticFiles();
) antes de a UseAuthentication
. Los recursos estáticos de la carpeta MyStaticFiles requieren autenticación. En el código de ejemplo se muestra esto.
Un enfoque alternativo a proporcionar archivos según la autorización es:
- Almacénalos fuera de
wwwroot
y cualquier directorio al que el middleware de archivos estáticos tenga acceso. - Proporciónelos a través de un método de acción al que se aplica la autorización y devuelva un objeto FileResult:
[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");
}
}
Examen de directorios
El examen de directorios permite enumerar directorios dentro de los directorios especificados.
Por motivos de seguridad, el examen de directorios está deshabilitado de forma predeterminada. Para obtener más información, consulta Consideraciones de seguridad para archivos estáticos.
Habilita el examen de directorios con AddDirectoryBrowser y 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();
El código anterior permite el examen de directorios de la carpeta wwwroot/images usando la dirección URL https://<hostname>/MyImages
, con vínculos a cada archivo y carpeta:
AddDirectoryBrowser
agrega servicios requeridos por el middleware de examen de directorios, incluido HtmlEncoder. Estos servicios se pueden agregar mediante otras llamadas, como AddRazorPages, pero se recomienda llamar a AddDirectoryBrowser
para asegurarse de que los servicios se agregan en todas las aplicaciones.
Suministro de documentos predeterminados
El establecimiento de una página predeterminada proporciona a los visitantes un punto inicial en un sitio. Para servir un archivo predeterminado desde wwwroot
sin necesidad de que la dirección URL de la solicitud incluya el nombre del archivo, llame al método UseDefaultFiles:
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();
Debe llamarse a UseDefaultFiles
antes de a UseStaticFiles
para proporcionar el archivo predeterminado. UseDefaultFiles
es un sistema de reescritura de direcciones URL que no proporciona el archivo.
Con UseDefaultFiles
, las solicitudes a una carpeta en wwwroot
buscan:
default.htm
default.html
index.htm
index.html
El primer archivo que se encuentra en la lista se sirve como si la solicitud incluyera el nombre de archivo. La dirección URL del explorador sigue reflejando el URI solicitado.
El código siguiente cambia el nombre de archivo predeterminado a 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 para documentos predeterminados
UseFileServer combina la funcionalidad de UseStaticFiles
y UseDefaultFiles
y, opcionalmente, la de UseDirectoryBrowser
.
Llama a app.UseFileServer
para poder proporcionar archivos estáticos y el archivo predeterminado. El examen de directorios no está habilitado:
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();
El código siguiente permite proporcionar archivos estáticos, el archivo predeterminado y el examen de directorios:
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();
Ten en cuenta la siguiente jerarquía de directorios:
wwwroot
css
images
js
MyStaticFiles
images
MyImage.jpg
default.html
El código siguiente permite proporcionar archivos estáticos, el archivo predeterminado y el examen de directorios de 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();
Se debe llamar a AddDirectoryBrowser cuando el valor de la propiedad EnableDirectoryBrowsing
es true
.
Al usar la jerarquía de archivos y el código anteriores, las direcciones URL se resuelven como se indica a continuación:
Identificador URI | Respuesta |
---|---|
https://<hostname>/StaticFiles/images/MyImage.jpg |
MyStaticFiles/images/MyImage.jpg |
https://<hostname>/StaticFiles |
MyStaticFiles/default.html |
Si no existe ningún archivo con el nombre predeterminado en el directorio MyStaticFiles, https://<hostname>/StaticFiles
devuelve la lista de directorios con vínculos activos:
UseDefaultFiles y UseDirectoryBrowser realizan un redireccionamiento del lado cliente desde el URI de destino sin una /
final hasta el URI de destino una /
final. Por ejemplo, desde https://<hostname>/StaticFiles
hasta https://<hostname>/StaticFiles/
. Las direcciones URL relativas dentro del directorio StaticFiles no son válidas sin una barra diagonal final (/
), a menos que se use la opción RedirectToAppendTrailingSlash de DefaultFilesOptions.
FileExtensionContentTypeProvider
La clase FileExtensionContentTypeProvider contiene una propiedad Mappings
que actúa como una asignación de extensiones de archivo para tipos de contenido MIME. En el ejemplo siguiente, se asignan varias extensiones de archivo a los tipos MIME conocidos. Se reemplaza la extensión .rtf y se quita .mp4:
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();
Consulta Tipos de contenido MIME.
Tipos de contenido no estándar
El middleware de archivos estáticos entiende casi 400 tipos de contenido de archivo conocidos. Si el usuario solicita un archivo con un tipo de archivo desconocido, el middleware de archivos estáticos pasa la solicitud al siguiente middleware de la canalización. Si ningún middleware se ocupa de la solicitud, se devuelve una respuesta 404 No encontrado. Si se habilita la exploración de directorios, se muestra un vínculo al archivo en una lista de directorios.
El código siguiente permite proporcionar tipos desconocidos y procesa el archivo desconocido como una imagen:
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();
Con el código anterior, una solicitud para un archivo con un tipo de contenido desconocido se devuelve como una imagen.
Advertencia
Habilitar ServeUnknownFileTypes supone un riesgo para la seguridad. Está deshabilitado de forma predeterminada y no se recomienda su uso. FileExtensionContentTypeProvider proporciona una alternativa más segura a ofrecer archivos con extensiones no estándar.
Entrega de archivos desde varias ubicaciones
Tenga en cuenta la página Razor siguiente que muestra el archivo /MyStaticFiles/image3.png
:
@page
<p> Test /MyStaticFiles/image3.png</p>
<img src="~/image3.png" class="img" asp-append-version="true" alt="Test">
UseStaticFiles
y UseFileServer
tienen como valor predeterminado el proveedor de archivos que apunta a wwwroot
. Se pueden proporcionar instancias adicionales de UseStaticFiles
y UseFileServer
con otros proveedores de archivos para proporcionar archivos desde otras ubicaciones. En el ejemplo siguiente se llama a UseStaticFiles
dos veces para entregar archivos desde wwwroot
y MyStaticFiles
:
app.UseStaticFiles(); // Serve files from wwwroot
app.UseStaticFiles(new StaticFileOptions
{
FileProvider = new PhysicalFileProvider(
Path.Combine(builder.Environment.ContentRootPath, "MyStaticFiles"))
});
Con el código anterior:
- Se muestra el archivo
/MyStaticFiles/image3.png
. - El AppendVersion Asistentes de etiquetas de imagen no se aplica porque los asistentes de etiquetas dependen de WebRootFileProvider.
WebRootFileProvider
no se ha actualizado para incluir la carpetaMyStaticFiles
.
El código siguiente actualiza WebRootFileProvider
, que permite al asistente de etiquetas de imagen proporcionar una versión:
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();
Consideraciones de seguridad para archivos estáticos
Advertencia
UseDirectoryBrowser
y UseStaticFiles
pueden producir pérdidas de información confidencial. Se recomienda deshabilitar el examen de directorios en producción. Revisa cuidadosamente los directorios que se habilitan mediante UseStaticFiles
o UseDirectoryBrowser
. Todo el directorio y sus subdirectorios pasan a ser accesibles públicamente. Almacena los archivos adecuados para proporcionarlos al público en un directorio dedicado, como <content_root>/wwwroot
. Separe estos archivos de las vistas MVC, de Razor Pages, de los archivos de configuración, etc.
Las direcciones URL para el contenido que se expone a través de
UseDirectoryBrowser
yUseStaticFiles
están sujetas a la distinción entre mayúsculas y minúsculas, y a restricciones de caracteres del sistema de archivos subyacente. Por ejemplo, Windows no distingue entre mayúsculas y minúsculas, pero macOS y Linux sí.Las aplicaciones de ASP.NET Core hospedadas en IIS usan el módulo de ASP.NET Core para reenviar todas las solicitudes a la aplicación, incluidas las solicitudes de archivos estáticos. No se utiliza el controlador de archivos estáticos de IIS y no tiene la posibilidad de controlar las solicitudes.
Completa los pasos siguientes en el Administrador de IIS para quitar el controlador de archivos estáticos de IIS en el nivel de servidor o de sitio web:
- Navega hasta la característica Módulos.
- En la lista, selecciona StaticFileModule.
- Haz clic en Quitar en la barra lateral Acciones.
Advertencia
Si el controlador de archivos estáticos de IIS está habilitado y el módulo de ASP.NET Core no está configurado correctamente, se proporcionan archivos estáticos. Esto sucede, por ejemplo, si el archivo web.config no está implementado.
- Coloca los archivos de código (incluidos
.cs
y.cshtml
) fuera de la raíz web del proyecto de la aplicación. Por lo tanto, se crea una separación lógica entre el contenido del lado cliente de la aplicación y el código basado en servidor. Esto impide que se filtre el código del lado servidor.
Proporcionar archivos fuera de wwwroot mediante la actualización de IWebHostEnvironment.WebRootPath
Cuando IWebHostEnvironment.WebRootPath se establece en una carpeta distinta de wwwroot
:
- En el entorno de desarrollo, los recursos estáticos que se encuentran en
wwwroot
y en la propiedadIWebHostEnvironment.WebRootPath
actualizada se proporcionan desdewwwroot
. - En cualquier entorno distinto del de desarrollo, los recursos estáticos duplicados se proporcionan desde la carpeta
IWebHostEnvironment.WebRootPath
actualizada.
Considera una aplicación web creada con la plantilla web vacía:
Que contenga un archivo
Index.html
enwwwroot
ywwwroot-custom
.Con el siguiente archivo
Program.cs
actualizado que estableceWebRootPath = "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();
En el código anterior, las solicitudes a /
:
- En el entorno de desarrollo, devuelven
wwwroot/Index.html
- En cualquier entorno distinto del de desarrollo, devuelven
wwwroot-custom/Index.html
Para asegurarte de que se devuelven los recursos de wwwroot-custom
, usa uno de los enfoques siguientes:
Elimina los recursos con nombre duplicado en
wwwroot
.Establece
"ASPNETCORE_ENVIRONMENT"
deProperties/launchSettings.json
en cualquier valor distinto de"Development"
.Deshabilita completamente los recursos web estáticos estableciendo
<StaticWebAssetsEnabled>false</StaticWebAssetsEnabled>
en el archivo del proyecto. ADVERTENCIA, al deshabilitar los recursos web estáticos, se deshabilitan las bibliotecas de clases de Razor.Agregue el siguiente JSON al archivo del proyecto:
<ItemGroup> <Content Remove="wwwroot\**" /> </ItemGroup>
El código siguiente actualiza IWebHostEnvironment.WebRootPath
a un valor que no es de desarrollo, lo que garantiza que se devuelva contenido duplicado de wwwroot-custom
en lugar de 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();
Recursos adicionales
Por Rick Anderson y Kirk Larkin
Los archivos estáticos, como HTML, CSS, imágenes y JavaScript, son activos que una aplicación de ASP.NET Core proporciona directamente a los clientes de forma predeterminada.
Vea o descargue el código de ejemplo (cómo descargarlo)
Proporcionar archivos estáticos
Los archivos estáticos se almacenan en el directorio raíz web del proyecto. El directorio predeterminado es {content root}/wwwroot
, pero se puede cambiar con el método UseWebRoot. Para obtener más información, consulta Raíz del contenido y Raíz web.
El método CreateDefaultBuilder establece la raíz de contenido en el directorio actual:
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>();
});
}
El código anterior se creó con la plantilla de la aplicación web.
Se puede acceder a los archivos estáticos a través de una ruta de acceso relativa a la raíz web. Por ejemplo, las plantillas de proyecto Aplicación web contienen varias carpetas dentro de la carpeta wwwroot
:
wwwroot
css
js
lib
Considere la posibilidad de crear la carpeta wwwroot/images y agregar el archivo wwwroot/images/MyImage.jpg
. El formato del URI para acceder a un archivo en la carpeta images
es https://<hostname>/images/<image_file_name>
. Por ejemplo, https://localhost:5001/images/MyImage.jpg
.
Suministro de archivos en la raíz web
Las plantillas de aplicación web predeterminadas llaman al método UseStaticFiles en Startup.Configure
, que permite proporcionar archivos estáticos:
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();
});
}
La sobrecarga del método UseStaticFiles
sin parámetros marca los archivos en la raíz web como que se pueden proporcionar. El siguiente marcado hace referencia a wwwroot/images/MyImage.jpg
:
<img src="~/images/MyImage.jpg" class="img" alt="My image" />
En el código anterior, el carácter de tilde de la ñ ~/
apunta a la raíz web.
Proporcionar archivos fuera de la raíz web
Considere una jerarquía de directorios en la que residen fuera de la raíz web los archivos estáticos que se van a proporcionar:
wwwroot
css
images
js
MyStaticFiles
images
red-rose.jpg
Una solicitud puede acceder al archivo red-rose.jpg
configurando el middleware de archivos estáticos como se muestra a continuación:
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();
});
}
En el código anterior, la jerarquía del directorio MyStaticFiles se expone públicamente a través del segmento de URI StaticFiles. Una solicitud a https://<hostname>/StaticFiles/images/red-rose.jpg
sirve al archivo red-rose.jpg
.
El siguiente marcado hace referencia a MyStaticFiles/images/red-rose.jpg
:
<img src="~/StaticFiles/images/red-rose.jpg" class="img" alt="A red rose" />
Establecer encabezados de respuesta HTTP
Se puede usar un objeto StaticFileOptions para establecer encabezados de respuesta HTTP. Además de configurar el servicio de archivos estáticos desde la raíz web, el código siguiente establece el encabezado Cache-Control
:
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();
});
}
El código anterior establece la antigüedad máxima en 604 800 segundos (7 días).
Autorización de archivos estáticos
Las plantillas de ASP.NET Core llaman a UseStaticFiles antes de llamar a UseAuthorization. La mayoría de las aplicaciones siguen este patrón. Cuando se llama al middleware de archivos estáticos antes de al middleware de autorización:
- No se realizan comprobaciones de autorización en los archivos estáticos.
- Los archivos estáticos que atiende el middleware de archivos estáticos, como los que están en
wwwroot
, son accesibles públicamente.
Para proporcionar archivos estáticos según su autorización:
- Almacénalos fuera de
wwwroot
. - Llama a
UseStaticFiles
, especificando una ruta de acceso, después de llamar aUseAuthorization
. - Establece la directiva de autorización de reserva.
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.
En el código anterior, la directiva de autorización de reserva requiere que se autentiquen todos los usuarios. Los puntos de conexión como los controladores, Razor Pages, etc. que especifican sus propios requisitos de autorización no usan la directiva de autorización de reserva. Por ejemplo, Razor Pages, controladores o métodos de acción con [AllowAnonymous]
o [Authorize(PolicyName="MyPolicy")]
usan el atributo de autorización aplicado en lugar de la directiva de autorización de reserva.
RequireAuthenticatedUser agrega DenyAnonymousAuthorizationRequirement a la instancia actual, lo que exige que el usuario actual se autentique.
Los recursos estáticos en wwwroot
son accesibles públicamente porque se llama al middleware de archivos estáticos predeterminado (app.UseStaticFiles();
) antes de a UseAuthentication
. Los recursos estáticos de la carpeta MyStaticFiles requieren autenticación. En el código de ejemplo se muestra esto.
Un enfoque alternativo a proporcionar archivos según la autorización es:
- Almacénalos fuera de
wwwroot
y cualquier directorio al que el middleware de archivos estáticos tenga acceso. - Proporciónelos a través de un método de acción al que se aplica la autorización y devuelva un objeto FileResult:
[Authorize]
public IActionResult BannerImage()
{
var filePath = Path.Combine(
_env.ContentRootPath, "MyStaticFiles", "images", "red-rose.jpg");
return PhysicalFile(filePath, "image/jpeg");
}
Examen de directorios
El examen de directorios permite enumerar directorios dentro de los directorios especificados.
Por motivos de seguridad, el examen de directorios está deshabilitado de forma predeterminada. Para obtener más información, consulte Consideraciones de seguridad para archivos estáticos.
Habilite el examen de directorios con:
- AddDirectoryBrowser en
Startup.ConfigureServices
. - UseDirectoryBrowser en
Startup.Configure
.
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();
});
}
El código anterior permite el examen de directorios de la carpeta wwwroot/images usando la dirección URL https://<hostname>/MyImages
, con vínculos a cada archivo y carpeta:
Suministro de documentos predeterminados
El establecimiento de una página predeterminada proporciona a los visitantes un punto inicial en un sitio. Para servir un archivo predeterminado desde wwwroot
sin necesidad de que la dirección URL de la solicitud incluya el nombre del archivo, llame al método UseDefaultFiles:
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();
});
}
Debe llamarse a UseDefaultFiles
antes de a UseStaticFiles
para proporcionar el archivo predeterminado. UseDefaultFiles
es un sistema de reescritura de direcciones URL que no proporciona el archivo.
Con UseDefaultFiles
, las solicitudes a una carpeta en wwwroot
buscan:
default.htm
default.html
index.htm
index.html
El primer archivo que se encuentra en la lista se sirve como si la solicitud incluyera el nombre de archivo. La dirección URL del explorador sigue reflejando el URI solicitado.
El código siguiente cambia el nombre de archivo predeterminado a mydefault.html
:
var options = new DefaultFilesOptions();
options.DefaultFileNames.Clear();
options.DefaultFileNames.Add("mydefault.html");
app.UseDefaultFiles(options);
app.UseStaticFiles();
El código siguiente muestra Startup.Configure
con el código anterior:
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 para documentos predeterminados
UseFileServer combina la funcionalidad de UseStaticFiles
y UseDefaultFiles
y, opcionalmente, la de UseDirectoryBrowser
.
Llame a app.UseFileServer
para poder proporcionar archivos estáticos y el archivo predeterminado. El examen de directorios no está habilitado. El código siguiente muestra Startup.Configure
con 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();
});
}
El código siguiente permite proporcionar archivos estáticos, el archivo predeterminado y el examen de directorios:
app.UseFileServer(enableDirectoryBrowsing: true);
El código siguiente muestra Startup.Configure
con el código anterior:
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();
});
}
Tenga en cuenta la siguiente jerarquía de directorios:
wwwroot
css
images
js
MyStaticFiles
images
MyImage.jpg
default.html
El código siguiente permite proporcionar archivos estáticos, el archivo predeterminado y el examen de directorios de 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();
});
}
Se debe llamar a AddDirectoryBrowser cuando el valor de la propiedad EnableDirectoryBrowsing
es true
.
Al usar la jerarquía de archivos y el código anterior, las direcciones URL se resuelven como se indica a continuación:
Identificador URI | Respuesta |
---|---|
https://<hostname>/StaticFiles/images/MyImage.jpg |
MyStaticFiles/images/MyImage.jpg |
https://<hostname>/StaticFiles |
MyStaticFiles/default.html |
Si no existe ningún archivo con el nombre predeterminado en el directorio MyStaticFiles, https://<hostname>/StaticFiles
devuelve la lista de directorios con vínculos activos:
UseDefaultFiles y UseDirectoryBrowser realizan un redireccionamiento del lado cliente desde el URI de destino sin una /
final hasta el URI de destino una /
final. Por ejemplo, desde https://<hostname>/StaticFiles
hasta https://<hostname>/StaticFiles/
. Las direcciones URL relativas dentro del directorio StaticFiles no son válidas sin una barra diagonal final (/
).
FileExtensionContentTypeProvider
La clase FileExtensionContentTypeProvider contiene una propiedad Mappings
que actúa como una asignación de extensiones de archivo para tipos de contenido MIME. En el ejemplo siguiente, se asignan varias extensiones de archivo a los tipos MIME conocidos. Se reemplaza la extensión .rtf y se quita .mp4:
// 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"
});
El código siguiente muestra Startup.Configure
con el código anterior:
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();
});
}
Tipos de contenido no estándar
El middleware de archivos estáticos entiende casi 400 tipos de contenido de archivo conocidos. Si el usuario solicita un archivo con un tipo de archivo desconocido, el middleware de archivos estáticos pasa la solicitud al siguiente middleware de la canalización. Si ningún middleware se ocupa de la solicitud, se devuelve una respuesta 404 No encontrado. Si se habilita la exploración de directorios, se muestra un vínculo al archivo en una lista de directorios.
El código siguiente permite proporcionar tipos desconocidos y procesa el archivo desconocido como una imagen:
app.UseStaticFiles(new StaticFileOptions
{
ServeUnknownFileTypes = true,
DefaultContentType = "image/png"
});
El código siguiente muestra Startup.Configure
con el código anterior:
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();
});
}
Con el código anterior, una solicitud para un archivo con un tipo de contenido desconocido se devuelve como una imagen.
Advertencia
Habilitar ServeUnknownFileTypes supone un riesgo para la seguridad. Está deshabilitado de forma predeterminada y no se recomienda su uso. FileExtensionContentTypeProvider proporciona una alternativa más segura a ofrecer archivos con extensiones no estándar.
Entrega de archivos desde varias ubicaciones
UseStaticFiles
y UseFileServer
tienen como valor predeterminado el proveedor de archivos que apunta a wwwroot
. Se pueden proporcionar instancias adicionales de UseStaticFiles
y UseFileServer
con otros proveedores de archivos para proporcionar archivos desde otras ubicaciones. Para más información, consulte este problema de GitHub.
Consideraciones de seguridad para archivos estáticos
Advertencia
UseDirectoryBrowser
y UseStaticFiles
pueden producir pérdidas de información confidencial. Se recomienda deshabilitar el examen de directorios en producción. Revisa cuidadosamente los directorios que se habilitan mediante UseStaticFiles
o UseDirectoryBrowser
. Todo el directorio y sus subdirectorios pasan a ser accesibles públicamente. Almacena los archivos adecuados para proporcionarlos al público en un directorio dedicado, como <content_root>/wwwroot
. Separe estos archivos de las vistas MVC, de Razor Pages, de los archivos de configuración, etc.
Las direcciones URL para el contenido que se expone a través de
UseDirectoryBrowser
yUseStaticFiles
están sujetas a la distinción entre mayúsculas y minúsculas, y a restricciones de caracteres del sistema de archivos subyacente. Por ejemplo, Windows no distingue entre mayúsculas y minúsculas, pero macOS y Linux sí.Las aplicaciones de ASP.NET Core hospedadas en IIS usan el módulo de ASP.NET Core para reenviar todas las solicitudes a la aplicación, incluidas las solicitudes de archivos estáticos. No se utiliza el controlador de archivos estáticos de IIS y no tiene la posibilidad de controlar las solicitudes.
Completa los pasos siguientes en el Administrador de IIS para quitar el controlador de archivos estáticos de IIS en el nivel de servidor o de sitio web:
- Navega hasta la característica Módulos.
- En la lista, selecciona StaticFileModule.
- Haz clic en Quitar en la barra lateral Acciones.
Advertencia
Si el controlador de archivos estáticos de IIS está habilitado y el módulo de ASP.NET Core no está configurado correctamente, se proporcionan archivos estáticos. Esto sucede, por ejemplo, si el archivo web.config no está implementado.
- Coloca los archivos de código (incluidos
.cs
y.cshtml
) fuera de la raíz web del proyecto de la aplicación. Por lo tanto, se crea una separación lógica entre el contenido del lado cliente de la aplicación y el código basado en servidor. Esto impide que se filtre el código del lado servidor.