patterncsharpMinor
Inject dependency into PostSharp aspect
Viewed 0 times
aspectintodependencypostsharpinject
Problem
I have designed couple of aspects using PostSharp for different projects, but there is a design flaw in many of them: dependency management.
This is a question about injection of dependencies into aspects, not about dependency injection using aspects
Due to nature of PostSharp post-compilation there are several limitations applied to aspects
-
It's only possible to provide values of value types known during compilation and
After all those limitations, there is only one approach (known to me): provide
PostSharp aspect that has dependency injection
Here is an example of trivial tracing aspect, that has dependency injection
```
[Serializable]
public class TracingAspectAttribute : OnMethodBoundaryAspect
{
// Question #1: Is there any better way to design aspect
// and to inject dependency into it?
public Type AbstractFactoryType { get; set; }
private ILogger Logger { get; set; }
// Compile time validation.
// Question #2: Better approach to ensure during post-compile time
// that abstract factory could be created at runtime using Activator.CreateInstance
public override bool CompileTimeV
This is a question about injection of dependencies into aspects, not about dependency injection using aspects
Due to nature of PostSharp post-compilation there are several limitations applied to aspects
- Constructor injection is not applicable. Constructor will be executed once during post-compilation, then object will be serialized and later deserialized multiple times at runtime. There is a method for runtime initialization
IEventLevelAspect.RuntimeInitialize.
- Neither property injection is possible to do : properties will be initialized before runtime, and IL weaver will rewrite code, so decoration with some kind of
[Injection]attribute will be not possible also
- Neither Ambient context nor Service Locator are not suitable because they will break unit testing isolation
-
It's only possible to provide values of value types known during compilation and
System.Type next to aspect decoration:[MyAspect(integerValue = 1, providedType = typeof(Type))]After all those limitations, there is only one approach (known to me): provide
System.Type of abstract factory or class with factory method, so aspect could creates its instance during runtime initialization and resolves dependency using it.PostSharp aspect that has dependency injection
Here is an example of trivial tracing aspect, that has dependency injection
```
[Serializable]
public class TracingAspectAttribute : OnMethodBoundaryAspect
{
// Question #1: Is there any better way to design aspect
// and to inject dependency into it?
public Type AbstractFactoryType { get; set; }
private ILogger Logger { get; set; }
// Compile time validation.
// Question #2: Better approach to ensure during post-compile time
// that abstract factory could be created at runtime using Activator.CreateInstance
public override bool CompileTimeV
Solution
I've not used PostSharp in a number of years, but have often used the following pattern to get around life-cycle issues with DI on attributes. It's a little manual, so should be seen as the exception rather than the rule, but it's easy to follow.
In your aspect, define a static factory method specifically designed to create your dependency . Define it as a Func and during execution of the aspect, call that func to get an instance of your dependency in the current context.
For example:
This allows you to declaratively bind up your dependencies (unfortunately manually, though I'm sure you could work out some convention for auto-binding), and ensures that your container gives you the correct object on each execution.
I'm not sure if PostSharps IL weaving would interfere with this, but it's simple, clear and effective. We initially started using it to control the life-cycle of injected components that required access to NHibernate ISessions in ASP.NET MVC attributes.
If you intend to wireup many of these types of dependencies, you could likely just use reflection to find any properties on your attributes following a naming convention, and bind them to your container.
This obviously works fine for testability, as you just wire up the Func on your test setup. Obviously, buyer beware if you're running your tests concurrently because of the static.
In your aspect, define a static factory method specifically designed to create your dependency . Define it as a Func and during execution of the aspect, call that func to get an instance of your dependency in the current context.
For example:
public class SomeDependency
{
public void DoSomething()
{
}
}
public class ContainerRegistrationCode
{
public void RegisterTypesInContainer()
{
SomeAspect.CreateSomeDependency = () => new SomeDependency();
// Probably something like
// SomeAspect.GetDependency = () => Kernel.GetService();
// goes here
}
}
public class SomeAspect
{
public static Func CreateSomeDependency { get; set; }
public void OnExecute()
{
//Some behavior
var dependencyINeed = CreateSomeDependency();
dependencyINeed.DoSomething();
}
}This allows you to declaratively bind up your dependencies (unfortunately manually, though I'm sure you could work out some convention for auto-binding), and ensures that your container gives you the correct object on each execution.
I'm not sure if PostSharps IL weaving would interfere with this, but it's simple, clear and effective. We initially started using it to control the life-cycle of injected components that required access to NHibernate ISessions in ASP.NET MVC attributes.
If you intend to wireup many of these types of dependencies, you could likely just use reflection to find any properties on your attributes following a naming convention, and bind them to your container.
This obviously works fine for testability, as you just wire up the Func on your test setup. Obviously, buyer beware if you're running your tests concurrently because of the static.
Code Snippets
public class SomeDependency
{
public void DoSomething()
{
}
}
public class ContainerRegistrationCode
{
public void RegisterTypesInContainer()
{
SomeAspect.CreateSomeDependency = () => new SomeDependency();
// Probably something like
// SomeAspect.GetDependency = () => Kernel.GetService<SomeDependency>();
// goes here
}
}
public class SomeAspect
{
public static Func<SomeDependency> CreateSomeDependency { get; set; }
public void OnExecute()
{
//Some behavior
var dependencyINeed = CreateSomeDependency();
dependencyINeed.DoSomething();
}
}Context
StackExchange Code Review Q#20341, answer score: 9
Revisions (0)
No revisions yet.