Skip to content

Commit a2ef6b6

Browse files
committed
Add docs.
1 parent a7909c7 commit a2ef6b6

File tree

6 files changed

+3127
-54
lines changed

6 files changed

+3127
-54
lines changed

README.md

Lines changed: 183 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,87 +1,216 @@
1-
[ASPeKT]
2-
===
1+
# Aspekt - Aspect-Oriented Programming for .NET
32

43
[![Build status](https://ci.appveyor.com/api/projects/status/ysr9ebr6dwaqamus?svg=true)](https://ci.appveyor.com/project/mvpete/aspekt)
4+
[![.NET](https://img.shields.io/badge/.NET-6.0%20%7C%208.0%20%7C%209.0-blue)](https://dotnet.microsoft.com/)
5+
[![License](https://img.shields.io/badge/license-MIT-green)](LICENSE)
56

6-
A lightweight (Aspect Oriented Programming) AOP foundation
7+
Aspekt is a lightweight, powerful Aspect-Oriented Programming (AOP) foundation library for .NET that allows you to implement cross-cutting concerns using attributes. It supports modern .NET versions including .NET 6.0, 8.0, and 9.0, with async/await patterns and comprehensive Design by Contract capabilities.
78

8-
### Overview
9-
Aspekt is a small AOP foundation library written in C#. Aspect Oriented Programming (AOP) allows to ease the pain associated with cross-cutting concerns. A cross-cutting concern is a pattern that gets across a program that cannot easily be factored into its own module. This raises the so called signal-to-noise ratio. One common cross cutting concern is logging, when logging entry/exit/exception of a function, the code becomes cluttered with log code and the intent can become lost. Aspekt addresses these concerns, by using attributes as annotation of functions. Like PostSharp aspect utilizes post processing of the .NET binaries, inserting the aspects post build. For ASPeKT this is done using Mono.Cecil.
9+
## 🚀 Key Features
1010

11-
### Usage
11+
- **Attribute-Based AOP**: Apply aspects declaratively using C# attributes
12+
- **Async Support**: Full support for async/await patterns with `ValueTask` methods
13+
- **Design by Contract**: Comprehensive contract system with preconditions, postconditions, and invariants
14+
- **Return Value Interception**: Modify return values using `IAspectExitHandler<T>`
15+
- **Modern .NET Support**: Compatible with .NET 6.0, 8.0, 9.0, and .NET Standard 2.1
16+
- **Post-Compilation Weaving**: IL manipulation using Mono.Cecil for zero-overhead aspect application
17+
- **Built-in Logging**: Ready-to-use logging aspects with customizable formatters
18+
- **Thread-Safe**: Designed for multi-threaded applications
19+
20+
## 📦 Installation
21+
22+
```bash
23+
# Core AOP functionality
24+
Install-Package Aspekt
25+
26+
# Design by Contract support
27+
Install-Package Aspekt.Contracts
1228

13-
The foundation of Aspekt is the base Aspect. In order to utilize Aspects, just derive from Aspekt.Aspect and implement the OnEntry, OnExit, OnException methods. Aspekt will only place the calls implemented on the class i.e. OnEntry, OnExit, OnException
29+
# Logging aspects
30+
Install-Package Aspekt.Logging
31+
```
32+
33+
## 🏃‍♂️ Quick Start
1434

35+
### Basic Logging Aspect
1536

1637
```csharp
17-
class SampleAspect : Aspekt.Aspect
38+
using Aspekt;
39+
40+
public class LoggingAspect : Aspect
1841
{
19-
public SampleAspect(String val)
20-
{
21-
}
22-
23-
public void override OnEntry(MethodArgs ma)
24-
{
25-
// called before any existing code is ran
26-
}
27-
28-
public void override OnExit(MethodArgs ma)
29-
{
30-
// called before ANY return statement
31-
}
32-
33-
public void override OnException(MethodArgs ma, Exception e)
34-
{
35-
// called if existing codes excepts
36-
}
42+
public override void OnEntry(MethodArguments args)
43+
{
44+
Console.WriteLine($"Entering: {args.FullName}");
45+
}
46+
47+
public override void OnExit(MethodArguments args)
48+
{
49+
Console.WriteLine($"Exiting: {args.FullName}");
50+
}
51+
52+
public override void OnException(MethodArguments args, Exception ex)
53+
{
54+
Console.WriteLine($"Exception in {args.FullName}: {ex.Message}");
55+
}
3756
}
3857
```
3958

40-
When you use the Aspect in your client code, such as
59+
### Usage
4160

4261
```csharp
43-
class Foo
62+
public class Calculator
4463
{
45-
[SampleAspect("Some Value")]
46-
public void Bar(String s, int i)
64+
[Logging]
65+
public int Add(int x, int y)
4766
{
48-
// Do something here.
67+
return x + y;
68+
}
69+
70+
[Logging]
71+
public async Task<string> GetDataAsync()
72+
{
73+
await Task.Delay(100);
74+
return "Hello, World!";
4975
}
5076
}
5177
```
5278

53-
Aspekt will re-write the code, to something along the lines of the following.
79+
### Advanced: Return Value Modification
5480

5581
```csharp
56-
class Foo
82+
public class ResultModifierAspect : Aspect, IAspectExitHandler<string>
5783
{
58-
[SampleAspect("Some Value")]
59-
public void Bar(String s, int i)
84+
public string OnExit(MethodArguments args, string result)
6085
{
61-
MethodArgs ma = new MethodArgs("Bar", "Assembly.Foo.Bar(String s, int i)", new Arguments(new object[] { s, i }), this);
62-
SampleAspect sa = new SampleAspect("Some Value");
63-
sa.OnEntry(ma);
64-
try
65-
{
66-
// Do Something Here
67-
sa.OnExit(ma);
68-
}
69-
catch(Exception e)
70-
{
71-
sa.OnException(ma,e);
72-
throw;
73-
}
86+
return $"Modified: {result}";
7487
}
7588
}
76-
```
77-
As mentioned earlier, Aspekt will only write functions where they've been overridden. This means, only the methods that you want, are added. As well, Aspekt tries not alter or modify existing code, so if the IL contains multiple returns, Aspekt calls OnExit before each return.
7889

79-
If you're using NuGet to get ASPeKT, your project will have the appropriate post build steps. You can ignore anything below.
90+
public class Service
91+
{
92+
[ResultModifier]
93+
public string GetMessage() => "Original";
94+
// Returns: "Modified: Original"
95+
}
96+
```
97+
98+
### Design by Contract
99+
100+
```csharp
101+
using Aspekt.Contracts;
80102

81-
Since Aspekt works post compile, in order to use it you must run the Bootstrap application against your assembly.
103+
public class BankAccount
104+
{
105+
private decimal _balance;
82106

83-
> Aspekt.Bootstrap.Host [PathToAssembly]
107+
[Invariant(nameof(_balance), Contract.Comparison.GreaterThanEqualTo, 0)]
108+
public decimal Balance => _balance;
109+
110+
[Require(nameof(amount), Contract.Comparison.GreaterThan, 0)]
111+
[Ensure(Contract.Comparison.GreaterThanEqualTo, 0)]
112+
public decimal Deposit(decimal amount)
113+
{
114+
_balance += amount;
115+
return _balance;
116+
}
117+
}
118+
```
119+
120+
## 📚 Documentation
121+
122+
- **[Getting Started Guide](docs/GETTING_STARTED.md)** - Complete guide from installation to advanced features
123+
- **[Contracts Documentation](docs/CONTRACTS.md)** - Design by Contract with preconditions, postconditions, and invariants
124+
- **[API Reference](docs/API.md)** - Detailed API documentation for all components
125+
- **[Examples](docs/EXAMPLES.md)** - Real-world usage examples and patterns
126+
- **[Troubleshooting Guide](docs/TROUBLESHOOTING.md)** - Common issues and solutions
127+
128+
## 🔧 How It Works
129+
130+
Aspekt uses post-compilation IL weaving via Mono.Cecil. When you apply an aspect attribute to a method:
131+
132+
1. **Build Time**: Your code compiles normally
133+
2. **Post-Build**: Aspekt.Bootstrap.Host processes your assembly
134+
3. **IL Weaving**: Aspect calls are injected into your methods
135+
4. **Runtime**: Aspects execute seamlessly with your code
136+
137+
```csharp
138+
// Your code:
139+
[LoggingAspect]
140+
public void DoWork() { /* your logic */ }
141+
142+
// Becomes (conceptually):
143+
public void DoWork()
144+
{
145+
var aspect = new LoggingAspect();
146+
var args = new MethodArguments(/* method info */);
147+
148+
aspect.OnEntry(args);
149+
try
150+
{
151+
/* your original logic */
152+
aspect.OnExit(args);
153+
}
154+
catch (Exception ex)
155+
{
156+
aspect.OnException(args, ex);
157+
throw;
158+
}
159+
}
160+
```
161+
162+
## 🏗️ Project Structure
163+
164+
- **Aspekt**: Core AOP functionality and base `Aspect` class
165+
- **Aspekt.Contracts**: Design by Contract implementation
166+
- **Aspekt.Logging**: Built-in logging aspects with multiple formatters
167+
- **Aspekt.Bootstrap**: IL weaving engine using Mono.Cecil
168+
- **Aspekt.Test**: Comprehensive test suite with 100+ tests
169+
170+
## 🛠️ Build Requirements
171+
172+
- .NET SDK 6.0 or later
173+
- Visual Studio 2022 or VS Code
174+
- MSBuild 17.0+
175+
176+
```bash
177+
# Clone and build
178+
git clone https://github.com/your-org/aspekt.git
179+
cd aspekt
180+
dotnet build
181+
dotnet test
182+
```
183+
184+
## ⚡ Performance
185+
186+
Aspekt is designed for minimal runtime overhead:
187+
- **Zero reflection** at runtime
188+
- **Compile-time weaving** means no performance impact from AOP infrastructure
189+
- **Selective application** - only methods with aspects are modified
190+
- **Async-aware** - proper support for async/await patterns
191+
192+
## 🤝 Contributing
193+
194+
We welcome contributions! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
195+
196+
1. Fork the repository
197+
2. Create a feature branch
198+
3. Add tests for your changes
199+
4. Ensure all tests pass
200+
5. Submit a pull request
201+
202+
## 📄 License
203+
204+
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
205+
206+
## 🙏 Acknowledgments
207+
208+
- Built with [Mono.Cecil](https://github.com/jbevain/cecil) for IL manipulation
209+
- Inspired by PostSharp and other AOP frameworks
210+
- Thanks to all contributors and users
211+
212+
---
84213

85-
This will process the assembly and add in the aspects to their respective members.
214+
**Get started today**: Check out the [Getting Started Guide](docs/GETTING_STARTED.md) to begin using Aspekt in your projects!
86215

87216

0 commit comments

Comments
 (0)