Open Closed

404 on files added to the wwwroot folder after compilation #10327


User avatar
0
stephenhynds created

I am trying to add a robots.txt file to the wwwroot folder on our test environment server so that we can deny crawlers. This file does not exist at compilation time as it doesn't need to for local development or production.

From my understanding MapAbpStaticAssets should still allow files added to this folder to be served, but this does not seem to be the case. I've tried adding other files or modifying existing files but I am either served with a 404 for new files, or the content of the file at compilation time.

Is there something I'm missing from the configuration to enabled this?


2 Answer(s)
  • User Avatar
    0
    AI-Bot created
    Support Team ABP Agent
    1. Solution

    MapAbpStaticAssets (and underlying MapStaticAssets) works on the static web assets manifest generated at build/publish time.
    That means:

    • Only files that exist at build/publish are included.
    • Files you copy into wwwroot after deployment are not discovered by MapStaticAssets, so they return 404.
    • If you overwrite a file on disk, the response still comes from the pre‑compressed cached version created at publish time, so you see the old content.

    So what you are seeing is expected behavior with MapStaticAssets/MapAbpStaticAssets and not a misconfiguration.

    How to handle robots.txt per environment

    You have two practical options:


    Option A – Include robots.txt in the project and republish

    1. Add robots.txt into your Blazor Web App project under wwwroot (or another folder, as long as it’s part of static web assets).
    2. Ensure it’s marked as content if needed (in the .csproj of the WebApp project):
    <ItemGroup>
         <Content Include="wwwroot\robots.txt" CopyToOutputDirectory="Always" />
       </ItemGroup>
    
    1. Publish and deploy again.

    For different environments (dev/test/prod), you can:

    • Use different publish profiles that copy a different robots.txt into wwwroot before publish, or
    • Use a simple pre-publish script that overwrites wwwroot/robots.txt based on an environment variable/profile.

    This fits best with the MapStaticAssets design.


    Option B – Custom middleware endpoint for /robots.txt (no republish for content changes)

    If you really need to change robots.txt without republishing, don’t rely on static web assets at all. Serve it via middleware or a minimal API that reads from the physical file or configuration:

    In your Blazor Web App host project (where you call app.MapAbpStaticAssets()), add something like:

    public override void OnApplicationInitialization(ApplicationInitializationContext context)
    {
        var app = context.GetApplicationBuilder();
        var env = context.GetEnvironment();
    
        // ... existing pipeline configuration ...
    
        app.MapAbpStaticAssets();
    
        // Custom robots.txt endpoint
        app.MapGet("/robots.txt", async ctx =>
        {
            ctx.Response.ContentType = "text/plain; charset=utf-8";
    
            // Example 1: Different content by environment
            if (env.IsDevelopment())
            {
                await ctx.Response.WriteAsync("User-agent: *\nDisallow:");
            }
            else if (env.IsEnvironment("Test"))
            {
                await ctx.Response.WriteAsync("User-agent: *\nDisallow: /");
            }
            else // Production
            {
                // Example 2: Read from a physical file that you can change on the server
                var filePath = Path.Combine(env.ContentRootPath, "robots.txt");
                if (File.Exists(filePath))
                {
                    await ctx.Response.WriteAsync(await File.ReadAllTextAsync(filePath));
                }
                else
                {
                    await ctx.Response.WriteAsync("User-agent: *\nDisallow:");
                }
            }
        });
    
        // ... rest of pipeline (routing, antiforgery, endpoints, etc.) ...
    }
    

    Notes:

    • This bypasses the static asset manifest entirely, so any change to the physical robots.txt (or the logic) takes effect immediately on restart.
    • You can keep robots.txt outside of wwwroot (e.g., at ContentRootPath) so it’s clearly treated as configuration, not a static asset.

    1. Sources
    • ABP community article explaining MapStaticAssets and MapAbpStaticAssets behavior (build-time optimization and use of static web assets manifest):
      https://abp.io/community/articles/gyv140vb

    This response was generated by AI. If it didn’t solve your problem, feel free to post a new answer — our support team will jump in to help you soon.

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi

    You can try adding middleware to return this file dynamically based on the current app environment.

    app.UseRouting();
    app.Use(async (context, next) =>
    {
        if (context.Request.Path.Equals("/robots.txt", StringComparison.OrdinalIgnoreCase))
        {
            context.Response.ContentType = "text/plain; charset=utf-8";
            if (env.IsDevelopment() || env.IsStaging())
            {
                await context.Response.WriteAsync("""
    User-agent: *
    Disallow: /
    """);
            }
            else
            {
                context.Response.StatusCode = StatusCodes.Status404NotFound;
            }
            return;
        }
    
        await next();
    });
    
    app.MapAbpStaticAssets();
    

    Thanks

Boost Your Development
ABP Live Training
Packages
See Trainings
Mastering ABP Framework Book
The Official Guide
Mastering
ABP Framework
Learn More
Mastering ABP Framework Book
Made with ❤️ on ABP v10.2.0-preview. Updated on January 20, 2026, 07:04
1
ABP Assistant
🔐 You need to be logged in to use the chatbot. Please log in first.