Disabling Controllers in .NET Core Web API with Custom C# Attribute

Abstract: Disable specific .NET Core Web API endpoints by applying a custom attribute that returns 404 without removing routes.

Created: 2026-08-04 by

To disable controllers in a .NET Core Web API, create a custom attribute inheriting from Attribute and implement an IActionFilter. This filter checks for the attribute on the controller or action during execution and returns a 404 Not Found status code if present. This approach provides a clean, declarative way to hide endpoints without modifying routing configurations.

Understanding the Requirement

In many enterprise applications, there is a need to temporarily or permanently disable specific API endpoints. While one might consider removing routes or using conditional middleware, these approaches often lack granularity or require significant architectural changes. A custom attribute offers a lightweight solution that keeps the logic close to the affected controllers. This method allows developers to mark controllers or individual actions as disabled directly in the code, making it easy to toggle availability through configuration or simple comments.

Why Not Just Remove Routes?

Removing routes entirely can break client-side references or cause confusion during deployment cycles where features are toggled based on environment variables. Using an attribute ensures that the code remains in place but is effectively invisible to the HTTP pipeline. This is particularly useful for deprecated endpoints that should still exist in the codebase for historical reference but must not respond to live traffic.

Creating the Custom Attribute

The first step is to define a custom attribute class. In C#, attributes are classes that inherit from System.Attribute. You can add properties to this attribute if you need to pass additional information, such as a reason for disabling or an expiration date. For basic functionality, a simple marker attribute is sufficient.

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false)]
public class DisableControllerAttribute : Attribute
{
    public string Reason { get; set; }
    
    public DisableControllerAttribute(string reason = "Disabled")
    {
        Reason = reason;
    }
}

This attribute can be applied to either the entire controller class or specific action methods. By setting AllowMultiple to false, we ensure that the attribute is only applied once per target, preventing potential conflicts or ambiguous states.

Implementing the Filter Logic

Attributes themselves do not execute logic; they merely store metadata. To act on this metadata, you need a filter. Implementing IActionFilter is the most appropriate choice because it runs after the action has been selected but before it executes. This allows you to intercept the request and short-circuit the response.

public class DisableControllerFilter : IActionFilter
{
    public void OnActionExecuting(ActionExecutingContext context)
    {
        // Check if the attribute exists on the controller or action
        var disableAttr = context.ActionDescriptor.EndpointMetadata
            .OfType()
            .FirstOrDefault();

        if (disableAttr != null)
        {
            context.Result = new NotFoundResult();
        }
    }

    public void OnActionExecuted(ActionExecutedContext context)
    {
        // No logic needed here
    }
}

The OnActionExecuting method inspects the EndpointMetadata of the current action descriptor. If the DisableControllerAttribute is found, it sets the Result property to a NotFoundResult. This immediately terminates the request pipeline and sends a 404 response to the client, bypassing the actual controller logic entirely.

Registering the Filter

Once the filter is defined, it must be registered in the dependency injection container so that ASP.NET Core knows to invoke it. This is typically done in the Program.cs file or the Startup.cs file, depending on your project structure.

builder.Services.AddControllers(options =>
{
    options.Filters.Add();
});

By adding the filter globally, it will check every incoming request against any controller or action marked with the DisableControllerAttribute. If you prefer to apply it only to specific controllers, you can register it as an instance within the controller itself, but global registration is generally cleaner for cross-cutting concerns like this.

Applying the Attribute

With the infrastructure in place, applying the attribute is straightforward. Simply place the attribute above your controller class or specific action methods.

[DisableController("Deprecated endpoint")]
[ApiController]
[Route("api/[controller]")]
public class OldDataController : ControllerBase
{
    [HttpGet]
    public IActionResult Get()
    {
        return Ok(new { message = "This will never be reached" });
    }
}

In this example, any GET request to /api/olddata will result in a 404 Not Found error. The underlying logic in the Get method is never executed. This is ideal for sunsetting APIs where you want to avoid returning 500 errors or exposing sensitive data from legacy systems.

Handling Configuration-Based Disabling

If you need to disable controllers based on runtime configuration rather than static code, you can enhance the attribute to accept configuration keys. However, this requires injecting IConfiguration into the filter, which adds complexity. For most use cases, static attributes provide sufficient control and maintainability.

Benefits of This Approach

Using a custom attribute for disabling controllers offers several advantages over alternative methods. It keeps the code DRY (Don't Repeat Yourself) by centralizing the logic in one filter. It also improves readability, as developers can instantly see which endpoints are inactive by scanning the attribute usage. Furthermore, it integrates seamlessly with existing MVC pipelines, requiring no changes to routing tables or middleware stacks.

For more insights on managing .NET Core components effectively, you might find Alternative to avoid calculating the total record count when performing pagination helpful for optimizing other aspects of your API performance.

Frequently Asked Questions

Can I return a different status code instead of 404?

Yes, you can return any IActionResult you choose. For example, use new StatusCodeResult(410) for Gone or new BadRequestObjectResult("Disabled") for a clearer error message. Changing the result type allows you to communicate the deprecation status more accurately to clients.

Does this affect Swagger documentation?

Standard Swagger generators like Swashbuckle scan controller types and actions regardless of runtime filters. Therefore, disabled endpoints may still appear in the generated documentation. You would need to configure Swagger to ignore specific controllers or actions manually if you wish to hide them from the UI.

Is there a performance impact?

The performance impact is negligible. The filter runs extremely quickly, simply checking metadata and setting a result. It avoids the overhead of executing the actual controller logic, which is beneficial if the disabled controller contained expensive database queries or external service calls.

How do I handle authentication for disabled endpoints?

Since the filter runs in OnActionExecuting, it executes after authentication middleware has completed its work. If you want to skip authentication entirely for disabled endpoints, you should place the filter logic earlier or ensure that the 404 response is sent before authentication costs are incurred. Typically, however, security best practices suggest that disabled endpoints should still respect authentication policies.

Can I use this attribute in ASP.NET Framework?

While the concept is similar, ASP.NET Framework uses ActionFilterAttribute which inherits from both Attribute and IActionFilter. The implementation details differ slightly, particularly in how you access metadata. You would need to adapt the code to fit the older framework's event model.

Latest News

How to Display Output of xterm Command in Terminal Screen using Cron

Resolve the inability to display xterm output in a terminal screen from cron by redirecting logs or using wall instead of insecure X11 workarounds.

Read More
Expose Local Server on VPS Preserving Real Client IPs (OS Level)

Resolve VPS logging showing only gateway IPs by configuring reverse proxies to forward real client addresses via X-Forwarded-For headers.

Read More
How to Clear Recent Files History in Linux without Deleting Actual Files?

Clear recent files history in Linux by deleting ~/.local/share/recently-used.xbel without removing the actual files.

Read More
Best HDD Copy Strategy: Manually Syncing and Rewriting Scratch

Resolve data drift between two 4TB hard drives by using rsync with the --delete flag to manually sync and rewrite scratch data for an exact mirror.

Read More
Understanding Bash Prompt Abbreviations: An Overview

Resolve repetitive typing errors by creating and persisting Bash aliases in the .bashrc file for improved command-line efficiency.

Read More
Free Tools and Methods to Log Real-Time Performance Details in Task Manager

Log real-time CPU and memory metrics to CSV files using Windows Performance Monitor Data Collector Sets to troubleshoot system slowness.

Read More
Contact Qatar Airways Customer Service: Phone Number, Help Center, and More

Resolve urgent Qatar Airways reservation issues like flight changes and baggage claims using the US phone number +1801-855-5905 or online self-service tools.

Read More
Windows 11: Alt Codes Displaying Wrong Characters - Solutions

Resolve Windows 11 Alt codes showing wrong characters by verifying the US keyboard layout and enabling Num Lock.

Read More
Run Programs with Elevated Privileges: A Comprehensive Guide

Eliminates the need to type sudo for frequent administrative tasks by configuring .bashrc aliases or functions.

Read More
Dynamically Changing Dates in Excel Formulas Using Cells

Eliminate manual date updates in Excel by using cell references to create dynamic formulas that automatically adjust calculations when input dates change.

Read More
Granting Edit Access to a Specific Excel Sheet in an Office 365 User Email ID-Based Login

Excel Online lacks native sheet-level permissions, so users must split workbooks or use worksheet protection to isolate edit access for specific tabs.

Read More
Creating Network Load on Local Wi-Fi from One PC

Generate sustained Wi-Fi bandwidth load from a single PC using a VM SFTP server to test router stability and throughput.

Read More
Changing the Default Editor for Batch Files in Windows 11's File Explorer

Resolve the issue of batch files opening in Notepad by changing the default editor to a preferred application like VS Code.

Read More
Gain WiFi Connection Minutes Before Losing it by Changing MAC Address

Bypass MAC address filtering to restore WiFi connectivity temporarily when a device is blocked by network administrators.

Read More
Photos Folders Turned Black: Troubleshooting Picture Applications on Windows

Resolve black screens in Windows Photos by resetting the app, updating graphics drivers, and repairing system files.

Read More
Troubleshooting High CPU Temperature Values: A Step-by-Step Guide

Resolve high CPU temperatures and thermal throttling by monitoring with Speedfan, cleaning dust from cooling components, and replacing degraded thermal paste.

Read More
Make cURL establish TLS connection with CA unknown

Resolve cURL TLS connection failures with unknown or self-signed certificates by using the --insecure flag to bypass CA validation.

Read More
Troubleshooting Incorrect Network Metrics Values in Grafana, Prometheus, InfluxDB, and Telegraf

Fix incorrect network metrics in Grafana, Prometheus, InfluxDB, and Telegraf by verifying interface selection, resolving unit mismatches, and handling counter resets.

Read More
Start Another Terminal Window (cmd.exe) Windows Repair/Troubleshoot

Provides step-by-step instructions to access the Windows Command Prompt via bootable media for advanced system repair and troubleshooting.

Read More
Thinkpad P1 Gen 6: Sudden Thunderbolt 3 Dock USB-C Charging Stopped Working

Resolve sudden Thunderbolt 3 dock USB-C charging and internet failure on ThinkPad P1 Gen 6 by updating firmware, resetting the dock, and adjusting power settings.

Read More
ASUS Windows 11 Laptop: Internet Connection Issue with Hotspot

Resolve ASUS Windows 11 laptop spinning wheel issue when connecting to mobile hotspot by resetting network stack, disabling IPv6, and adjusting power settings.

Read More
Developing iOS Project with Firebase: Logging in and Sending Push Notifications

Integrates Firebase to enable secure user authentication and push notifications in iOS applications.

Read More
Troubleshooting Bash Script with Suspected Issues of Spaces, Dashes, Filenames and Quoting

Resolve Bash script failures caused by word splitting, globbing, and special characters in filenames by applying proper quoting techniques.

Read More
Populating OneDrive Folder for Local Backup without Affecting Remote Files

Prevent OneDrive from deleting remote files during Windows reinstallation by unlinking the account or using symbolic links to isolate local data.

Read More
Force First Frame as Keyframe Without Re-encoding: A Quick Solution

Resolve inaccurate seeking and playback glitches by re-encoding video to ensure the first frame is a valid keyframe.

Read More
Find Information in Database Using WSL (Ubuntu) on Windows-10

Resolve database connection issues from WSL Ubuntu on Windows 10 by configuring client tools and network access to query remote or local servers.

Read More
Configuring a New Router with Different Networks: One Family, One Guest

Resolve IP conflicts and isolate guest traffic by configuring a second router with a distinct subnet via its WAN port.

Read More
Quickly Open Multiple Stock Websites with a Single Command

Solve the problem of manually opening multiple stock research websites by creating a single command to launch them simultaneously on Windows, macOS, or Linux.

Read More
Improved Adobe Acrobat Search Experience: Access Advanced Search with Ease

Access advanced search filters like case sensitivity and regex in Adobe Acrobat by clicking More Options in the Find bar.

Read More
Port Forwarding VM via OpenVPN: A Comprehensive Guide

Configure OpenVPN server and iptables to forward specific ports from VPN clients to a virtual machine's internal IP address.

Read More
Understanding Partitions in the 1980s: A Look Back at MS-DOS and Master Boot Record

Explains how the Master Boot Record and partition table enabled MS-DOS to manage multiple disk volumes on a single physical drive.

Read More
Windows 10 Enterprise: Keyboard Not Detected in Managed Organization with Admin Privileges

Resolve Windows 10 Enterprise keyboard detection failures caused by Group Policy restrictions, driver corruption, or USB enumeration errors.

Read More
Can't Find x86_64 Versions of Applications on MacOS arm64 (M1)

Resolve missing x86_64 app issues on M1 Macs by installing Rosetta 2 and reinstalling apps as universal binaries.

Read More
How to Hide Installation Source for an Android App

Manage Android app installation source visibility by using USB transfers or file managers to reduce browser traces and isolate data via work profiles.

Read More
Connecting Momentus 4200.2 ST9808210A Hard Drive via USB Cable

Resolve inability to access Seagate Momentus 4200.2 ST9808210A hard drive by connecting it via USB using a compatible SATA-to-USB adapter and configuring the disk in Windows.

Read More