Click here to Skip to main content
15,867,686 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
My .NET CORE API Custom middleware is being ignored when the API receives a message. This middleware is intended to perform some header validation on any given request.

I am expecting the header validation middleware to be called as part of the request so that header.isValid will show the outcome of this validation. When I put a breakpoint in the controller, the header variable is empty.

Am I mis understanidng what middleware can do in expecting it to communicate with the controller. All I need for it to do is act as a gatekeeper against bad requests so I would be open to having it terminate bad requests and allow good ones through as an outcome

What I have tried:

public interface IHeaderIsValid
{
    bool isValid { get; set; }
    bool fromCMDS { get; set; }
    bool fromLocal { get; set; }
    Int16 transmittingInstallationID { get; set; }
}

public class HeaderIsValid : IHeaderIsValid
{
    public bool  isValid { get; set; }
    public bool fromCMDS { get; set; }
    public bool fromLocal { get; set; }
    public Int16 transmittingInstallationID { get; set; }

}

public static class RequestHeaderMiddlewareExtensions
{
    public static IApplicationBuilder UseHeaderValidation(this IApplicationBuilder app)
    {
        return app.UseMiddleware<RequestHeaderMiddleware>();
    }
}

public class RequestHeaderMiddleware
{

    #region CONSTRUCTORS

    /// <summary>
    /// The Request header middleware constructor
    /// </summary>
    /// <param name="next">navigation parameter to pass the request to the next pipeline item</param>
    public RequestHeaderMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    #endregion


    #region PUBLIC METHJODS

    /// <summary>
    /// Invoke the middleware to validate the request header
    /// </summary>
    /// <param name="context">the context of the request</param>
    /// <returns>true or throws an exception</returns>
    public async Task Invoke(HttpContext context, IHeaderIsValid header)
    {
        try
        {
            header.isValid = false;
            bool hasInstallationID = Int16.TryParse(context.Request.Headers.FirstOrDefault(x => x.Key == "InstallationID").Value.ToString(), out this.transmittingInstallationID);
            if (!hasInstallationID)
            {
                throw new NoInstallationIDOnHeaderException("No Installation ID on the Request Header");
            }

            string fromLocalHeader = context.Request.Headers.FirstOrDefault(x => x.Key == "FromLocal").Value.ToString();
            if (fromLocalHeader != string.Empty)
            {
                bool.TryParse(fromLocalHeader, out this.fromLocal);
            }
            else
            {
                this.fromLocal = false;
            }

            bool hasFromCMDS = bool.TryParse(context.Request.Headers.FirstOrDefault(x => x.Key == "FromCMDS").Value.ToString(), out this.fromCMDS);
            if (!hasFromCMDS)
            {
                this.fromCMDS = false;
            }

            if (this.fromCMDS && this.fromLocal)
            {
                throw new FromCMDSAndFromLocalSetException("The FromLocal and FromCMDS indicators are both set on the request header");
            }

            if (!this.fromCMDS && !this.fromLocal)
            {
                throw new NoOriginSetException("One of The FromLocal and FromCMDS indicators must be set on the request header");
            }

        }
        catch (Exception ex)
        {
            throw ex;
        }

       header.isValid = true;

        await _next(context);
    }

    #endregion


    #region PRIVATE VARIABLES

    private readonly RequestDelegate _next;

    #endregion


    #region PUBLIC VARIABLES

    public Int16 transmittingInstallationID;
    public bool fromCMDS;
    public bool fromLocal;

    #endregion
}


Then in startup.cs (ConfigureServices is trimmed for brevity)
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddScoped<IHeaderIsValid, HeaderIsValid>();
            services.AddMvcCore()
                .AddAuthorization()
                .AddJsonFormatters();
 
        }


       public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory)
        {
            loggerFactory.AddLog4Net();

            app.UseCors("default");
            app.UseAuthentication();
            app.UseMvc();

            // My custom middleware to validate the header
            app.UseHeaderValidation();
        }
    }
}


Here is a snippet from the controller:
[Route("LDH/[controller]")]
[ApiController]
public class SalesController : ControllerBase
{
  [Authorize]
    [HttpPost("ProcessPayment")]
    public async Task<ActionResult> ProcessPayment(WorkingTicket ticketDetails)
    {
        if (!header.isValid)
        {
            ModelState.AddModelError("BadHeader", "Request header is invalid");
            return BadRequest(ModelState);
        }
        Return OK();
    }

    private IHeaderIsValid header;
}
Posted
Updated 26-Feb-20 20:38pm
v3
Comments
cjb110 26-Feb-20 3:18am    
Is it not ordering within `Configure`? Try moving your middleware to before UseAuth or UseMvc.
Ger Hayden 26-Feb-20 3:36am    
That as it. Much appreciated.

1 solution

The ordering of calls within Configure is important, UseMvc and similar tend to need to go last.

If your middleware alters authentication then again it needs to be called before the UseAuthentication.
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900