Arquivos estáticos no ASP.NET Core

Observação

Esta não é a versão mais recente deste artigo. Para informações sobre a versão vigente, confira a Versão do .NET 8 deste artigo.

Importante

Essas informações relacionam-se ao produto de pré-lançamento, que poderá ser substancialmente modificado antes do lançamento comercial. A Microsoft não oferece nenhuma garantia, explícita ou implícita, quanto às informações fornecidas aqui.

Para informações sobre a versão vigente, confira a Versão do .NET 8 deste artigo.

Por Rick Anderson

Arquivos estáticos, como HTML, CSS, imagens e JavaScript, são ativos que um aplicativo ASP.NET Core fornece diretamente para os clientes por padrão.

Fornecer arquivos estáticos

Os arquivos estáticos são armazenados no diretório raiz Web do projeto. O diretório padrão é {content root}/wwwroot, mas pode ser alterado com o método UseWebRoot. Para obter mais informações, consulte Raiz de conteúdo e Raiz web.

O método CreateBuilder define a raiz do conteúdo como o diretório atual:

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();

Os arquivos estáticos são acessíveis por meio de um caminho relativo à raiz Web. Por exemplo, os modelos de projeto do Aplicativo Web contêm várias pastas dentro da pasta wwwroot:

  • wwwroot
    • css
    • js
    • lib

Considere criar a pasta wwwroot/images e adicionar o arquivo wwwroot/images/MyImage.jpg. O formato de URI para acessar um arquivo na pasta images é https://<hostname>/images/<image_file_name>. Por exemplo, https://localhost:5001/images/MyImage.jpg

Fornecer arquivos na raiz Web

Os modelos de aplicativo Web padrão chamam o método UseStaticFiles no Program.cs, que permite que arquivos estáticos sejam fornecidos:

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();

A sobrecarga do método UseStaticFiles sem parâmetro marca os arquivos raiz Web como fornecíveis. As seguintes referências de marcação wwwroot/images/MyImage.jpg:

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

Na marcação anterior, o caractere ~ de til aponta para a raiz Web.

Fornecer arquivos fora do diretório base

Considere uma hierarquia de diretórios na qual os arquivos estáticos a serem fornecidos residam fora da raiz Web:

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

Uma solicitação pode acessar o arquivo red-rose.jpg configurando o middleware de arquivo estático da seguinte maneira:

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();

No código anterior, a hierarquia de diretórios MyStaticFiles é exposta publicamente por meio do segmento do URI StaticFiles. Uma solicitação para https://<hostname>/StaticFiles/images/red-rose.jpg fornece ao arquivo red-rose.jpg.

As seguintes referências de marcação MyStaticFiles/images/red-rose.jpg:

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

Para fornecer arquivos de vários locais, consulte Fornecer arquivos de vários locais.

Definir cabeçalhos de resposta HTTP

Um objeto StaticFileOptions pode ser usado para definir cabeçalhos de resposta HTTP. Além de configurar o fornecimento de arquivo estático da raiz Web, o seguinte código define o cabeçalho de controle por cache:

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();

O código anterior disponibiliza arquivos estáticos publicamente no cache local por uma semana (604800 segundos).

Autorização de arquivo estático

Os modelos de ASP.NET Core chamam UseStaticFiles antes de chamar UseAuthorization. A maioria dos aplicativos segue esse padrão. Quando o Middleware de arquivo estático é chamado antes do middleware de autorização:

  • Nenhuma verificação de autorização é executada nos arquivos estáticos.
  • Os arquivos estáticos fornecidos pelo Middleware de arquivo estático, como aqueles em wwwroot, são acessíveis publicamente.

Para fornecer arquivos estáticos com base na autorização:

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();

No código anterior, a política de autorização de fallback exige que todos os usuários sejam autenticados. Pontos de extremidade, como controladores, Páginas do Razor etc., que especificam seus próprios requisitos de autorização não usam a política de autorização de fallback. Por exemplo, Páginas do Razor, controladores ou métodos de ação com [AllowAnonymous] ou [Authorize(PolicyName="MyPolicy")] usam o atributo de autorização aplicado em vez da política de autorização de fallback.

RequireAuthenticatedUser adiciona DenyAnonymousAuthorizationRequirement à instância atual, que impõe que o usuário atual seja autenticado.

Os ativos estáticos em wwwroot são acessíveis publicamente porque o middleware de arquivo estático padrão (app.UseStaticFiles();) é chamado antes de UseAuthentication. Os ativos estáticos na pasta MyStaticFiles exigem autenticação. O código de amostra demonstra isso.

Uma abordagem alternativa para fornecer arquivos com base na autorização é:

  • Armazene-os fora do wwwroot e de qualquer diretório acessível ao middleware de arquivo estático.

  • Forneça-os por meio de um método de ação ao qual a autorização é aplicada e retorne um 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");
        }
    }
    

A abordagem anterior exige uma página ou um ponto de extremidade por arquivo. O seguinte código retorna ou carrega arquivos para os usuários 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();

Confira a pasta StaticFileAuth do GitHub para ver a amostra completa.

Pesquisa no diretório

A navegação no diretório permite a listagem de diretórios nos diretórios especificados.

A navegação no diretório está desabilitada por padrão por motivos de segurança. Para obter mais informações, consulte Considerações sobre segurança relacionadas a arquivos estáticos.

Habilite a navegação no diretório com AddDirectoryBrowser e 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();

O código anterior permite a navegação no diretório da pasta wwwroot/images usando a URL https://<hostname>/MyImages, com links para cada arquivo e pasta:

pesquisa no diretório

AddDirectoryBrowseradiciona serviços exigidos pelo middleware de navegação no diretório, incluindo HtmlEncoder. Esses serviços podem ser adicionados por outras chamadas, como AddRazorPages, mas recomendamos chamar AddDirectoryBrowser para garantir que os serviços sejam adicionados em todos os aplicativos.

Fornecer documentos padrão

Definir uma página padrão fornece aos visitantes um ponto de partida em um site. Para fornecer um arquivo padrão de wwwroot sem exigir que a URL de solicitação para incluir o nome do arquivo, chame o 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();

UseDefaultFiles deve ser chamado antes de UseStaticFiles para fornecer o arquivo padrão. UseDefaultFiles é um regenerador de URL que não fornece o arquivo.

Com UseDefaultFiles, as solicitações para uma pasta em wwwroot pesquisam:

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

O primeiro arquivo encontrado na lista é fornecido como se a solicitação fosse incluída no nome do arquivo. A URL do navegador continua refletindo o URI solicitado.

O seguinte código altera o nome do arquivo padrão para 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 padrão

UseFileServer combina a funcionalidade de UseStaticFiles, UseDefaultFiles e opcionalmente UseDirectoryBrowser.

Chame app.UseFileServer para habilitar o fornecimento de arquivos estáticos e o arquivo padrão. A navegação no diretório não está habilitada:

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();

O código a seguir permite o fornecimento de arquivos estáticos, do arquivo padrão e da navegação no diretório:

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();

Considere a seguinte hierarquia de diretórios:

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

O código a seguir permite o fornecimento de arquivos estáticos, do arquivo padrão e da navegação no diretório 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();

AddDirectoryBrowser precisa ser chamado quando o valor da propriedade EnableDirectoryBrowsing é true.

Com o uso da hierarquia de arquivos anterior e do código, as URLs são resolvidas da seguinte maneira:

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

Se nenhum arquivo nomeado como padrão existir no diretório MyStaticFiles, https://<hostname>/StaticFiles retornará a listagem de diretórios com links clicáveis:

Lista de arquivos estáticos

UseDefaultFiles e UseDirectoryBrowser executam um redirecionamento do lado do cliente do URI de destino sem um / à direita para o URI de destino com um / à direita. Por exemplo, de https://<hostname>/StaticFiles para https://<hostname>/StaticFiles/. As URLs relativas dentro do diretório StaticFiles são inválidas sem uma barra à direita (/), a menos que a opção RedirectToAppendTrailingSlash de DefaultFilesOptions seja usada.

FileExtensionContentTypeProvider

A classe FileExtensionContentTypeProvider contém uma propriedade Mappings que fornece como um mapeamento de extensões de arquivo para tipos de conteúdo MIME. Na amostra a seguir, várias extensões de arquivo são mapeadas para tipos MIME conhecidos. A extensão .rtf é substituída e .mp4 é removida:

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();

Consulte Tipos de conteúdo MIME.

Tipos de conteúdo não padrão

O middleware de arquivo estático compreende quase 400 tipos de conteúdo de arquivo conhecidos. Se o usuário solicitar um arquivo com um tipo de arquivo desconhecido, o middleware de arquivo estático aprovará a solicitação para o próximo middleware no pipeline. Se nenhum middleware manipular a solicitação, uma resposta 404 Não Encontrado será retornada. Se a navegação no diretório estiver habilitada, um link para o arquivo será exibido na lista do diretório.

O seguinte código habilita o fornecimento de tipos desconhecidos e renderiza o arquivo desconhecido como uma imagem:

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();

Com o código anterior, uma solicitação para um arquivo com um tipo de conteúdo desconhecido é retornada como uma imagem.

Aviso

Habilitar ServeUnknownFileTypes é um risco à segurança. Ela está desabilitada por padrão, e seu uso não é recomendado. FileExtensionContentTypeProvider fornece uma alternativa mais segura para o fornecimento de arquivos com extensões não padrão.

Fornecer arquivos de vários locais

Considere a seguinte página Razor que exibe o arquivo /MyStaticFiles/image3.png:

@page

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

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

UseStaticFiles e UseFileServer padrão para o provedor de arquivos apontando para wwwroot. Instâncias adicionais de UseStaticFiles e UseFileServer podem ser fornecidas com outros provedores de arquivos para fornecer arquivos de outros locais. O exemplo a seguir chama UseStaticFiles duas vezes para fornecer arquivos de wwwroot e MyStaticFiles:

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

Usando o código anterior:

O código a seguir atualiza o WebRootFileProvider, que permite que o auxiliar de marcação de imagem forneça uma versão:

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();

Considerações de segurança para arquivos estáticos

Aviso

UseDirectoryBrowser e UseStaticFiles podem causar a perda de segredos. A desabilitação da navegação no diretório em produção é altamente recomendada. Examine com atenção os diretórios que são habilitados por meio de UseStaticFiles ou UseDirectoryBrowser. Todo o diretório e seus subdiretórios se tornam publicamente acessíveis. Armazene arquivos adequados para fornecimento ao público em um diretório dedicado, como <content_root>/wwwroot. Separe esses arquivos das exibições MVC, Páginas do Razor, arquivos de configuração, etc.

  • As URLs para o conteúdo exposto com UseDirectoryBrowser e UseStaticFiles estão sujeitas à diferenciação de maiúsculas e minúsculas e a restrições de caracteres do sistema de arquivos subjacente. Por exemplo, o Windows diferencia maiúsculas de minúsculas, mas o macOS e o Linux não.

  • Os aplicativos ASP.NET Core hospedados no IIS usam o Módulo do ASP.NET Core para encaminhar todas as solicitações ao aplicativo, inclusive as solicitações de arquivo estático. O manipulador de arquivo estático de IIS não é usado e não tem nenhuma chance de lidar com solicitações.

  • Conclua as etapas seguinte no Gerenciador do IIS para remover o manipulador de arquivos estáticos no IIS no nível do servidor ou do site:

    1. Navegue para o recurso Módulos.
    2. Selecione StaticFileModule na lista.
    3. Clique em Remover na barra lateral Ações.

Aviso

Se o manipulador de arquivo estático do IIS estiver habilitado e o Módulo do ASP.NET Core não estiver configurado corretamente, os arquivos estáticos serão atendidos. Isso acontece, por exemplo, se o arquivo web.config não foi implantado.

  • Coloque arquivos de código, incluindo .cs e .cshtml, fora da raiz Web do projeto de aplicativo. Portanto, uma separação lógica é criada entre o conteúdo do lado do cliente do aplicativo e o código baseado em servidor. Isso impede a perda de código do lado do servidor.

Fornecer arquivos fora de wwwroot atualizando IWebHostEnvironment.WebRootPath

Quando IWebHostEnvironment.WebRootPath é definido como uma pasta diferente de wwwroot:

  • No ambiente de desenvolvimento, os ativos estáticos encontrados em wwwroot e os atualizados IWebHostEnvironment.WebRootPath são fornecidos do wwwroot.
  • Em qualquer ambiente que não seja o desenvolvimento, ativos estáticos duplicados são fornecidos da pasta atualizada IWebHostEnvironment.WebRootPath.

Considere um aplicativo Web criado com o modelo da Web vazio:

  • Contendo um arquivo Index.html em wwwroot e wwwroot-custom.

  • Com o seguinte arquivo Program.cs atualizado que define WebRootPath = "wwwroot-custom":

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

No código anterior, solicita /:

  • No ambiente de desenvolvimento retorna wwwroot/Index.html
  • Em qualquer ambiente que não seja o retorno do desenvolvimento wwwroot-custom/Index.html

Para garantir que os ativos de wwwroot-custom sejam retornados, use uma das seguintes abordagens:

  • Exclua ativos nomeados duplicados em wwwroot.

  • Defina "ASPNETCORE_ENVIRONMENT" em Properties/launchSettings.json para qualquer valor diferente de "Development".

  • Desabilite completamente os ativos da Web estáticos definindo <StaticWebAssetsEnabled>false</StaticWebAssetsEnabled> no arquivo de projeto. AVISO, desabilitar ativos da Web estáticos desabilita Razor bibliotecas de classes.

  • Adicione o seguinte JSON ao arquivo de projeto:

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

O código a seguir atualiza IWebHostEnvironment.WebRootPath para um valor que não é de desenvolvimento, garantindo que o conteúdo duplicado seja retornado de wwwroot-custom ao invés 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 adicionais

Por Rick Anderson e Kirk Larkin

Arquivos estáticos, como HTML, CSS, imagens e JavaScript, são ativos que um aplicativo ASP.NET Core fornece diretamente para os clientes por padrão.

Fornecer arquivos estáticos

Os arquivos estáticos são armazenados no diretório raiz Web do projeto. O diretório padrão é {content root}/wwwroot, mas pode ser alterado com o método UseWebRoot. Para obter mais informações, consulte Raiz de conteúdo e Raiz web.

O método CreateBuilder define a raiz do conteúdo como o diretório atual:

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();

Os arquivos estáticos são acessíveis por meio de um caminho relativo à raiz Web. Por exemplo, os modelos de projeto do Aplicativo Web contêm várias pastas dentro da pasta wwwroot:

  • wwwroot
    • css
    • js
    • lib

Considere criar a pasta wwwroot/images e adicionar o arquivo wwwroot/images/MyImage.jpg. O formato de URI para acessar um arquivo na pasta images é https://<hostname>/images/<image_file_name>. Por exemplo, https://localhost:5001/images/MyImage.jpg

Fornecer arquivos na raiz Web

Os modelos de aplicativo Web padrão chamam o método UseStaticFiles no Program.cs, que permite que arquivos estáticos sejam fornecidos:

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();

A sobrecarga do método UseStaticFiles sem parâmetro marca os arquivos raiz Web como fornecíveis. As seguintes referências de marcação wwwroot/images/MyImage.jpg:

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

Na marcação anterior, o caractere ~ de til aponta para a raiz Web.

Fornecer arquivos fora do diretório base

Considere uma hierarquia de diretórios na qual os arquivos estáticos a serem fornecidos residam fora da raiz Web:

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

Uma solicitação pode acessar o arquivo red-rose.jpg configurando o middleware de arquivo estático da seguinte maneira:

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();

No código anterior, a hierarquia de diretórios MyStaticFiles é exposta publicamente por meio do segmento do URI StaticFiles. Uma solicitação para https://<hostname>/StaticFiles/images/red-rose.jpg fornece ao arquivo red-rose.jpg.

As seguintes referências de marcação MyStaticFiles/images/red-rose.jpg:

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

Para fornecer arquivos de vários locais, consulte Fornecer arquivos de vários locais.

Definir cabeçalhos de resposta HTTP

Um objeto StaticFileOptions pode ser usado para definir cabeçalhos de resposta HTTP. Além de configurar o fornecimento de arquivo estático da raiz Web, o seguinte código define o cabeçalho de controle por cache:

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();

O código anterior disponibiliza arquivos estáticos publicamente no cache local por uma semana (604800 segundos).

Autorização de arquivo estático

Os modelos de ASP.NET Core chamam UseStaticFiles antes de chamar UseAuthorization. A maioria dos aplicativos segue esse padrão. Quando o Middleware de arquivo estático é chamado antes do middleware de autorização:

  • Nenhuma verificação de autorização é executada nos arquivos estáticos.
  • Os arquivos estáticos fornecidos pelo Middleware de arquivo estático, como aqueles em wwwroot, são acessíveis publicamente.

Para fornecer arquivos estáticos com base na autorização:

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();

No código anterior, a política de autorização de fallback exige que todos os usuários sejam autenticados. Pontos de extremidade, como controladores, Páginas do Razor etc., que especificam seus próprios requisitos de autorização não usam a política de autorização de fallback. Por exemplo, Páginas do Razor, controladores ou métodos de ação com [AllowAnonymous] ou [Authorize(PolicyName="MyPolicy")] usam o atributo de autorização aplicado em vez da política de autorização de fallback.

RequireAuthenticatedUser adiciona DenyAnonymousAuthorizationRequirement à instância atual, que impõe que o usuário atual seja autenticado.

Os ativos estáticos em wwwroot são acessíveis publicamente porque o middleware de arquivo estático padrão (app.UseStaticFiles();) é chamado antes de UseAuthentication. Os ativos estáticos na pasta MyStaticFiles exigem autenticação. O código de amostra demonstra isso.

Uma abordagem alternativa para fornecer arquivos com base na autorização é:

  • Armazene-os fora do wwwroot e de qualquer diretório acessível ao middleware de arquivo estático.
  • Forneça-os por meio de um método de ação ao qual a autorização é aplicada e retorne um 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");
    }
}

Pesquisa no diretório

A navegação no diretório permite a listagem de diretórios nos diretórios especificados.

A navegação no diretório está desabilitada por padrão por motivos de segurança. Para obter mais informações, consulte Considerações sobre segurança relacionadas a arquivos estáticos.

Habilite a navegação no diretório com AddDirectoryBrowser e 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();

O código anterior permite a navegação no diretório da pasta wwwroot/images usando a URL https://<hostname>/MyImages, com links para cada arquivo e pasta:

pesquisa no diretório

AddDirectoryBrowseradiciona serviços exigidos pelo middleware de navegação no diretório, incluindo HtmlEncoder. Esses serviços podem ser adicionados por outras chamadas, como AddRazorPages, mas recomendamos chamar AddDirectoryBrowser para garantir que os serviços sejam adicionados em todos os aplicativos.

Fornecer documentos padrão

Definir uma página padrão fornece aos visitantes um ponto de partida em um site. Para fornecer um arquivo padrão de wwwroot sem exigir que a URL de solicitação para incluir o nome do arquivo, chame o 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();

UseDefaultFiles deve ser chamado antes de UseStaticFiles para fornecer o arquivo padrão. UseDefaultFiles é um regenerador de URL que não fornece o arquivo.

Com UseDefaultFiles, as solicitações para uma pasta em wwwroot pesquisam:

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

O primeiro arquivo encontrado na lista é fornecido como se a solicitação fosse incluída no nome do arquivo. A URL do navegador continua refletindo o URI solicitado.

O seguinte código altera o nome do arquivo padrão para 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 padrão

UseFileServer combina a funcionalidade de UseStaticFiles, UseDefaultFiles e opcionalmente UseDirectoryBrowser.

Chame app.UseFileServer para habilitar o fornecimento de arquivos estáticos e o arquivo padrão. A navegação no diretório não está habilitada:

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();

O código a seguir permite o fornecimento de arquivos estáticos, do arquivo padrão e da navegação no diretório:

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();

Considere a seguinte hierarquia de diretórios:

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

O código a seguir permite o fornecimento de arquivos estáticos, do arquivo padrão e da navegação no diretório 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();

AddDirectoryBrowser precisa ser chamado quando o valor da propriedade EnableDirectoryBrowsing é true.

Com o uso da hierarquia de arquivos anterior e do código, as URLs são resolvidas da seguinte maneira:

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

Se nenhum arquivo nomeado como padrão existir no diretório MyStaticFiles, https://<hostname>/StaticFiles retornará a listagem de diretórios com links clicáveis:

Lista de arquivos estáticos

UseDefaultFiles e UseDirectoryBrowser executam um redirecionamento do lado do cliente do URI de destino sem um / à direita para o URI de destino com um / à direita. Por exemplo, de https://<hostname>/StaticFiles para https://<hostname>/StaticFiles/. As URLs relativas dentro do diretório StaticFiles são inválidas sem uma barra à direita (/), a menos que a opção RedirectToAppendTrailingSlash de DefaultFilesOptions seja usada.

FileExtensionContentTypeProvider

A classe FileExtensionContentTypeProvider contém uma propriedade Mappings que fornece como um mapeamento de extensões de arquivo para tipos de conteúdo MIME. Na amostra a seguir, várias extensões de arquivo são mapeadas para tipos MIME conhecidos. A extensão .rtf é substituída e .mp4 é removida:

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();

Consulte Tipos de conteúdo MIME.

Tipos de conteúdo não padrão

O middleware de arquivo estático compreende quase 400 tipos de conteúdo de arquivo conhecidos. Se o usuário solicitar um arquivo com um tipo de arquivo desconhecido, o middleware de arquivo estático aprovará a solicitação para o próximo middleware no pipeline. Se nenhum middleware manipular a solicitação, uma resposta 404 Não Encontrado será retornada. Se a navegação no diretório estiver habilitada, um link para o arquivo será exibido na lista do diretório.

O seguinte código habilita o fornecimento de tipos desconhecidos e renderiza o arquivo desconhecido como uma imagem:

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();

Com o código anterior, uma solicitação para um arquivo com um tipo de conteúdo desconhecido é retornada como uma imagem.

Aviso

Habilitar ServeUnknownFileTypes é um risco à segurança. Ela está desabilitada por padrão, e seu uso não é recomendado. FileExtensionContentTypeProvider fornece uma alternativa mais segura para o fornecimento de arquivos com extensões não padrão.

Fornecer arquivos de vários locais

Considere a seguinte página Razor que exibe o arquivo /MyStaticFiles/image3.png:

@page

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

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

UseStaticFiles e UseFileServer padrão para o provedor de arquivos apontando para wwwroot. Instâncias adicionais de UseStaticFiles e UseFileServer podem ser fornecidas com outros provedores de arquivos para fornecer arquivos de outros locais. O exemplo a seguir chama UseStaticFiles duas vezes para fornecer arquivos de wwwroot e MyStaticFiles:

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

Usando o código anterior:

O código a seguir atualiza o WebRootFileProvider, que permite que o auxiliar de marcação de imagem forneça uma versão:

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();

Considerações de segurança para arquivos estáticos

Aviso

UseDirectoryBrowser e UseStaticFiles podem causar a perda de segredos. A desabilitação da navegação no diretório em produção é altamente recomendada. Examine com atenção os diretórios que são habilitados por meio de UseStaticFiles ou UseDirectoryBrowser. Todo o diretório e seus subdiretórios se tornam publicamente acessíveis. Armazene arquivos adequados para fornecimento ao público em um diretório dedicado, como <content_root>/wwwroot. Separe esses arquivos das exibições MVC, Páginas do Razor, arquivos de configuração, etc.

  • As URLs para o conteúdo exposto com UseDirectoryBrowser e UseStaticFiles estão sujeitas à diferenciação de maiúsculas e minúsculas e a restrições de caracteres do sistema de arquivos subjacente. Por exemplo, o Windows diferencia maiúsculas de minúsculas, mas o macOS e o Linux não.

  • Os aplicativos ASP.NET Core hospedados no IIS usam o Módulo do ASP.NET Core para encaminhar todas as solicitações ao aplicativo, inclusive as solicitações de arquivo estático. O manipulador de arquivo estático de IIS não é usado e não tem nenhuma chance de lidar com solicitações.

  • Conclua as etapas seguinte no Gerenciador do IIS para remover o manipulador de arquivos estáticos no IIS no nível do servidor ou do site:

    1. Navegue para o recurso Módulos.
    2. Selecione StaticFileModule na lista.
    3. Clique em Remover na barra lateral Ações.

Aviso

Se o manipulador de arquivo estático do IIS estiver habilitado e o Módulo do ASP.NET Core não estiver configurado corretamente, os arquivos estáticos serão atendidos. Isso acontece, por exemplo, se o arquivo web.config não foi implantado.

  • Coloque arquivos de código, incluindo .cs e .cshtml, fora da raiz Web do projeto de aplicativo. Portanto, uma separação lógica é criada entre o conteúdo do lado do cliente do aplicativo e o código baseado em servidor. Isso impede a perda de código do lado do servidor.

Fornecer arquivos fora de wwwroot atualizando IWebHostEnvironment.WebRootPath

Quando IWebHostEnvironment.WebRootPath é definido como uma pasta diferente de wwwroot:

  • No ambiente de desenvolvimento, os ativos estáticos encontrados em wwwroot e os atualizados IWebHostEnvironment.WebRootPath são fornecidos do wwwroot.
  • Em qualquer ambiente que não seja o desenvolvimento, ativos estáticos duplicados são fornecidos da pasta atualizada IWebHostEnvironment.WebRootPath.

Considere um aplicativo Web criado com o modelo da Web vazio:

  • Contendo um arquivo Index.html em wwwroot e wwwroot-custom.

  • Com o seguinte arquivo Program.cs atualizado que define WebRootPath = "wwwroot-custom":

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

No código anterior, solicita /:

  • No ambiente de desenvolvimento retorna wwwroot/Index.html
  • Em qualquer ambiente que não seja o retorno do desenvolvimento wwwroot-custom/Index.html

Para garantir que os ativos de wwwroot-custom sejam retornados, use uma das seguintes abordagens:

  • Exclua ativos nomeados duplicados em wwwroot.

  • Defina "ASPNETCORE_ENVIRONMENT" em Properties/launchSettings.json para qualquer valor diferente de "Development".

  • Desabilite completamente os ativos da Web estáticos definindo <StaticWebAssetsEnabled>false</StaticWebAssetsEnabled> no arquivo de projeto. AVISO, desabilitar ativos da Web estáticos desabilita Razor bibliotecas de classes.

  • Adicione o seguinte JSON ao arquivo de projeto:

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

O código a seguir atualiza IWebHostEnvironment.WebRootPath para um valor que não é de desenvolvimento, garantindo que o conteúdo duplicado seja retornado de wwwroot-custom ao invés 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 adicionais

Por Rick Anderson e Kirk Larkin

Arquivos estáticos, como HTML, CSS, imagens e JavaScript, são ativos que um aplicativo ASP.NET Core fornece diretamente para os clientes por padrão.

Exibir ou baixar código de exemplo (como baixar)

Fornecer arquivos estáticos

Os arquivos estáticos são armazenados no diretório raiz Web do projeto. O diretório padrão é {content root}/wwwroot, mas pode ser alterado com o método UseWebRoot. Para obter mais informações, consulte Raiz de conteúdo e Raiz web.

O método CreateDefaultBuilder define a raiz do conteúdo como o diretório atual:

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>();
            });
}

O código anterior foi criado com o modelo de aplicativo Web.

Os arquivos estáticos são acessíveis por meio de um caminho relativo à raiz Web. Por exemplo, os modelos de projeto do Aplicativo Web contêm várias pastas dentro da pasta wwwroot:

  • wwwroot
    • css
    • js
    • lib

Considere criar a pasta wwwroot/images e adicionar o arquivo wwwroot/images/MyImage.jpg. O formato de URI para acessar um arquivo na pasta images é https://<hostname>/images/<image_file_name>. Por exemplo, https://localhost:5001/images/MyImage.jpg

Fornecer arquivos na raiz Web

Os modelos de aplicativo Web padrão chamam o método UseStaticFiles no Startup.Configure, que permite que arquivos estáticos sejam fornecidos:

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();
    });
}

A sobrecarga do método UseStaticFiles sem parâmetro marca os arquivos raiz Web como fornecíveis. As seguintes referências de marcação wwwroot/images/MyImage.jpg:

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

No código anterior, o caractere til ~/ aponta para a raiz Web.

Fornecer arquivos fora do diretório base

Considere uma hierarquia de diretórios na qual os arquivos estáticos a serem fornecidos residam fora da raiz Web:

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

Uma solicitação pode acessar o arquivo red-rose.jpg configurando o middleware de arquivo estático da seguinte maneira:

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();
    });
}

No código anterior, a hierarquia de diretórios MyStaticFiles é exposta publicamente por meio do segmento do URI StaticFiles. Uma solicitação para https://<hostname>/StaticFiles/images/red-rose.jpg fornece ao arquivo red-rose.jpg.

As seguintes referências de marcação MyStaticFiles/images/red-rose.jpg:

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

Definir cabeçalhos de resposta HTTP

Um objeto StaticFileOptions pode ser usado para definir cabeçalhos de resposta HTTP. Além de configurar o fornecimento de arquivo estático da raiz Web, o seguinte código define o cabeçalho 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();
    });
}

O código anterior define a idade máxima como 604800 segundos (7 dias).

Cabeçalho de resposta mostrando que o cabeçalho Cache-Control foi adicionado

Autorização de arquivo estático

Os modelos de ASP.NET Core chamam UseStaticFiles antes de chamar UseAuthorization. A maioria dos aplicativos segue esse padrão. Quando o Middleware de arquivo estático é chamado antes do middleware de autorização:

  • Nenhuma verificação de autorização é executada nos arquivos estáticos.
  • Os arquivos estáticos fornecidos pelo Middleware de arquivo estático, como aqueles em wwwroot, são acessíveis publicamente.

Para fornecer arquivos estáticos com base na autorização:

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.

No código anterior, a política de autorização de fallback exige que todos os usuários sejam autenticados. Pontos de extremidade, como controladores, Páginas do Razor etc., que especificam seus próprios requisitos de autorização não usam a política de autorização de fallback. Por exemplo, Páginas do Razor, controladores ou métodos de ação com [AllowAnonymous] ou [Authorize(PolicyName="MyPolicy")] usam o atributo de autorização aplicado em vez da política de autorização de fallback.

RequireAuthenticatedUser adiciona DenyAnonymousAuthorizationRequirement à instância atual, que impõe que o usuário atual seja autenticado.

Os ativos estáticos em wwwroot são acessíveis publicamente porque o middleware de arquivo estático padrão (app.UseStaticFiles();) é chamado antes de UseAuthentication. Os ativos estáticos na pasta MyStaticFiles exigem autenticação. O código de amostra demonstra isso.

Uma abordagem alternativa para fornecer arquivos com base na autorização é:

  • Armazene-os fora do wwwroot e de qualquer diretório acessível ao middleware de arquivo estático.
  • Forneça-os por meio de um método de ação ao qual a autorização é aplicada e retorne um objeto FileResult:
[Authorize]
public IActionResult BannerImage()
{
    var filePath = Path.Combine(
        _env.ContentRootPath, "MyStaticFiles", "images", "red-rose.jpg");

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

Pesquisa no diretório

A navegação no diretório permite a listagem de diretórios nos diretórios especificados.

A navegação no diretório está desabilitada por padrão por motivos de segurança. Para obter mais informações, consulte Considerações sobre segurança relacionadas a arquivos estáticos.

Habilite a navegação no diretório com:

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();
    });
}

O código anterior permite a navegação no diretório da pasta wwwroot/images usando a URL https://<hostname>/MyImages, com links para cada arquivo e pasta:

pesquisa no diretório

Fornecer documentos padrão

Definir uma página padrão fornece aos visitantes um ponto de partida em um site. Para fornecer um arquivo padrão de wwwroot sem exigir que a URL de solicitação para incluir o nome do arquivo, chame o 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();
    });
}

UseDefaultFiles deve ser chamado antes de UseStaticFiles para fornecer o arquivo padrão. UseDefaultFiles é um regenerador de URL que não fornece o arquivo.

Com UseDefaultFiles, as solicitações para uma pasta em wwwroot pesquisam:

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

O primeiro arquivo encontrado na lista é fornecido como se a solicitação fosse incluída no nome do arquivo. A URL do navegador continua refletindo o URI solicitado.

O seguinte código altera o nome do arquivo padrão para mydefault.html:

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

O código a seguir mostra Startup.Configure com o 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 padrão

UseFileServer combina a funcionalidade de UseStaticFiles, UseDefaultFiles e opcionalmente UseDirectoryBrowser.

Chame app.UseFileServer para habilitar o fornecimento de arquivos estáticos e o arquivo padrão. A navegação no diretório não está habilitada. O código a seguir mostra Startup.Configure com 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();
    });
}

O código a seguir permite o fornecimento de arquivos estáticos, do arquivo padrão e da navegação no diretório:

app.UseFileServer(enableDirectoryBrowsing: true);

O código a seguir mostra Startup.Configure com o 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();
    });
}

Considere a seguinte hierarquia de diretórios:

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

O código a seguir permite o fornecimento de arquivos estáticos, do arquivo padrão e da navegação no diretório 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();
    });
}

AddDirectoryBrowser precisa ser chamado quando o valor da propriedade EnableDirectoryBrowsing é true.

Com o uso da hierarquia de arquivos e do código anterior, as URLs são resolvidas da seguinte maneira:

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

Se nenhum arquivo nomeado como padrão existir no diretório MyStaticFiles, https://<hostname>/StaticFiles retornará a listagem de diretórios com links clicáveis:

Lista de arquivos estáticos

UseDefaultFiles e UseDirectoryBrowser executam um redirecionamento do lado do cliente do URI de destino sem um / à direita para o URI de destino com um / à direita. Por exemplo, de https://<hostname>/StaticFiles para https://<hostname>/StaticFiles/. As URLs relativas dentro do diretório StaticFiles são inválidas sem uma barra à direita (/).

FileExtensionContentTypeProvider

A classe FileExtensionContentTypeProvider contém uma propriedade Mappings que fornece como um mapeamento de extensões de arquivo para tipos de conteúdo MIME. Na amostra a seguir, várias extensões de arquivo são mapeadas para tipos MIME conhecidos. A extensão .rtf é substituída e .mp4 é removida:

// 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"
});

O código a seguir mostra Startup.Configure com o 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();
    });
}

Consulte Tipos de conteúdo MIME.

Tipos de conteúdo não padrão

O middleware de arquivo estático compreende quase 400 tipos de conteúdo de arquivo conhecidos. Se o usuário solicitar um arquivo com um tipo de arquivo desconhecido, o middleware de arquivo estático aprovará a solicitação para o próximo middleware no pipeline. Se nenhum middleware manipular a solicitação, uma resposta 404 Não Encontrado será retornada. Se a navegação no diretório estiver habilitada, um link para o arquivo será exibido na lista do diretório.

O seguinte código habilita o fornecimento de tipos desconhecidos e renderiza o arquivo desconhecido como uma imagem:

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

O código a seguir mostra Startup.Configure com o 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();
    });
}

Com o código anterior, uma solicitação para um arquivo com um tipo de conteúdo desconhecido é retornada como uma imagem.

Aviso

Habilitar ServeUnknownFileTypes é um risco à segurança. Ela está desabilitada por padrão, e seu uso não é recomendado. FileExtensionContentTypeProvider fornece uma alternativa mais segura para o fornecimento de arquivos com extensões não padrão.

Fornecer arquivos de vários locais

UseStaticFiles e UseFileServer padrão para o provedor de arquivos apontando para wwwroot. Instâncias adicionais de UseStaticFiles e UseFileServer podem ser fornecidas com outros provedores de arquivos para fornecer arquivos de outros locais. Saiba mais neste tópico do GitHub.

Considerações de segurança para arquivos estáticos

Aviso

UseDirectoryBrowser e UseStaticFiles podem causar a perda de segredos. A desabilitação da navegação no diretório em produção é altamente recomendada. Examine com atenção os diretórios que são habilitados por meio de UseStaticFiles ou UseDirectoryBrowser. Todo o diretório e seus subdiretórios se tornam publicamente acessíveis. Armazene arquivos adequados para fornecimento ao público em um diretório dedicado, como <content_root>/wwwroot. Separe esses arquivos das exibições MVC, Páginas do Razor, arquivos de configuração, etc.

  • As URLs para o conteúdo exposto com UseDirectoryBrowser e UseStaticFiles estão sujeitas à diferenciação de maiúsculas e minúsculas e a restrições de caracteres do sistema de arquivos subjacente. Por exemplo, o Windows diferencia maiúsculas de minúsculas, mas o macOS e o Linux não.

  • Os aplicativos ASP.NET Core hospedados no IIS usam o Módulo do ASP.NET Core para encaminhar todas as solicitações ao aplicativo, inclusive as solicitações de arquivo estático. O manipulador de arquivo estático de IIS não é usado e não tem nenhuma chance de lidar com solicitações.

  • Conclua as etapas seguinte no Gerenciador do IIS para remover o manipulador de arquivos estáticos no IIS no nível do servidor ou do site:

    1. Navegue para o recurso Módulos.
    2. Selecione StaticFileModule na lista.
    3. Clique em Remover na barra lateral Ações.

Aviso

Se o manipulador de arquivo estático do IIS estiver habilitado e o Módulo do ASP.NET Core não estiver configurado corretamente, os arquivos estáticos serão atendidos. Isso acontece, por exemplo, se o arquivo web.config não foi implantado.

  • Coloque arquivos de código, incluindo .cs e .cshtml, fora da raiz Web do projeto de aplicativo. Portanto, uma separação lógica é criada entre o conteúdo do lado do cliente do aplicativo e o código baseado em servidor. Isso impede a perda de código do lado do servidor.

Recursos adicionais