Skip to content

This project is about AOP (Aspect Oriented Programming), one of the paradigms to which OOP belongs [.NET 9.0, C#]

Notifications You must be signed in to change notification settings

MrEshboboyev/aspect-oriented-programming

Repository files navigation

Aspect-Oriented Programming (AOP) in .NET

This project demonstrates the implementation of Aspect-Oriented Programming (AOP) concepts in a .NET Web API application using Castle DynamicProxy.

Table of Contents

  1. What is Aspect-Oriented Programming?
  2. Key Concepts
  3. Project Structure
  4. Implemented Aspects
  5. How It Works
  6. Real-World Examples
  7. Running the Project
  8. Testing
  9. Benefits of AOP
  10. When to Use AOP

What is Aspect-Oriented Programming?

Aspect-Oriented Programming (AOP) is a programming paradigm that aims to increase modularity by allowing the separation of cross-cutting concerns. It does so by adding additional behavior to existing code (an advice) without modifying the code itself, instead separately specifying which code is modified via a "pointcut" specification, such as "log all function calls when the function's name begins with 'set'". This allows behaviors that are not central to the business logic (such as logging) to be added to a program without cluttering the code core to the functionality.

Key Concepts

Aspect

An aspect is a modularization of a concern that cuts across multiple classes. In our implementation, aspects are represented by interceptor classes like LoggingInterceptor.

Join Point

A join point is a point during the execution of a program, such as a method call or an exception being thrown. In our implementation, every method execution is a potential join point.

Pointcut

A pointcut is a predicate that matches join points. Advice is associated with a pointcut expression and runs at any join point matched by the pointcut. In our implementation, pointcuts are defined using custom attributes like [Log].

Advice

Advice is action taken by an aspect at a particular join point. Different types of advice include "around," "before," and "after" advice. In our implementation, advice is implemented in the interceptor methods like OnBefore, OnAfter, etc.

Target Object

A target object is an object being advised by one or more aspects. Also referred to as the advised object. In our implementation, service classes like ProductService are target objects.

Proxy

A proxy is an object created after applying advice to a target object. In our implementation, Castle DynamicProxy creates proxies for our service classes.

Weaving

Weaving is the process of linking aspects with other application types or objects to create an advised object. This can be done at compile time, load time, or runtime. In our implementation, weaving happens at runtime when services are registered with proxy support.

Project Structure

AspectOrientedProgramming.API/
├── Aspects/                    # AOP interceptors and infrastructure
│   ├── BaseInterceptor.cs      # Base interceptor class
│   ├── ProxyFactory.cs         # Proxy creation utilities
│   ├── LoggingInterceptor.cs   # Logging aspect implementation
│   ├── CachingInterceptor.cs   # Caching aspect implementation
│   ├── ValidationInterceptor.cs # Validation aspect implementation
│   ├── SecurityInterceptor.cs  # Security aspect implementation
│   └── PerformanceInterceptor.cs # Performance monitoring aspect
├── Attributes/                 # Custom attributes for AOP
│   ├── LogAttribute.cs         # Attribute for logging
│   ├── CacheAttribute.cs       # Attribute for caching
│   ├── ValidateAttribute.cs    # Attribute for validation
│   ├── AuthorizeAttribute.cs   # Attribute for authorization
│   └── PerformanceAttribute.cs # Attribute for performance monitoring
├── Controllers/                # Web API controllers
│   ├── ProductsController.cs   # Product management endpoints
│   └── OrdersController.cs     # Order management endpoints
├── Models/                     # Data models
│   ├── Product.cs              # Product entity
│   └── Order.cs                # Order entity
├── Services/                   # Business logic services
│   ├── IProductService.cs      # Product service interface
│   ├── ProductService.cs       # Product service implementation
│   ├── IOrderService.cs        # Order service interface
│   └── OrderService.cs         # Order service implementation
└── Program.cs                  # Application entry point

AspectOrientedProgramming.API.Tests/
├── *.cs                        # Unit tests for AOP functionality

Implemented Aspects

Logging

The LoggingInterceptor provides automatic logging of method execution, including method entry, successful completion, and exception handling.

Usage:

[Log]
public Product GetProductById(int id)
{
    // Method implementation
}

How it works:

  1. Before method execution: Logs method name and parameters
  2. After successful execution: Logs method result
  3. On exception: Logs the exception details

Caching

The CachingInterceptor provides automatic caching of method results based on method parameters.

Usage:

[Cache(DurationInMinutes = 5)]
public List<Product> GetAllProducts()
{
    // Method implementation
}

How it works:

  1. Generates a cache key based on method name and parameters
  2. Checks if result exists in cache
  3. If found, returns cached result without executing method
  4. If not found, executes method and caches the result

Validation

The ValidationInterceptor provides automatic validation of method parameters using Data Annotations.

Usage:

[Validate]
public Product CreateProduct(Product product)
{
    // Method implementation
}

How it works:

  1. Validates all method parameters that implement validation attributes
  2. Throws ValidationException if validation fails

Security

The SecurityInterceptor provides authorization checks for method execution.

Usage:

[Authorize(Roles = "Admin")]
public void DeleteProduct(int id)
{
    // Method implementation
}

How it works:

  1. Checks if user is authenticated
  2. Verifies user roles if specified in the attribute

Performance Monitoring

The PerformanceInterceptor monitors method execution time and logs performance warnings.

Usage:

[Performance(WarningThresholdMs = 1000)]
public List<Product> GetAllProducts()
{
    // Method implementation
}

How it works:

  1. Measures method execution time
  2. Logs execution duration
  3. Logs warning if execution exceeds threshold

How It Works

  1. Proxy Creation: When services are registered in Program.cs, Castle DynamicProxy creates proxy objects that wrap the actual service instances.

  2. Method Interception: When a method with an AOP attribute is called, the proxy intercepts the call and executes the appropriate interceptor logic.

  3. Advice Execution: The interceptor executes the cross-cutting concern logic (logging, caching, etc.) before, after, or around the actual method execution.

  4. Method Proceed: The interceptor calls invocation.Proceed() to execute the original method.

Real-World Examples

Product Service with Multiple Aspects

public class ProductService : IProductService
{
    [Cache(10)] // Cache for 10 minutes
    [Log]       // Log method execution
    [Performance(500)] // Warn if takes more than 500ms
    public List<Product> GetAllProducts()
    {
        // Implementation
    }

    [Validate]  // Validate input parameters
    [Log]       // Log method execution
    [Performance(1000)] // Warn if takes more than 1 second
    public Product CreateProduct(Product product)
    {
        // Implementation
    }
}

Order Controller Using AOP-Enhanced Services

[ApiController]
[Route("[controller]")]
public class OrdersController : ControllerBase
{
    private readonly IOrderService _orderService;

    public OrdersController(IOrderService orderService)
    {
        _orderService = orderService;
    }

    [HttpPost]
    [Validate] // Automatically validates the Order parameter
    [Log]      // Automatically logs the method execution
    public IActionResult CreateOrder(Order order)
    {
        // The order parameter is automatically validated
        // Method execution is automatically logged
        var createdOrder = _orderService.CreateOrder(order);
        return CreatedAtAction(nameof(GetOrderById), new { id = createdOrder.Id }, createdOrder);
    }
}

Running the Project

Prerequisites

  • .NET 9.0 SDK
  • Visual Studio or Visual Studio Code

Steps

  1. Clone the repository
  2. Navigate to the project directory:
    cd AspectOrientedProgramming.API
  3. Restore NuGet packages:
    dotnet restore
  4. Build the project:
    dotnet build
  5. Run the application:
    dotnet run
  6. The API will be available at https://localhost:5001 or http://localhost:5000

Testing

The project includes comprehensive unit tests for all AOP functionality.

Running Tests

cd AspectOrientedProgramming.API.Tests
dotnet test

Test Coverage

  • Interceptor functionality
  • Attribute-based pointcut matching
  • Service method interception
  • Cross-cutting concern implementation

Benefits of AOP

  1. Separation of Concerns: Business logic is separated from cross-cutting concerns
  2. Code Reusability: Aspects can be applied to multiple methods/classes
  3. Maintainability: Changes to cross-cutting concerns only need to be made in one place
  4. Reduced Code Duplication: Eliminates repetitive code for logging, caching, etc.
  5. Modularity: Aspects can be easily added, removed, or modified

When to Use AOP

AOP is particularly useful for:

  1. Logging and Tracing: Automatically log method calls and execution details
  2. Caching: Cache expensive method results automatically
  3. Security: Enforce authorization and authentication checks
  4. Transaction Management: Automatically manage database transactions
  5. Performance Monitoring: Monitor and log method execution times
  6. Error Handling: Centralize exception handling and logging
  7. Validation: Automatically validate method parameters
  8. Auditing: Track changes and user actions

Conclusion

This project demonstrates how AOP can be implemented in .NET using Castle DynamicProxy to create clean, maintainable code that separates business logic from cross-cutting concerns. By using attributes to define pointcuts and interceptors to implement advice, we can create powerful, reusable aspects that enhance our application without cluttering the core business logic.

About

This project is about AOP (Aspect Oriented Programming), one of the paradigms to which OOP belongs [.NET 9.0, C#]

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages