Search code examples
asp.net-web-apiasp.net-coreowin-middleware

404 not found Gets response when using Asp.net Core Middleware with .map


Below is code snippet in which i have wrote a Middleware which receives api request and validate it and send response.

But when ever the request is valid at that time it does not call API , it show 404 Not Found Error.

Middleware code snippet

    // You may need to install the Microsoft.AspNetCore.Http.Abstractions package into your project
public class ApiKeyValidatorsMiddleware
{
    private readonly RequestDelegate _next;
    IValidateRequest _IValidateRequest { get; set; }

    public ApiKeyValidatorsMiddleware(RequestDelegate next , IValidateRequest ivalidaterequest)
    {
        _next = next;
        _IValidateRequest = ivalidaterequest;
    }

    public async Task Invoke(HttpContext httpContext)
    {
        try
        {
            var queryString = httpContext.Request.Query;
            StringValues keyvalue;
            queryString.TryGetValue("key", out keyvalue);



            if (httpContext.Request.Method != "POST")
            {
                httpContext.Response.StatusCode = 405; //Method Not Allowed               
                await httpContext.Response.WriteAsync("Method Not Allowed");
                return;
            }

            if (keyvalue.Count == 0)
            {
                httpContext.Response.StatusCode = 400; //Bad Request                
                await httpContext.Response.WriteAsync("API Key is missing");
                return;
            }
            else
            {
                var serviceName = httpContext.Request.Path.Value.Replace(@"/", string.Empty);

                if (!_IValidateRequest.ValidateKeys(keyvalue) && !_IValidateRequest.IsValidServiceRequest(keyvalue, serviceName))
                {
                    httpContext.Response.StatusCode = 401; //UnAuthorized
                    await httpContext.Response.WriteAsync("Invalid User Key");
                    return;
                }
            }

            await _next.Invoke(httpContext);
        }
        catch (Exception)
        {
            throw;
        }
    }
}

// Extension method used to add the middleware to the HTTP request pipeline.
public static class MiddlewareExtensions
{
    public static IApplicationBuilder UseMiddleware(this IApplicationBuilder builder)
    {
        return builder.UseMiddleware<ApiKeyValidatorsMiddleware>();
    }
}

Startup

 public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
            app.UseBrowserLink();
        }
        else
        {
            app.UseExceptionHandler("/Home/Error");
        }
        app.UseStaticFiles();
        app.UseSession();

        //Middleware Call
        app.Map("/api", appBuilder => appBuilder.UseMiddleware<ApiKeyValidatorsMiddleware>());

        app.UseMvc(routes =>
        {
            routes.MapRoute(
                name: "Servicedefault",
                template: "{controller=Login}/{action=Login}/{ServiceID}/{ServiceName}");

            routes.MapRoute(
                name: "default",
                template: "{controller=Login}/{action=Login}/{id?}");

        });
    }

Controller Codesnippet

It is simple API which do not have any authentication attribute on it.

    [Route("api/[controller]")]
public class MoviesAPIController : Controller
{
    IMovies _IMovies;
    public MoviesAPIController(IMovies imovies)
    {
        _IMovies = imovies;
    }

    // GET: api/values
    [HttpGet]
    public IEnumerable<string> Get()
    {
        return new string[] { "value1", "value2" };
    }

    // GET api/values/5
    [HttpGet("{id}")]
    public string Get(int id)
    {
        return "value";
    }

    // POST api/values
    [HttpPost]
    public List<MoviesTB> Post([FromQuery]string key)
    {
        return _IMovies.GetMusicStore();
    }

Output

enter image description here


Solution

  • As per documentation

    Map* extensions are used as a convention for branching the pipeline. Map branches the request pipeline based on matches of the given request path. If the request path starts with the given path, the branch is executed.

    You need to register your middle ware like this

    app.UseMiddleware<ApiKeyValidatorsMiddleware>();
    

    and then check either it is a API call or not in middle ware.

    httpContext.Request.Path.StartsWithSegments("/api")
    

    MiddleWare code

    // You may need to install the Microsoft.AspNetCore.Http.Abstractions package into your project
        public class ApiKeyValidatorsMiddleware
        {
            private readonly RequestDelegate _next;
            IValidateRequest _IValidateRequest { get; set; }
    
            public ApiKeyValidatorsMiddleware(RequestDelegate next, IValidateRequest ivalidaterequest)
            {
                _next = next;
                _IValidateRequest = ivalidaterequest;
            }
    
            public async Task Invoke(HttpContext httpContext)
            {
                try
                {
                    if (httpContext.Request.Path.StartsWithSegments("/api"))
                    {
    
                        var queryString = httpContext.Request.Query;
                        StringValues keyvalue;
                        queryString.TryGetValue("key", out keyvalue);
    
    
    
                        if (httpContext.Request.Method != "POST")
                        {
                            httpContext.Response.StatusCode = 405; //Method Not Allowed               
                            await httpContext.Response.WriteAsync("Method Not Allowed");
                            return;
                        }
    
                        if (keyvalue.Count == 0)
                        {
                            httpContext.Response.StatusCode = 400; //Bad Request                
                            await httpContext.Response.WriteAsync("API Key is missing");
                            return;
                        }
                        else
                        {
                            var serviceName = httpContext.Request.Path.Value.Replace(@"/", string.Empty);
    
                            if (!_IValidateRequest.ValidateKeys(keyvalue) && !_IValidateRequest.IsValidServiceRequest(keyvalue, serviceName))
                            {
                                httpContext.Response.StatusCode = 401; //UnAuthorized
                                await httpContext.Response.WriteAsync("Invalid User Key");
                                return;
                            }
                        }
    
                    }
                    await _next.Invoke(httpContext);
    
                }
                catch (Exception)
                {
                    throw;
                }
            }
        }
    
        // Extension method used to add the middleware to the HTTP request pipeline.
        public static class MiddlewareExtensions
        {
            public static IApplicationBuilder UseMiddleware(this IApplicationBuilder builder)
            {
                return builder.UseMiddleware<ApiKeyValidatorsMiddleware>();
            }
        }