12

Let's say that I have a ASP.NET application that have some APIs.

For example,

{HostName}/api/a/*      
{HostName}/api/b/*

Now I want to disable all {HostName}/api/a/* APIs(But remain /api/b/*). When client call /api/a/* APIs, they get a 404 error. When client call /api/b/* APIs, response normally.

Is there any way to do this in c# ASP.NET application?

Adrian Hall
  • 7,990
  • 1
  • 18
  • 26
Mabraygas
  • 199
  • 1
  • 2
  • 13
  • 3
    delete them in the code? – enkryptor Aug 17 '16 at 08:27
  • You can implement something like `DisableFunctionalityActionFilter` and assign it to a controller / area / action, which must be disabled. – Yeldar Kurmangaliyev Aug 17 '16 at 08:28
  • Just change name of controller name to something meaningless. – Kadaj Aug 17 '16 at 08:29
  • 1
    are you looking for `NonAction` attribute? __To prevent a method from getting invoked as an action, use the NonAction attribute. This signals to the framework that the method is not an action, even if it would otherwise match the routing rules.__ – Amit Kumar Ghosh Aug 17 '16 at 08:29
  • As there are so many APIs I want to disable, and the disable action might be just temporary(might re-enable some day), delete them in code or add an attribute to each function seems too many work to do... – Mabraygas Aug 17 '16 at 08:39
  • Is there some method that can take the advantage of regex and url rewriting or something like that? – Mabraygas Aug 17 '16 at 08:40
  • @Mabraygas you can do URL rewriting in IIS if it's installed, so you can intercept matching requests before they get to your API and redirect them to an error page or something. You can use regexes in that to match the routes you want to disable. – ADyson Aug 17 '16 at 09:09

3 Answers3

27

There are several approaches a can take to disable certain actions or routes as mentioned in the comments.

1.) [NonAction] attribute

The [NonAction] attribute from System.Web.Http can be applied for ApiController actions. If such a method is called then the server returns the HTTP Code 404 (Method not found). The attribute can only be applied on method level and not on classes. So every single method has to be decorated with this attribute.

2.) Writing a custom action filter

This approach gives you more control. Your filter can be applied on class level and you can implement some more advanced logic in which conditions your controller is accessible or not (depending on dates, licences, feature toggles and so forth)

public class MyNoActionFilterAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(HttpActionContext actionContext)
    {            
        if (IfDisabledLogic(actionContext))
        {
            actionContext.Response = new HttpResponseMessage(HttpStatusCode.NotFound);
        }
        else                
          base.OnActionExecuting(actionContext);
    }
}

[MyNoActionFilter]
public class ValuesController : ApiController
{
    // web api controller logic...
}

3.) Route Configuration in WebApiConfig.cs

You can add a web api route for the inaccessible controllers in the WebApiConfig and map this route to a non existant controller. Then the framework takes this route, does not find the controller and sends a 404 return code to the client. It is important to place these routes at the beginning in order to avoid undesired execution.

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        // Web API configuration and services
        
        config.Routes.MapHttpRoute(
            name: "DisabledApi",
            routeTemplate: "api/b/{id}",
            defaults: new { controller = "DoesNotExist", id = RouteParameter.Optional }
        );

        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional }
        );
    }
}

Because you stated not to use attributes because of the amount of work I recommend the third option, because the route configuration defines a single place for this. And if you want to enable the route in the future again you have to remove only one route definition.

Yaseer
  • 506
  • 2
  • 14
Ralf Bönning
  • 14,515
  • 5
  • 49
  • 67
  • For approach number 2 in Net Core, instead of setting `actionContext.Response` you should set `actionContext.Result` so that it returns immediately; i.e: `actionContext.Result = new NotFoundObjectResult(actionContext.ModelState);` – Felipe Correa Jan 17 '22 at 15:22
4

Might be a hack, but works fine for me:

Changing scope of the Controller from public to internal hides all actions from that Controller class. So:

internal class AController : ApiController
{
  [...]
}

Requests to http://host/api/a/* then will fail with "No type was found that matches the controller named 'a'."

Markus
  • 63
  • 2
  • 7
2

Feature flags were built for this purpose

How to enable/disable controllers/routes using feature flags: Tutorial for using feature flags in a .NET Core app | Microsoft Docs

To enable this in your app:

  1. Add the Microsoft.FeatureManagement.AspNetCore nuget package to your project.

  2. Add the feature management service to your builder in Program.cs: builder.Services.AddFeatureManagement();

  3. Add settings for the features you want to turn on and off in appsettings.json:

     { "FeatureManagement": {    
       "AdminAccess": true, 
       "AnonymousAccess": false 
     }
    
  4. Add the FeatureGate decorator to the controllers/actions you want to control access to: [FeatureGate("AnonymousAccess")]

Scott Semyan
  • 187
  • 3