How to return 404 page in ASP .NET MVC when query string parameters is incorrect

Let's imagine I have the following action

public ViewResult Products(string color)
{...}

and route which maps url "products" to this action.

According to SEO tips link /products?color=red should return

200 OK

But link /products?someOtherParametr=someValue

404 Not found

So the question is - how to handle unexisting query parameters and return 404 in this case


Considering the accepted answer at What is the proper way to send an HTTP 404 response from an ASP.NET MVC action?, there is a special ActionResult that could fulfill your expectation.

public class HomeController : Controller
{
    public ViewResult Products(string color)
    {
        if (color != "something") // it can be replaced with any guarded clause(s)
            return new HttpNotFoundResult("The color does not exist.");
        ...
    }
}

Update:

public class HomeController : Controller
{
    public ViewResult Products(string color)
    {
        if (Request.QueryString.Count != 1 || 
            Request.QueryString.GetKey(0) != "color")
            return new HttpNotFoundResult("the error message");
        ...
    }
}

Validate this before executing the Action Method. This approach is valid for all Controller of you project or specific Action method.

Controller Action Methods

[attr]  // Before executing any Action Method, Action Filter will execute to 
        //check for Valid Query Strings.
public class ActionResultTypesController : Controller
{
    [HttpGet]
    public ActionResult Index(int Param = 0)
    {
        return View();
    }

    [HttpPost]
    public ActionResult Index(MyViewModel obj)
    {
        return View(obj);
    }

}

Action Filter

public class attr : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        if (filterContext.ActionParameters.Count == 0 &&
                  System.Web.HttpContext.Current.Request.QueryString.Count > 0)
        {
              //When no Action Parameter exists and Query String exists. 
        }
        else
        {
            // Check the Query String Key name and compare it with the Action 
            // Parameter name
            foreach (var item in System.Web.HttpContext
                                       .Current
                                       .Request.QueryString.Keys)
            {
                if (!filterContext.ActionParameters.Keys.Contains(item))
                {
                    // When the Query String is not matching with the Action 
                    // Parameter
                }
            }
        }
        base.OnActionExecuting(filterContext);
    }
}

If you pay attention to the above code, we are checking the Action parameter as shown in the screen show below.

enter image description here

What can we do in case the QueryString passed does not exists in the Action Method Parameter? We can redirect the user to another page as shown in this link.

filterContext.Result = new RedirectToRouteResult(new RouteValueDictionary
                        {
                            {"action", "ActionName"},
                            {"controller", "ControllerName"},
                            {"area", "Area Name"},
                            {"Parameter Name","Parameter Value"}
                        });

Or

We can do like this. The below mentioned code will be written in the OnActionExecuting Method Override

filterContext.Result = new HttpStatusCodeResult(404);

protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
    var actionParameters = filterContext.ActionParameters.Keys;
    var queryParameters = filterContext
                                  .RequestContext
                                  .HttpContext
                                  .Request
                                  .QueryString
                                  .Keys;

    // if we pass to action any query string parameter which doesn't 
    // exists in action we should return 404 status code

    if(queryParameters.Cast<object>().Any(queryParameter 
                                 => !actionParameters.Contains(queryParameter)))
        filterContext.Result = new HttpStatusCodeResult(404);
}

Actually, if you don't want to write this is in every controller, you should override DefaultControllerFactory