Middleware, Filter and Attributes.
Examples:
Attributes
Middleware
Filter
Middleware
Lets create a Custom Middleware, We will create logging middleware which logs requests and outgoing responses
There are multiple way to write code in middleware but in this we will using extension method to create our middleware
app.use(), app.map() and aap.run() these are the methods to configure request delegates
The first Run delegate is always terminal and terminates the pipeline. Run is a convention.
Don't write response after next.Invoke method only do logging and other stuff
If another Use or Run delegate is added after the Run delegate, it's not called.
Order of middleware: It is important to put middleware in the right order to achieve expected behavior, security and performance.
Our custom middleware sits after authorization , check the order before adding custom middleware, it should be in proper order
Filter is another topic we will learn it as well after middleware
The order is critical for security, performance, and functionality.
In above image code you can see we created our custom Middleware, Now we can add it in Programe.cs file
We can directly register our middleware using app.UseMiddleware<LoggingMiddleware>(); method or we can wrap it in static class i.e extension method so we can use it as app.useLoggig();
OR
Create a static class and register our middleware in extension method in IApplicationBuider
Now use our middleware in programe.cs file
Custom Exception Middleware
Filter
Filter Pipelines
Filters:
What is filter
When to use and where to use
Use cases of filter
How to create and register custom filter
Built-in filters
In the above image you can see Filters and how they execute in specific order by endpoint middleware.
In ASP.NET Core, filters allow you to execute code before or after specific stages in the request processing pipeline. These stages are:
Authorization: Runs before the other stages to determine whether the current user is authorized to access the requested resource.
Resource: Executes after authorization but before model binding. It is used to make decisions based on the request context or modify the request.
Action: Executes code before and after the action method is called. These are the most commonly used filters and are typically applied to perform actions such as logging, validation, or modifying the action result.
Exception: Runs only when an unhandled exception occurs during the request processing. It can be used to handle errors and return custom error responses.
Result: Runs before and after the execution of the action result. It can be used to modify the action result or to perform actions such as logging the result or modifying the HTTP response.
Lets create and register Custom middleware
Create a custom Filter by implementing IActionFilter
Register filter in Program.cs file or using Service filter on controller level
We have to remember IActionFilter interface whenever we want to create custom filter, We have to create a class (eg. loggerFilter) and we have to implement IActionFilter interface in LoggerFilter class
Visual studio intelligent system will show the error when you implement IActionFilter, to resolve we have to implement IActionFilter’s method in loggerFilter class we can use VS intel. Feature to automatically implement the method, like in below images.
Logger Filter code
Lets globally register this filter so we can use it for every controller, Open Program.cs file add the below code there
Globally Register it in AddController method of IServiceCollection
To test it run code in debug mode and put breakpoint in filter, it will stop the code there
Register Filter on controller level using ServiceFIlter
Controller or Method (Locally) specific Register of logger filter
And update our Program.cs file again, We have to remove globally register LoggerFilter and register LoggerFilter in DI container
Register it in Services(DI)
Remove or comment globally on the register filter.
Apply Filter on Controller or Method
Or Method
OR
So this is how we can use filters in our application to handle cross-cutting concerns.
Attributes
Attributes allow you to add metadata into code. It is used to decorate classes, methods, properties and fields etc.. to provide additional information that can be accessed on runtime.
There are many built-in attributes available in .net.
Lets create custom attribute: To do so we have to derive new class from Attribute class,
Create Custom Attribute using Attribute base class
Apply this Custom Attribute on Method.
In above we apply the description attribute and decorate it on method, this attribute used to describe about method or other element of code eg. class field etc.
We can also get this information using Reflector.
Let's implement a role-based authorization system using Attribute and Action filters. This will be a high-level overview but can be easily scalable.
Prerequisites:
Filter: Check if the user has permission to access the resource.
Attribute: Set metadata on the controller's method.
Step-by-Step Implementation:
Create a Custom Attribute:
This attribute will set the "Allow Access" metadata on the controller's method when annotated.
Create a Custom Filter:
This filter will check if the user has the proper permissions to access the resource.
Example:
User Peter logs into the system and has the Order:Read permission. This means Peter can only access the Order API methods that have read access, but cannot access actions like Order:Write or Order:Delete.
We have a GetOrder method annotated with [AllowAccess("Order:Read")]. This attribute indicates that only users with the Order:Read permission can access this method.
We use JWT for authentication. When Peter logs in, he is provided with a JWT token with a claim set to Order:Read, which means Peter can access the GetOrder method.
We have a CheckAccessFilter that verifies whether the user has the appropriate permission. If the user has permission, access to the resource is granted; otherwise, a forbidden access exception is thrown.
Now Register the CheckAccessFilter globally in Program.cs file
Use AllowAccess Attribute on Method.
Let's run the code and test it.
First Check user without Order:Read Permission
User peter has no Permission Claim, Try to access Order method with it.
Expected result : Forbidden
Now check User with Permission Order:Read, let's give peter Order:read permission
User has Permission claim now check the api again
Expected Response , hence our code is working fine.
The above is for learning to set up RBAC , Instead of using IActionFilter we can IAuthorizationFilter or Directly write our code inside Attribute as well, Or we can use ActionFilterAttribute class
We will test one by one the above method approaches.
Instead of using Attribute and Action filter to check Permission we will use a single custom class to handle this using ActionFilterAttribute this will be used as Attribute see image.
We can also use IAuthorizationFilter to handle RBAC check below code image.
Or use TypeFilter
Program.cs file
We have multiple approaches to handle this use case, each with its benefits.
Using IAuthorizationFilter Interface and AllowAccess Attribute:
This approach allows us to manage authorization and permission access within a single class.
Using ActionFilterAttribute:
With this approach, we don't need to create an AllowAccess attribute separately; we can define the access logic within a single class.
However, this approach does not support dependency injection (DI). If you need to inject dependencies, this method is not suitable. Otherwise, it is efficient and allows managing code in one place.
Using IActionFilter and AllowAccess Attribute:
If you want to use dependency injection and prefer not to use IAuthorizationFilter, you can opt for IActionFilter combined with the AllowAccess attribute.
To understand the order and interaction of Middleware and Filters, you can place debugger breakpoints in your middleware, filter, and controller levels. Then, you can perform step-by-step debugging (F10) to observe how they work.
Useful Built-in Attributes
[Authorize]: Specifies that access to a controller or action method is restricted to users who meet the authorization requirement.
[AllowAnonymous]: Allows anonymous users to access a controller or action method, even if [Authorize] is applied globally or to the controller.
[Route]: Defines a route template for a controller or action method.
[HttpGet] ,[HttpPost] , [HttpPut("{id}")] , [HttpDelete("{id}")] , [HttpPatch("{id}")]
Model Binding and Validation [BindProperty]
[FromBody]: Binds a parameter to the body of the request.
[FromQuery]: Binds a parameter to the query string.
[FromRoute]: Binds a parameter to a route value.
[FromHeader]: Binds a parameter to a request header.
[FromForm]: Binds a parameter to form data.
[Required]: Specifies that a data field is required.
[StringLength]: Specifies the minimum and maximum length of a string data field.
[ApiController]: Specifies that a controller responds to web API requests. This attribute makes attribute routing a requirement, automatically validates model state, and provides other API-specific behaviors.
[Produces]: Specifies the type of response an action returns.
[ProducesResponseType]: Specifies the type of response and HTTP status code returned by an action.
[ValidateAntiForgeryToken]: Validates the anti-forgery token in requests.
[Consumes]: Specifies the type of request an action accepts.
[NonAction] attribute. When you have private methods or any methods in a controller that you do not want to expose as actions, you can use the [NonAction] attribute.
[ResponseCache]: Sets caching parameters for responses.
Useful built-in Filters
ExceptionFilterAttribute: A base class for creating custom exception filters.
ResultFilterAttribute: A base class for creating custom result filters that run code before and after the action result executes.
Useful built-in Middleware
Asdfasdf
Static Files Middleware Serves static files such as HTML, CSS, images, and JavaScript.
Authentication Middleware Enables authentication capabilities.
Authorization Middleware Enforces authorization policies.
Routing Middleware Matches request URLs to route handlers.
Endpoint Middleware Executes the matched endpoint.
CORS Middleware Configures Cross-Origin Resource Sharing.
HTTPS Redirection Middleware Redirects HTTP requests to HTTPS.
HSTS Middleware Adds HTTP Strict Transport Security headers.
Developer Exception Page Middleware Provides detailed error information during development.
Exception Handling Middleware Catches exceptions and generates error responses.
Status Code Pages Middleware Generates responses for HTTP status codes like 404, 500, etc.
Response Compression Middleware Compresses response data.
Response Caching Middleware Caches responses.
Session Middleware Enables session state.
Request Localization Middleware Configures localization for the request.
Forwarded Headers Middleware Forwards headers from reverse proxies.
WebSockets Middleware Enables WebSocket protocol.
File Server Middleware Serves static files and enables directory browsing.
Cookie Policy Middleware Manages cookie settings and consent.
Health Checks Middleware Provides application health checks.
Comments
Post a Comment