ASP.NET Core Web API on Azure App Service - POST and PUT requests failing 500 for a short period
Asked Answered
K

4

11

The web application is a REST API and a SPA. It's maintained and currently on .NET 6.0 and have been working steadily for years.

The requests are CORS and the server is properly configured for this.

Suddenly we have several outbursts per day of POST and PUT requests consistently failing with 500 server error. And they are failing quickly, only 30 ms. This goes on for 5-15 minutes and then returns to normal again.

All GET requests still working perfectly fine in between, which is strange.

Even stranger these failing requests are not logged, like they never reach the web server. Checked both web server logs (IIS) and ASP.NET Core application exceptions and traces.

The response header X-Powered-By: ASP.NET is also missing from these failing requests. Which would be present for normal 500 server errors. Also suggesting the requests never reach the server.

The App Service Plan is only using 30% of it's resources currently.

Same behaviour is confirmed across Chrome, Edge and Safari. But you can have the issue in Chrome, while a session in Edge is working flawlessly on the same PC.

If we close the browser and re-open, the issues are gone.

It all started this month: May 2024.

Also worth mentioning that we have a DNS load balancer, Azure Traffic Manager.

This only operates on DNS queries and returns the closest of the two instances of the REST API services.

Traffic Manager does therefore not log any requests.

Update confirmed that error also occurs without Traffic Manager.

Update 2 We have tested deploying on a brand new App Service. And tried upgrading to .NET8.0. To no avail

That leaves us with browser's network log the only place to inspect. We have exported numbers of HAR files and looked for differences between failing requests and working requests, and found none.

Has anyone experienced similar behaviour of any kind?

Configuration of ASP.NET Core in Startup.cs:

public class Startup
{
    readonly string _corsPolicyName = "corsOrigins";
    public IConfiguration Configuration { get; }
    public IWebHostEnvironment Environment { get; }

    private static IConfiguration config;
    public static IConfiguration GetConfiguration()
    {
        return config;
    }

    public Startup(IConfiguration configuration, IWebHostEnvironment environment)
    {
        Configuration = configuration;
        config = configuration;
        Environment = environment;
    }

    public void ConfigureServices(IServiceCollection services)
    {
        if (Environment.IsDevelopment())
            IdentityModelEventSource.ShowPII = true;

        // logging
        services.AddApplicationInsightsTelemetry();
        services.AddLogging(logging => 
        {
            logging.AddSimpleConsole();
            logging.AddAzureWebAppDiagnostics();
        });
        services.Configure<AzureFileLoggerOptions>(options =>
        {
            options.FileName = "filelog-";
            options.FileSizeLimit = 50 * 1024;
            options.RetainedFileCountLimit = 5;
        });
        services.Configure<AzureBlobLoggerOptions>(options =>
        {
            options.BlobName = "Backend.txt";
        });

        // so our claims will not be translated
        JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();

        // configure languages
        services.Configure<RequestLocalizationOptions>(options =>
        {
            var supportedCultures = new[]
            {
                new CultureInfo("en"),
                new CultureInfo("no")
            };
            options.DefaultRequestCulture = new RequestCulture("en");
            options.SupportedCultures = supportedCultures;
            options.SupportedUICultures = supportedCultures;
        });

        // add Identity
        services.AddIdentity<ApplicationUser, ApplicationRole>()
            .AddEntityFrameworkStores<AuthContext>()
            .AddRoleManager<RoleManager<ApplicationRole>>()
            .AddDefaultTokenProviders();
        services.AddUserAndPasswordPolicies();

        services.AddCors(options =>
        {
            {
                options.AddPolicy(_corsPolicyName, builder =>
                builder.SetIsOriginAllowedToAllowWildcardSubdomains()
                .WithOrigins("https://*.our.domain")
                .AllowAnyMethod()
                .AllowAnyHeader()
                .AllowCredentials());
            }
        });

        services.AddAuthentication(options =>
        {
            options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
            options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
        }).AddJwtBearer(o =>
        {
            o.MapInboundClaims = false;
            o.Authority = Configuration.GetValue<string>("authServerUrl");
            o.Audience = "backend";
            o.RequireHttpsMetadata = true;
            o.SaveToken = true;
            o.TokenValidationParameters = new TokenValidationParameters
            {
                NameClaimType = "name",
                RoleClaimType = "role",
                ValidateIssuer = true,
                ValidateAudience = true
            };
        });

        services.AddControllersWithViews(options =>
        {
            options.Filters.Add<WebCustomExceptionFilter>();
        })
            .AddNewtonsoftJson(options =>
            {
                options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
                options.SerializerSettings.DateTimeZoneHandling = DateTimeZoneHandling.Utc;
            });

        services.AddSignalRManager();

        services.AddRazorPages()
            .AddRazorRuntimeCompilation();

        services.AddSwaggerGenNewtonsoftSupport();
        services.AddSwaggerGen(options =>
        {
            options.SwaggerDoc("v1", new OpenApiInfo { Title = "server debug api spec", Version = "v1" });
            options.SchemaFilter<EnumSchemaFilter>();
        });
    }

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        StaticEnvironment.IsDebug = env.IsDevelopment();
        StaticEnvironment.ContentRootPath = env.ContentRootPath;

        app.UseCors(_corsPolicyName);

        if (env.IsDevelopment())
        {
            app.UseStaticFiles();
            app.UseDeveloperExceptionPage();
            app.UseSwagger();
            app.UseSwaggerUI(c => {
                c.DocumentTitle = "Backend Swagger docs";
                var sidebar = Path.Combine(env.ContentRootPath, "wwwroot/sidebar.html");
                c.HeadContent = File.ReadAllText(sidebar);
                c.InjectStylesheet("/colors.css");
                c.InjectStylesheet("/style.css");
                c.SwaggerEndpoint("/swagger/v1/swagger.json", "server");
            });
        }
        else
        {
            app.UseHttpsRedirection();
            app.UseHsts();
        }

        // Localization
        app.UseRequestLocalization();
        app.UseRouting();

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

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

        // Enable static files for use in MVC views. 
        app.UseStaticFiles();
        app.UseStaticFiles(new StaticFileOptions()
        {
            FileProvider = new PhysicalFileProvider(
                        Path.Combine(Directory.GetCurrentDirectory(), @"Style")),
            RequestPath = new PathString("/Style")
        });
    }
}

Typical controller signature:

[Authorize]
[ApiController]
[Route("api/[controller]")]
public class ImprovementController : ControllerBase

The Web client fetch code

const fullUrl = `${baseUrl}/${url}`
const bearer = getBearer()
const connectionId = getConnectionId()
    
const req = {
    method: "POST",
    headers: {
        "Authorization": bearer,
        "Content-Type": "application/json"
    },
    body: JSON.stringify(data)
}
    
const res = await fetch(fullUrl, req)
Kwarteng answered 29/5 at 18:20 Comment(16)
Do you have any code and/or configuration you can share with us? – Brnaby
@Brnaby I updated the description with what I think would be most relevant. Please ask if there is more relevant information that could be useful – Kwarteng
I believe the load balancer can throw that. Maybe check here: learn.microsoft.com/en-us/azure/traffic-manager/… – Boulevardier
@Boulevardier Yes, but I believe it would be very consistent across all simultaneous requests if this was the case. DNS lookup from Chrome chrome://net-internals/#dns is working correctly when we have the errors πŸ€·β€β™‚οΈ But I'm not writing off that Traffic Manager has something to do with it. – Kwarteng
Hey @altmag, when did this issue start? We are facing a similar issue at my company, and it seems that it also suddenly started – Focalize
We're seeing similar behavior which started roughly May 20th, 2024. No clear pattern of why some requests fail and others succeed to same endpoint, and no changes on our API side of any CORS related configuration. – Nonpros
Hi @Focalize first incident was registered 3rd of May. Then again on the 14th. This weak it kind of peaked with multiple occasions every day. Are you also using ASP.NET Core and Azure App service? – Kwarteng
@Nonpros interesting. We also experienced it first time this month. The essential configurations have not been changed in years. Are you also not able to find logs or traces for the failing requests in Azure? – Kwarteng
Yes, we are also using ASP.Net Core and Azure App Services. Ours also peaked since last week, in the browser side of app insights we just see failed requests with a status code of 0, but no logs or traces in the API side – Focalize
this post my be useful learn.microsoft.com/en-us/answers/questions/1362812/… – Focalize
There's a recent thread of discussion seems to be related to this issue here: learn.microsoft.com/en-us/answers/questions/1687258/… – Audreaaudres
interesting that the wildcard is mentioned a few times. Might try explicitly listing each subdomain for allowed origins instead of using wildcard for it. – Boulevardier
same thing happening here. here's what we've noticed. clearing cookies, storage, cache doesn't seem to help. closing tab and opening a new one doesn't help opening in an incognito browser works. I'm at a loss to what's different in the incognito window, I'm also at a loss to why it's showing up as a CORS failure when the CORS request seemed to work. next step for me is to try trap this with fiddler, but it's a pain to try trigger – Polyadelphous
@Polyadelphous interesting, maybe incognito is isolated somehow. Just like another browser. We experience failure in one browser while another works fine simultaneously. The reason it logs as CORS errors is because the response has no headers. CORS depends on the Access-Control-Allow-Origin header. Fooled me in other scenarios as well. – Kwarteng
It was mentioned that downgrading to HTTP 1.1 (if you're using HTTP 2 at this moment) may work in the thread: learn.microsoft.com/en-us/answers/questions/1687258/… – Audreaaudres
tracking here on Microsoft Q&A: learn.microsoft.com/en-us/answers/questions/1687258/… – Gap
A
4

There are several tickets raised at Microsoft. Please see https://learn.microsoft.com/en-us/answers/questions/1687258/our-azure-app-service-application-started-to-exper

We have the same issue and a lot of others have. Post requests are failing randomly with 500 error and gets are working fine. After a while it works again. Apparently it can be fixed in the meantime by setting the setting of HTTP/2 back to HTTP/1.1

I hope to confirm this next monday when all our customers are back to work

Anastomose answered 31/5 at 21:11 Comment(3)
any updated on this? – Patricapatrice
downgrading the http version on the web app from http2 to http/1.1 seems to work for me. I did not receive any complaints anymore but apparently for others, even downgrading does not solve the problem. Microsoft is still looking into it – Anastomose
@Anastomose We've tried this, along with other users. Seems to work at first, but comes back after a couple of hours. We suspect it might have something to do with the service/slot/instance being restarted as a result of updating the configuration, as the same thing happens when you simply restart the service. – Cyclosis
P
2

We experience the very same issue as described here Angular Application shows random 500 Server Errors with Azure App Service

We are pretty confident, that the issue lays somewhere in Azure itself. Hopefully, they come up with a solution soon. It's already been over two weeks, which is hardly acceptable.

Patricapatrice answered 5/6 at 7:24 Comment(0)
D
0

The same issue is described here: https://learn.microsoft.com/en-us/answers/questions/1687258/our-azure-app-service-application-started-to-exper

This morning a Microsoft Employee commented: "We have been discussing on this internally and our product team is actively working on the fix. As soon as we have more info, we will share it here. We appreciate your patience.".

This would confirm that there is indeed an issue caused by Microsoft. For now waiting is the only thing we can do.

Dialysis answered 6/6 at 8:16 Comment(0)
G
0

We have a case open with Microsoft on this issue. We had "500 errors", which were cleared up by making the change from http 2.0 to 1.1. However, our customers continue to have poor performance involving "0 errors". The duration of these failing requests ranges from 10-25 seconds, on page loads that should take 1-2 seconds max. The other odd characteristic is that the problems are happening for a single customer - largely not exclusively.
Our app is C# and it uses AJAX calls. For the 500 errors, they were definitely POST's, but for the 0 errors, they are a mixture of GET's and POST's.

Garretgarreth answered 11/6 at 13:48 Comment(0)

© 2022 - 2024 β€” McMap. All rights reserved.