-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
3 changed files
with
82 additions
and
261 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,263 +1,69 @@ | ||
# Aspectus | ||
|
||
[![Build status](https://ci.appveyor.com/api/projects/status/j5968toe7ikmj826?svg=true)](https://ci.appveyor.com/project/JaCraig/aspectus) | ||
Aspectus is an advanced Aspect-Oriented Programming (AOP) library that simplifies the injection of cross-cutting concerns into your codebase. It empowers you to write clean and maintainable code by separating cross-cutting concerns from the core logic of your application. | ||
|
||
Aspectus is an AOP library that allows you to inject cross cutting concerns in an easy manner. | ||
## Key Features | ||
|
||
- **Easy Integration**: Aspectus seamlessly integrates with your project by registering with the IoC (Inversion of Control) container during startup. | ||
- **Code Generation**: Leveraging Roslyn, Aspectus generates code dynamically, allowing you to write expressive C# code for implementing aspects. | ||
- **Flexible Aspect Customization**: Implement the `IAspect` interface to define custom logic for constructors, methods, and exception handling. | ||
- **AOP Modules**: Aspectus supports modules, enabling you to consolidate and load setup code efficiently. | ||
- **NuGet Package**: Install Aspectus easily through NuGet, simplifying the setup process for your projects. | ||
|
||
## Setting Up the Library | ||
|
||
Aspectus relies on [Canister](https://github.com/JaCraig/Canister) in order to hook itself up. In order for this to work, you must do the following at startup: | ||
|
||
services.AddCanisterModules(configure => configure.RegisterAspectus()); | ||
The RegisterAspectus function is an extension method that registers it with the IoC container. When this is done, Aspectus is ready to use. | ||
|
||
## Basic Usage | ||
|
||
The way that Aspectus handles AOP is by doing code generation using Roslyn. As such you're writing C# codes for the most part. Start by implementing a class that inherits from IAspect: | ||
|
||
public interface IExample | ||
{ | ||
string MySecretData { get; set; } | ||
} | ||
|
||
public class TestAspect : IAspect | ||
{ | ||
public TestAspect() | ||
{ | ||
AssembliesUsing = new List<MetadataReference>(); | ||
AssembliesUsing.Add(MetadataReference.CreateFromFile(typeof(TestAspect).GetTypeInfo().Assembly.Location)); | ||
foreach (var DLL in new DirectoryInfo(@"C:\Program Files\dotnet\shared\Microsoft.NETCore.App\1.0.0\") | ||
.EnumerateFiles("*.dll") | ||
.Where(x => !DontLoad.Contains(x.Name))) | ||
{ | ||
var TempAssembly = MetadataReference.CreateFromFile(DLL.FullName); | ||
AssembliesUsing.Add(TempAssembly); | ||
} | ||
} | ||
|
||
public ICollection<MetadataReference> AssembliesUsing { get; private set; } | ||
|
||
public ICollection<Type> InterfacesUsing => new Type[] { typeof(IExample) }; | ||
|
||
public ICollection<string> Usings => new string[] { }; | ||
|
||
private string[] DontLoad = { | ||
"sos.dll", | ||
"mscorrc.dll", | ||
"mscorrc.debug.dll", | ||
"mscordbi.dll", | ||
"mscordaccore.dll", | ||
"libuv.dll", | ||
"hostpolicy.dll", | ||
"hostfxr.dll", | ||
"ext-ms-win-ntuser-keyboard-l1-2-1.dll", | ||
"ext-ms-win-advapi32-encryptedfile-l1-1-0.dll", | ||
"dbgshim.dll", | ||
"coreclr.dll", | ||
"clrjit.dll", | ||
"clretwrc.dll", | ||
"clrcompression.dll", | ||
"api-ms-win-service-winsvc-l1-1-0.dll", | ||
"api-ms-win-service-private-l1-1-1.dll", | ||
"api-ms-win-service-private-l1-1-0.dll", | ||
"api-ms-win-service-management-l2-1-0.dll", | ||
"api-ms-win-service-management-l1-1-0.dll", | ||
"api-ms-win-service-core-l1-1-1.dll", | ||
"api-ms-win-service-core-l1-1-0.dll", | ||
"api-ms-win-security-sddl-l1-1-0.dll", | ||
"api-ms-win-security-provider-l1-1-0.dll", | ||
"API-MS-Win-Security-LsaPolicy-L1-1-0.dll", | ||
"api-ms-win-security-lsalookup-l2-1-1.dll", | ||
"api-ms-win-security-lsalookup-l2-1-0.dll", | ||
"api-ms-win-security-cryptoapi-l1-1-0.dll", | ||
"api-ms-win-security-cpwl-l1-1-0.dll", | ||
"api-ms-win-security-base-l1-1-0.dll", | ||
"api-ms-win-ro-typeresolution-l1-1-0.dll", | ||
"API-MS-Win-EventLog-Legacy-L1-1-0.dll", | ||
"API-MS-Win-Eventing-Provider-L1-1-0.dll", | ||
"API-MS-Win-Eventing-Legacy-L1-1-0.dll", | ||
"API-MS-Win-Eventing-Controller-L1-1-0.dll", | ||
"API-MS-Win-Eventing-Consumer-L1-1-0.dll", | ||
"API-MS-Win-Eventing-ClassicProvider-L1-1-0.dll", | ||
"API-MS-Win-devices-config-L1-1-1.dll", | ||
"API-MS-Win-devices-config-L1-1-0.dll", | ||
"api-ms-win-core-xstate-l2-1-0.dll", | ||
"api-ms-win-core-xstate-l1-1-0.dll", | ||
"api-ms-win-core-wow64-l1-1-0.dll", | ||
"api-ms-win-core-winrt-string-l1-1-0.dll", | ||
"api-ms-win-core-winrt-roparameterizediid-l1-1-0.dll", | ||
"api-ms-win-core-winrt-robuffer-l1-1-0.dll", | ||
"api-ms-win-core-winrt-registration-l1-1-0.dll", | ||
"api-ms-win-core-winrt-l1-1-0.dll", | ||
"api-ms-win-core-winrt-error-l1-1-1.dll", | ||
"api-ms-win-core-winrt-error-l1-1-0.dll", | ||
"api-ms-win-core-version-l1-1-0.dll", | ||
"api-ms-win-core-util-l1-1-0.dll", | ||
"api-ms-win-core-url-l1-1-0.dll", | ||
"api-ms-win-core-timezone-l1-1-0.dll", | ||
"api-ms-win-core-threadpool-private-l1-1-0.dll", | ||
"api-ms-win-core-threadpool-legacy-l1-1-0.dll", | ||
"api-ms-win-core-threadpool-l1-2-0.dll", | ||
"api-ms-win-core-sysinfo-l1-2-3.dll", | ||
"api-ms-win-core-sysinfo-l1-2-2.dll", | ||
"api-ms-win-core-sysinfo-l1-2-1.dll", | ||
"api-ms-win-core-sysinfo-l1-2-0.dll", | ||
"api-ms-win-core-sysinfo-l1-1-0.dll", | ||
"api-ms-win-core-synch-l1-2-0.dll", | ||
"api-ms-win-core-synch-l1-1-0.dll", | ||
"api-ms-win-core-stringloader-l1-1-1.dll", | ||
"api-ms-win-core-stringloader-l1-1-0.dll", | ||
"API-MS-Win-Core-StringAnsi-L1-1-0.dll", | ||
"api-ms-win-core-string-obsolete-l1-1-1.dll", | ||
"api-ms-win-core-string-obsolete-l1-1-0.dll", | ||
"API-MS-Win-Core-String-L2-1-0.dll", | ||
"api-ms-win-core-string-l1-1-0.dll", | ||
"api-ms-win-core-shutdown-l1-1-1.dll", | ||
"api-ms-win-core-shutdown-l1-1-0.dll", | ||
"api-ms-win-core-shlwapi-obsolete-l1-1-0.dll", | ||
"api-ms-win-core-shlwapi-legacy-l1-1-0.dll", | ||
"api-ms-win-core-rtlsupport-l1-1-0.dll", | ||
"api-ms-win-core-registry-l2-1-0.dll", | ||
"api-ms-win-core-registry-l1-1-0.dll", | ||
"api-ms-win-core-realtime-l1-1-0.dll", | ||
"api-ms-win-core-psapi-obsolete-l1-1-0.dll", | ||
"api-ms-win-core-psapi-l1-1-0.dll", | ||
"api-ms-win-core-psapi-ansi-l1-1-0.dll", | ||
"api-ms-win-core-profile-l1-1-0.dll", | ||
"API-MS-Win-Core-ProcessTopology-Obsolete-L1-1-0.dll", | ||
"api-ms-win-core-processthreads-l1-1-2.dll", | ||
"api-ms-win-core-processthreads-l1-1-1.dll", | ||
"api-ms-win-core-processthreads-l1-1-0.dll", | ||
"api-ms-win-core-processsecurity-l1-1-0.dll", | ||
"api-ms-win-core-processenvironment-l1-2-0.dll", | ||
"api-ms-win-core-processenvironment-l1-1-0.dll", | ||
"api-ms-win-core-privateprofile-l1-1-1.dll", | ||
"API-MS-Win-Core-PrivateProfile-L1-1-0.dll", | ||
"api-ms-win-core-normalization-l1-1-0.dll", | ||
"api-ms-win-core-namedpipe-l1-2-1.dll", | ||
"api-ms-win-core-namedpipe-l1-1-0.dll", | ||
"api-ms-win-core-memory-l1-1-3.dll", | ||
"api-ms-win-core-memory-l1-1-2.dll", | ||
"api-ms-win-core-memory-l1-1-1.dll", | ||
"api-ms-win-core-memory-l1-1-0.dll", | ||
"api-ms-win-core-localization-obsolete-l1-2-0.dll", | ||
"api-ms-win-core-localization-l2-1-0.dll", | ||
"api-ms-win-core-localization-l1-2-1.dll", | ||
"api-ms-win-core-localization-l1-2-0.dll", | ||
"api-ms-win-core-libraryloader-l1-1-1.dll", | ||
"api-ms-win-core-libraryloader-l1-1-0.dll", | ||
"API-MS-Win-Core-Kernel32-Private-L1-1-2.dll", | ||
"API-MS-Win-Core-Kernel32-Private-L1-1-1.dll", | ||
"API-MS-Win-Core-Kernel32-Private-L1-1-0.dll", | ||
"api-ms-win-core-kernel32-legacy-l1-1-2.dll", | ||
"api-ms-win-core-kernel32-legacy-l1-1-1.dll", | ||
"api-ms-win-core-kernel32-legacy-l1-1-0.dll", | ||
"api-ms-win-core-io-l1-1-1.dll", | ||
"api-ms-win-core-io-l1-1-0.dll", | ||
"api-ms-win-core-interlocked-l1-1-0.dll", | ||
"api-ms-win-core-heap-obsolete-l1-1-0.dll", | ||
"api-ms-win-core-heap-l1-1-0.dll", | ||
"api-ms-win-core-handle-l1-1-0.dll", | ||
"api-ms-win-core-file-l2-1-1.dll", | ||
"api-ms-win-core-file-l2-1-0.dll", | ||
"api-ms-win-core-file-l1-2-1.dll", | ||
"api-ms-win-core-file-l1-2-0.dll", | ||
"api-ms-win-core-file-l1-1-0.dll", | ||
"api-ms-win-core-fibers-l1-1-1.dll", | ||
"api-ms-win-core-fibers-l1-1-0.dll", | ||
"api-ms-win-core-errorhandling-l1-1-1.dll", | ||
"api-ms-win-core-errorhandling-l1-1-0.dll", | ||
"api-ms-win-core-delayload-l1-1-0.dll", | ||
"api-ms-win-core-debug-l1-1-1.dll", | ||
"api-ms-win-core-debug-l1-1-0.dll", | ||
"api-ms-win-core-datetime-l1-1-1.dll", | ||
"api-ms-win-core-datetime-l1-1-0.dll", | ||
"api-ms-win-core-console-l2-1-0.dll", | ||
"api-ms-win-core-console-l1-1-0.dll", | ||
"api-ms-win-core-comm-l1-1-0.dll", | ||
"api-ms-win-core-com-private-l1-1-0.dll", | ||
"api-ms-win-core-com-l1-1-0.dll", | ||
"API-MS-Win-Base-Util-L1-1-0.dll" | ||
}; | ||
|
||
public void Setup(object value) | ||
{ | ||
var ExampleValue = value as IExample; | ||
if (ExampleValue != null) | ||
ExampleValue.MySecretData = "BLAH"; | ||
} | ||
|
||
public string SetupDefaultConstructor(Type baseType) | ||
{ | ||
return ""; | ||
} | ||
|
||
public string SetupEndMethod(MethodInfo method, Type baseType, string returnValueName) | ||
{ | ||
return ""; | ||
} | ||
|
||
public string SetupExceptionMethod(MethodInfo method, Type baseType) | ||
{ | ||
return ""; | ||
} | ||
|
||
public string SetupInterfaces(Type type) | ||
{ | ||
return "public string MySecretData{get; set;}"; | ||
} | ||
|
||
public string SetupStartMethod(MethodInfo method, Type baseType) | ||
{ | ||
return ""; | ||
} | ||
} | ||
|
||
You will notice a couple of things with this code. The first is the most annoying part which is the assembly reference. Thanks to .Net Core's approach to assembly referencing it pushes everything into a dotnet folder. On Linux, Mac, etc. it will be in a different location. On top of that there are a number of DLLs that do not have metadata associated with them and Roslyn breaks if you try to compile against them. As such, if you're using this, you will probably prefer doing a more specified load of just the DLLs that you need and not everything in the NetCore.App directory. Similarly you will need to make sure you are pointing to the correct version. The above is just pointing to 1.0.0, change it accordingly if you wish to target 1.1 or 1.0.1 or something else. | ||
## Installation | ||
|
||
The next bit of code to notice is that you must define any special interfaces you wish the newly generated type to inherit from. It is not possible to specify a base class as the type that is being generated will already be declared based on the type requested. Third property to notice is the Usings property. In the case above we aren't using any but if you would like to add any, that is where you do it. | ||
To install Aspectus, use the NuGet package manager: | ||
|
||
There are then a couple of functions in this class. SetupDefaultConstructor allows you to inject code into the default constructor for the type that you are generating. Any class setup code should be handled here. SetupInterfaces is where you would declare any functions, properties, or fields needed in order to implement the interfaces that you specified earlier. In the example above it returns the MySecretData property defined in the IExample interface. The SetupStartMethod is where you would return any code that you wish to inject at the beginning of the method. SetupEndMethod similarly is where you return any code that you wish to inject at the end of a method call. And lastly there is SetupExceptionMethod. This is where you would return any code that you wish to inject when an exception is thrown by the method. | ||
``` | ||
Install-Package Aspectus | ||
``` | ||
|
||
After the code is constructed, the user calls the Create function on the Aspectus class: | ||
## Getting Started | ||
|
||
public class AOPTestClass | ||
{ | ||
public virtual string A { get; set; } | ||
Follow these steps to start using Aspectus in your project: | ||
|
||
public virtual int B { get; set; } | ||
1. Register Aspectus with your IoC container during startup. Example code for ASP.NET Core: | ||
|
||
public virtual float C { get; set; } | ||
```csharp | ||
services.AddCanisterModules(); | ||
``` | ||
|
||
public virtual List<string> D { get; set; } | ||
} | ||
2. Implement aspects by creating classes that inherit from the `IAspect` interface. Customize aspects based on your specific requirements, such as constructor setups, method injections, and exception handling. | ||
|
||
... | ||
var Test = Canister.Builder.Bootstrapper.Resolve<Aspectus>(); | ||
var Item = (AOPTestClass)Test.Create(typeof(AOPTestClass)); | ||
This will construct a new instance of AOPTestClass and return it to the user. Before it returns it, it will call into your aspect one last time calling the Setup method, passing in the object created. When it does that you can modify the object however you would like prior to it being returned to the end user. From there the end user can modify, use, and debug their object without any issue. | ||
```csharp | ||
public class TestAspect : IAspect | ||
{ | ||
// Implement your aspect logic here | ||
} | ||
``` | ||
|
||
## AOP Modules | ||
3. Utilize Aspectus to create instances of types with injected aspects. | ||
|
||
While you can just create an Aspectus object and call Setup to implement items, you can actually do this when the the object is created for the first time by implementing the IAOPModule interface. By doing this you can tell the system to find and load your setup code all at once instead of doing it in chunks. | ||
```csharp | ||
var aspectus = Canister.Builder.Bootstrapper.Resolve<Aspectus>(); | ||
var item = aspectus.Create<YourClass>(); | ||
// Use and enjoy your enhanced object | ||
``` | ||
|
||
## Installation | ||
For a more detailed guide on using Aspectus, including advanced scenarios and AOP modules, refer to the [Aspectus Documentation](https://jacraig.github.io/Aspectus). | ||
|
||
The library is available via Nuget with the package name "Aspectus". To install it run the following command in the Package Manager Console: | ||
## Build Process | ||
|
||
Install-Package Aspectus | ||
To build Aspectus from source, ensure you have the following: | ||
|
||
## Build Process | ||
- Visual Studio 2022 | ||
- .Net 6 | ||
|
||
In order to build the library you will require the following: | ||
Simply clone the repository and open the solution in Visual Studio. | ||
|
||
1. Visual Studio 2015 with Update 3 | ||
2. .Net Core 1.0 SDK | ||
## Contributing | ||
|
||
Other than that, just clone the project and you should be able to load the solution and build without too much effort. | ||
Contributions are welcome! To contribute to Aspectus, please follow these steps: | ||
|
||
1. Fork the repository. | ||
2. Create your feature branch: `git checkout -b feature/YourFeature`. | ||
3. Commit your changes: `git commit -am 'Add YourFeature'`. | ||
4. Push to the branch: `git push origin feature/YourFeature`. | ||
5. Submit a pull request. | ||
|
||
Please ensure your code follows the existing coding style and includes appropriate tests. Additionally, make sure to update the documentation as needed. |
Oops, something went wrong.