I think the appropriate hook here is the ModelBinder.
You will have to come up with strategy for when you want to return a 404. Based on your details above, and for the sake of simplicity, I am going to assume that any time a parameter named "id" is null or is not passed when expected, that this generates a 404. Here is the example ModelBinder code.
using System.Net;
using System.Web;
using System.Web.Mvc;
public class MyModelBinder : DefaultModelBinder
{
public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
var result = base.BindModel(controllerContext, bindingContext);
if (result == null && bindingContext.ModelName.ToLower() == "id")
{
throw new HttpException((int)HttpStatusCode.NotFound, null);
}
return result;
}
}
You wire this up in Global.asax
:
protected void Application_Start()
{
ModelBinders.Binders.DefaultBinder = new MyModelBinder();
}
To get more granular, you could add an attribute only to parameters that you want this behavior for, and use reflection to inspect for the attribute and only throw the 404 Exception in this case, there will be a performance penalty for that. So you could wire up specific ModelBinders only for models that have this behavior as needed. Or you could maintain a dictionary of Controllers/Actions/Parameters to apply the behavior to as well.
Edit: You also note that you are specifically concerned with GET requests. This value is available in the model binder: controllerContext.RequestContext.HttpContext.Request.HttpMethod.