Custom Attributes in C# Web Controllers
17 December 2020
Updated: 03 September 2023
Implementing an attribute for a WebAPI or class in C# can help to reduce duplication and centralize parts of the application logic. This could be used for a variety of tasks such as logging information when methods are called as well as managinng authorization
In this post I’m going to cover the following:
Attribute Types and Execution Order
There are a few different attribute types that we can handle on a WebAPI that provide us with the ability to wrap some functionality around our endpoints, below are some of the common attributes that we can implement and the order in which they execute (StackOverflow)
- Authorization -
IAuthorizationFilter
- Action -
IActionFilter
- Result -
IResultFilter
- Exception -
IExceptionFilter
IActionFilter
The IActionFilter
executes before and after a method is executed and contains two different methods for doing this, namely the OnActionExecuting
and OnActionExecuted
methods respectively. A basic implemtation of IActionFilter
would look like this:
This can then be implemented on a controller method with a [LogStatus]
attribute:
The order of logging which we see will be as follows:
Attribute Initialized
when the controller is instantiatedOnActionExecuting
when the controller is calledExecuting Get
when the controller is executedOnActionExecuted
when the controller is done executing
IAuthorizationFilter
The IAuthorizationFilter
executes as the first filter on a controller’s method call
This can then be implemented on a controller method with a [CustomAuthorize]
attribute:
The order of logging which we see will be as follows:
Attribute Initialized
when the controller is instantiatedOnAuthorization
when the controller is calledExecuting Get
when the controller is executed
Modify Response Data
An attribute’s context
parameter gives us ways by which we can access the HttpContext
as well as set the result of a method call so that it can be handled down the line. For example, we can implement our CustomAuthorize attribute with the following:
This will mean that if we set the context.Result
in our method then the controller will not be executed and the endpoint will return the UnauthorizedResult
early. You can also see that we’re able to access things like the HttpContext
which makes it easy for us to view the request/response data and do things based on that
Attribute on a Class
Note that it’s also possible to apply the above to each method in a class by adding the attribute at the top of the class declaration:
Attributes with Input Parameters
We are also able to create attributes that enable the consumer to modify their behaviour by taking input parameters to the constructor, we can update our LogStatus
attribute to do something like add a prefix before all logs:
Then, applying to our controller method like so:
So the new output will look like so:
Attribute Initialized
when the controller is instantiatedWeatherForecast-Get:OnActionExecuting
when the controller is calledExecuting Get
when the controller is executedWeatherForecast-Get:OnActionExecuted
when the controller is done executing
Attribute Setting at Class and Method Level
Since an attribute can be implemented at a class and method level it’s useful for us to be able to implement it at a class and the override the behaviour or add behaviour for a specific method
We can do this by setting the attribute inheritence to false
Updating out LogStatusAttribute
we can add the AttributeUsage
Attribute as follows:
This means that we can independently apply the attribute at class and method levels, so now our controller can look something like this:
Which will output the logs as follows:
Attribute Initialized
when the controller is instantiatedWeatherForecast:OnActionExecuting
when the class is calledGet:OnActionExecuting
when the controller is calledExecuting Get
when the controller is executedGet:OnActionExecuted
when the controller is done executingWeatherForecast:OnActionExecuted
when the class is done executing