ASP.NET Core 6 randomly returning 200 with empty response

79 views Asked by At

I have a web app deployed on Azure. During testing, I found one of my endpoints is not working... sometimes. More specifically, this POST endpoint always works in my dev environment, and it randomly works in Prod.

When it fails, my controller endpoint is not hit (discovered by adding logs), and a "successful" 200 is returned but no response content is sent down. My POST body is tiny, only 50 or so bytes.

I'm not sure if its a clue or not, but it does seem to work immediately after a browser refresh, then when my auth token is refreshed it fails much more. This is fairly anecdotal though.

From googling, I found this helps some people:

var builder = WebApplication.CreateBuilder(args);
builder.WebHost.ConfigureKestrel(options =>
{
    options.Limits.MinRequestBodyDataRate = null;
    options.Limits.MinResponseDataRate = null;
});

No such luck here though. Any ideas what else might caused this? OR, any idea how how I can have .NET better tell me what's failing? I have nothing in my logs or anything.

Thanks!

EDIT:

I have two middlewares:

public class ExceptionHandlingMiddleware
{
    private readonly RequestDelegate _next;
    private readonly ILogger<ExceptionHandlingMiddleware> _logger;
    private readonly JsonSerializerOptions jsonPolicy = new JsonSerializerOptions() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase };

    public ExceptionHandlingMiddleware(RequestDelegate next, ILogger<ExceptionHandlingMiddleware> logger)
    {
        _next = next;
        _logger = logger;
    }

    public async Task InvokeAsync(HttpContext httpContext)
    {
        try
        {
            await _next(httpContext);
        }
        catch (Exception ex)
        {
            await HandleExceptionAsync(httpContext, ex);
        }
    }

    private async Task HandleExceptionAsync(HttpContext context, Exception exception)
    {
        context.Response.ContentType = "application/json";
        var response = context.Response;

        string msg;
        switch (exception)
        {
            case ApplicationException ex:
                if (ex.Message.Contains("Invalid Token"))
                {
                    response.StatusCode = (int)HttpStatusCode.Forbidden;
                    msg = ex.Message;
                    break;
                }
                response.StatusCode = (int)HttpStatusCode.BadRequest;
                msg = ex.Message;
                break;
            default:
                response.StatusCode = (int)HttpStatusCode.InternalServerError;
                msg = exception.Message;
                break;
        }
        var errorResponse = new
        {
            Failed = true,
            ErrorMessage = msg
        };

        _logger.LogError(exception, exception.Message);
        var result = JsonSerializer.Serialize(errorResponse, jsonPolicy);
        await context.Response.WriteAsync(result);
    }
}

and:

public class UserStatusMiddleware
{
    private readonly RequestDelegate _next;
    private readonly DbContextFactory DbContextFactory;
    private readonly ILogger<ExceptionHandlingMiddleware> _logger;
    private readonly JsonSerializerOptions jsonPolicy = new JsonSerializerOptions() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase };

    public UserStatusMiddleware(RequestDelegate next, DbContextFactory dbrderMonkeyContextFactory, ILogger<ExceptionHandlingMiddleware> logger)
    {
        _next = next;
        _logger = logger;
        DbContextFactory = dbContextFactory;
    }

    public async Task InvokeAsync(HttpContext httpContext)
    {
        using (DBContext dbContext = DbContextFactory.CreateDbContext())
        {
            var user = httpContext.User.FindFirst(ClaimTypes.NameIdentifier);
            if (user == null)
            {
                throw new ArgumentException();
            }
            AspNetUser dbUser = dbContext.AspNetUsers.FirstOrDefault(x => x.Id == user.Value);
            if (dbUser.IsDisabled || !dbUser.IsApproved)
            {
                httpContext.Response.ContentType = "application/json";
                var response = httpContext.Response;

                string msg;
                var errorResponse = new
                {
                    Failed = true,
                    IsDisabled = dbUser.IsDisabled,
                    IsApproved = dbUser.IsApproved,
                    ErrorMessage = "User is either disabled or not approved"
                };
                response.StatusCode = (int)HttpStatusCode.Unauthorized;

                var result = JsonSerializer.Serialize(errorResponse, jsonPolicy);
                await httpContext.Response.WriteAsync(result);
            }
            else
            {
                _next(httpContext);
            }
        }
    }
}

public static class UserStatusMiddlewareExtensions
{
    public static IApplicationBuilder UseUserStatusCheck(
        this IApplicationBuilder builder)
    {
        return builder.UseMiddleware<UserStatusMiddleware>();
    }
}

EDIT #2: So it looks like if I take out the second middleware, the problem goes away. But why? Is there some time limit for middleware?

0

There are 0 answers