pamidur / aspect-injector Goto Github PK
View Code? Open in Web Editor NEWAOP framework for .NET (c#, vb, etc)
License: Apache License 2.0
AOP framework for .NET (c#, vb, etc)
License: Apache License 2.0
For example:
class Program
{
private static StopwatchAspect _StopwatchAspect = new StopwatchAspect();
static void Main(string[] args)
{
var p = new Program();
p.Test2();
}
[Aspect(typeof(StopwatchAspect))]
public void Test()
{
Thread.Sleep(2000);
}
public void Test2()
{
Stopwatch tag = null;
_StopwatchAspect.Start(ref tag);
Thread.Sleep(2000);
_StopwatchAspect.Stop("Test2", ref tag);
}
}
class StopwatchAspect
{
[Advice(InjectionPoints.Before, InjectionTargets.Method)]
public void Start([AdviceArgument(AdviceArgumentSource.Tag)] ref Stopwatch sw)
{
sw = Stopwatch.StartNew();
}
[Advice(InjectionPoints.After, InjectionTargets.Method)]
public void Stop(
[AdviceArgument(AdviceArgumentSource.TargetName)] String name,
[AdviceArgument(AdviceArgumentSource.Tag)] ref Stopwatch sw)
{
sw.Stop();
Console.WriteLine("'{0}' Executed in {1} seconds", name, sw.ElapsedMilliseconds / 1000);
}
}
Looks like this would work well as a fody weaver https://github.com/Fody/Fody
Would you consider also shipping the functionality as a fody extension?
static void Main(string[] args)
{
var value = GetLengthLong("Text");
}
[Aspect(typeof(StopwatchAspect))]
public static Int32 GetLengthLong(String text)
{
Thread.Sleep(2000);
return text.Length;
}
class StopwatchAspect
{
[Advice(InjectionPoints.Around, InjectionTargets.Method)]
public Object New(
[AdviceArgument(AdviceArgumentSource.Name)] String name,
[AdviceArgument(AdviceArgumentSource.Arguments)] Object[] args,
[AdviceArgument(AdviceArgumentSource.Target)] Func<Object[], Object> target)
{
var sw = Stopwatch.StartNew();
var returnValue = target(args);
sw.Stop();
Console.WriteLine("'{0}' Executed in {1} seconds", name,
sw.ElapsedMilliseconds / 1000);
return returnValue;
}
}
An unhandled exception of type 'System.InvalidProgramException' occurred in ConsoleApplication1.exe
Additional information: JIT Compiler encountered an internal limitation
And replace custom data like this:
[Aspect(typeof(NotifyAdvicesClass), CustomData = new string[]{"ThatProperty"})]
==>
[NotifyThis(NotifyAlso='ThatProperty')]
"AspectDefinition" is an internal class definition, then how could I get this class for creating custom Attribute in the "outside assembly" ?
I used following test case for creating custom attribute.
It should be possible to suppress the exception after handling.
[Advice(InjectionPoints.Before, InjectionTargets.Method)]
public void HandleException(
[Arg(Source.Instance)] Object owner,
[Arg(Source.TargetException)] Exception targetException)
{
UiHelper.ShowError((FrameworkElement)owner, targetException);
//TODO: don't throw the exception
}
Version 1.0.0-beta4
I'm test this code:
public class StupidAspect
{
[Advice(InjectionPoints.Before, InjectionTargets.Method)]
public void StartMethod([AdviceArgument(AdviceArgumentSource.Name)]string methodName)
{
Console.WriteLine("start " + methodName);
}
[Advice(InjectionPoints.After, InjectionTargets.Method)]
public void StopMethood([AdviceArgument(AdviceArgumentSource.Name)]string methodName)
{
Console.WriteLine("end " + methodName);
}
}
[Aspect(typeof(StupidAspect))]
public class TestClass
{
CancellationToken token;
private CancellationTokenSource cancellationTokenSource;
public TestClass()
{
cancellationTokenSource = new CancellationTokenSource();
token = cancellationTokenSource.Token;
}
public async Task Start()
{
await Method1();
}
private async Task Method1()
{
try
{
await Wait(); // must throw exception
}
catch (Exception exp)
{
Console.WriteLine("Operation cancel");
}
}
private async Task Wait()
{
await Task.Delay(10000, token);
}
public void Cancel()
{
cancellationTokenSource.Cancel();
}
}
class Program
{
static void Main(string[] args)
{
TestClass testClass = new TestClass();
testClass.Start();
testClass.Cancel();
Console.ReadKey();
}
}
Console output:
start Start
start Method1
start Wait
start Cancel
end Cancel
end Wait
end Method1
end Start
Must be:
start Start
start Method1
start Wait
start Cancel
Operation cancel
end Cancel
end Wait
end Method1
end Start
Steps to reproduce:
Error 1 NullReferenceException: Object reference not set to an instance of an object.
at AspectInjector.BuildTask.Extensions.TypeExtensions.IsTypeOf(TypeReference typeReference1, TypeReference typeReference2)
at AspectInjector.BuildTask.Extensions.TypeExtensions.IsTypeOf(TypeReference typeReference, Type type)
at AspectInjector.BuildTask.Contexts.TargetMethodContext.SetupSingleReturnPoint(Instruction suggestedSingleReturnPoint)
at AspectInjector.BuildTask.Contexts.TargetMethodContext.SetupReturnPoints()
at AspectInjector.BuildTask.Contexts.TargetMethodContext..ctor(MethodDefinition targetMethod)
at AspectInjector.BuildTask.Contexts.MethodContextFactory.GetOrCreateContext(MethodDefinition md)
at AspectInjector.BuildTask.Processors.ModuleProcessors.InjectionProcessor.ProcessAspectAttributes(MethodDefinition targetMethod, String targetName, IEnumerable`1 aspectAttributes)
at AspectInjector.BuildTask.Processors.ModuleProcessors.InjectionProcessor.ProcessModule(ModuleDefinition module)
at AspectInjector.BuildTask.Processors.AssemblyProcessor.Process(AssemblyDefinition assembly)
at AspectInjector.BuildTask.AspectInjectorBuildTask.Execute()
ITWORK.Solutions.FishingForecast.WebServices
Since AI modifies assembly before Code contracts, we have to inject code after code contracts notions
That will enable to use defined aspects later and make build task flow easier
now in case a method references a type from broker - we fire
throw new CompilationException("Types from AspectInjector.Broker can't be referenced", method);
instead we need to point to exact line of code, like this
throw new CompilationException("Types from AspectInjector.Broker can't be referenced", instruction);
This can be easily done via reflection, but it requires extra overhead for each new instance. As far as I understand, if this is done the same way as the others AdviceArgumentSource, there will be now overhead. For InjectionTargets.Getter return both Getter and Setter MethodInfo. Same for InjectionTargets. Add and InjectionTargets.EventRemove.
Some use case: implement INotifyPropertyChanged and check if property is changed.
In the current version I cannot do anything better than(maybe there is a better way?):
private bool _hasChanged;
private MethodInfo _getter;
[Advice(InjectionPoints.Before, InjectionTargets.Setter)]
public void NotifyChangeBefore([AdviceArgument(AdviceArgumentSource.Instance)] object instance,
[AdviceArgument(AdviceArgumentSource.TargetName)] string name,
[AdviceArgument(AdviceArgumentSource.TargetArguments)] object[] parameters,
[AdviceArgument(AdviceArgumentSource.AbortFlag)] ref bool abort)
{
if (_getter == null)
{
var t = instance.GetType();
var p = t.GetProperties().Single(info => info.Name == name);
_getter = p.GetGetMethod();
}
var oldValue = _getter.Invoke(instance, null);
var newValue = parameters.Single();
_hasChanged = !Equals(oldValue, newValue);
if (!_hasChanged)
abort = true;
}
So one can get MethodInfo.
The main point here that TargetName returns "PropertyName" but not "set_PropertyName" which could be useful
In Debug mode code builds just fine and work.
See class which causes exception below:
Error 202 ArgumentOutOfRangeException: Specified argument was out of the range of valid values.
Parameter name: target
at Mono.Cecil.Cil.ILProcessor.InsertBefore(Instruction target, Instruction instruction)
at AspectInjector.BuildTask.Contexts.TargetMethodContext.SetupSingleReturnPoint(Instruction suggestedSingleReturnPoint)
at AspectInjector.BuildTask.Contexts.TargetMethodContext.SetupReturnPoints()
at AspectInjector.BuildTask.Contexts.TargetMethodContext..ctor(MethodDefinition targetMethod)
at AspectInjector.BuildTask.Contexts.MethodContextFactory.GetOrCreateContext(MethodDefinition md)
at AspectInjector.BuildTask.Processors.ModuleProcessors.InjectionProcessor.ProcessAspectAttributes(MethodDefinition targetMethod, String targetName, IEnumerable`1 aspectAttributes)
at AspectInjector.BuildTask.Processors.ModuleProcessors.InjectionProcessor.ProcessModule(ModuleDefinition module)
at AspectInjector.BuildTask.Processors.AssemblyProcessor.Process(AssemblyDefinition assembly)
at AspectInjector.BuildTask.AspectInjectorBuildTask.Execute()
OR.Data.Core
Target class
[Export(typeof(IPatientsService))]
[Aspect(typeof(TraceAspect))]
public class PatientsService : IPatientsService
{
private readonly IDiagnosisRepository _diagnosisRepository;
private readonly IDispensaryMarkRepository _dispensaryMarkRepository;
private readonly IPassportRepository _passportRepository;
private readonly IClinicalGroupsRepository _clinicalGroupsRepository;
private readonly ISendCallRepository _sendCallRepository;
[ImportingConstructor]
public PatientsService(IPassportRepository passportRepository,
IDiagnosisRepository diagRepository,
IDispensaryMarkRepository dispensaryMarkRepository,
IClinicalGroupsRepository clinicalGroupsRepository,
ISendCallRepository sendCallRepository)
{
_diagnosisRepository = diagRepository;
_dispensaryMarkRepository = dispensaryMarkRepository;
_passportRepository = passportRepository;
_clinicalGroupsRepository = clinicalGroupsRepository;
_sendCallRepository = sendCallRepository;
}
public IDiagnosis CreateNewDiagnosis()
{
return _diagnosisRepository.Create();
}
public IPatient GetById(string id)
{
var passport = _passportRepository.GetById(id);
if (passport == null)
{
return null;
}
var diagnoses = _diagnosisRepository.GetAllForPatient(id);
var clinicalGroups = _clinicalGroupsRepository.GetAllForPatient(id);
var patient = new Patient(passport, diagnoses, clinicalGroups);
return patient;
}
public void DeletePatient(IPatient patient)
{
var passport = _passportRepository.GetById(patient.Id);
if (passport != null)
{
//diagnoses delete by dbTrigger
_passportRepository.DeleteByKey(passport.Id);
}
}
public string GeneratePatientId()
{
return _passportRepository.GeneratePatientId();
}
public IPassport GetPassport(IPatient patient)
{
return _passportRepository.GetById(patient.Id);
}
public void AddPatient(IPatient patient)
{
if (patient.Passport == null)
{
throw new ArgumentException("Can't to add patient without passport");
}
_passportRepository.Create(patient.Passport);
}
public void UpdatePatient(IPatient patient)
{
if (patient.Passport == null)
{
throw new ArgumentException("Can't to update patient without passport");
}
var pasp = _passportRepository.GetById(patient.Id);
if (pasp != null)
{
//ToDo: update fields for item from DB???
_passportRepository.Update(patient.Passport);
}
}
public IEnumerable<IDiagnosis> GetAllDiagnoses(IPatient patient)
{
return _diagnosisRepository.GetAllForPatient(patient.Id);
}
public IDiagnosis GetDiagnosis(IPatient patient, int number)
{
return _diagnosisRepository.Get(patient.Id, number);
}
public void AddDiagnosis(IPatient patient, IDiagnosis diag)
{
var currentDiagnoses = _diagnosisRepository.GetAllForPatient(patient.Id);
diag.Number = currentDiagnoses.Any() ? currentDiagnoses.Max(x => x.Number) + 1 : 1;
_diagnosisRepository.Create(patient.Id, diag);
}
public void UpdateDiagnosis(IPatient patient, IDiagnosis diag)
{
var d = _diagnosisRepository.Get(patient.Id, diag.Number);
if (d != null)
{
_diagnosisRepository.Update(patient.Id, diag);
}
}
public void DeleteDiagnosis(IPatient patient, IDiagnosis diag)
{
var d = _diagnosisRepository.Get(patient.Id, diag.Number);
if (d != null)
{
_diagnosisRepository.Delete(d);
}
}
public void AddClinicGroup(IPatient patient, IClinicalGroup clinicalGroup)
{
_clinicalGroupsRepository.Create(patient.Id, clinicalGroup);
}
public void UpdateClinicalGroup(IPatient patient, IClinicalGroup clinicalGroup)
{
_clinicalGroupsRepository.Update(patient.Id, clinicalGroup);
}
public void DeleteClinicalGroup(IPatient patient, IClinicalGroup clinicalGroup)
{
_clinicalGroupsRepository.Delete(clinicalGroup);
}
public IEnumerable<IPatient> FindBy(IPatientSearchPattern pattern)
{
var pasports = _passportRepository.GetByExpression(pattern);
return pasports.Select(x => new Patient(x));
}
public IEnumerable<IDispensaryMark> GetAllDispensaryMarks(IPatient patient)
{
return _dispensaryMarkRepository.GetAllForPatient(patient.Id);
}
public IDispensaryMark GetDispensaryMark(int identity)
{
Expression<Func<IDispensaryMark, bool>> identityExpression = x => x.Identity == identity;
return _dispensaryMarkRepository.GetByIdentity(identity);
}
public void UpdateDispensaryMark(IDispensaryMark mark, int identity)
{
var dbMark = GetDispensaryMark(identity);
if (dbMark != null)
{
_dispensaryMarkRepository.UpdateByIdentity(identity, mark);
}
else
{
throw new ArgumentException("There is no such dispensary mark ");
}
}
public void DeleteDispensaryMark(int identity)
{
var dbMark = GetDispensaryMark(identity);
if (dbMark != null)
{
_dispensaryMarkRepository.DeleteByKey(dbMark);
}
else
{
throw new ArgumentException("There is no such dispensary mark ");
}
}
public void AddDispensaryMark(IPatient patient, IDispensaryMark mark)
{
_dispensaryMarkRepository.Create(patient.Id, mark);
}
public IEnumerable<ISendCall> GetSendedCalls(IPatient patient)
{
return _sendCallRepository.GetAllForPatient(patient.Id);
}
public void DeleteSendCall(ISendCall call)
{
_sendCallRepository.DeleteEntity(call);
}
public ISendCall GetSendCallByIdentity(int identity)
{
return _sendCallRepository.GetByIdentity(identity);
}
}
Steps to reproduce:
Error 2 InvalidCastException: Unable to cast object of type 'Mono.Cecil.TypeReference' to type 'Mono.Cecil.TypeDefinition'.
at AspectInjector.BuildTask.Processors.ModuleProcessors.InjectionProcessor.<>c__DisplayClassd.b__a(CustomAttribute attr)
at System.Linq.Enumerable.WhereSelectListIterator2.MoveNext() at System.Linq.Enumerable.WhereEnumerableIterator
1.MoveNext()
at System.Collections.Generic.List1..ctor(IEnumerable
1 collection)
at System.Linq.Enumerable.ToList[TSource](IEnumerable1 source) at AspectInjector.BuildTask.Processors.ModuleProcessors.InjectionProcessor.ProcessAspectAttributes(MethodDefinition targetMethod, String targetName, IEnumerable
1 aspectAttributes)
at AspectInjector.BuildTask.Processors.ModuleProcessors.InjectionProcessor.ProcessModule(ModuleDefinition module)
at AspectInjector.BuildTask.Processors.AssemblyProcessor.Process(AssemblyDefinition assembly)
at AspectInjector.BuildTask.AspectInjectorBuildTask.Execute()
ConsoleApplication2
Currently there is no other way to get AdviceArgumentSource.Instance (please correct me if I'm wrong) except of using [AdviceArgument(AdviceArgumentSource.Instance)] in [Advice(InjectionPoints.Before, InjectionTargets.Setter)](or similar). This creates an overhead because it is passed every time Advice is called and it is the same(instance value cannot be changed). My suggestion is to allow using AdviceArgumentSource.Instance in ctor or/and in AspectFactoryAttribute. So user has the ability to get values that don't change only once, without stack overhead.
Exception error:
Exception: Cannot find base class ctor call
at AspectInjector.BuildTask.Extensions.MemberExtensions.FindBaseClassCtorCall(MethodDefinition md)
at AspectInjector.BuildTask.Contexts.TargetMethodContext.SetupEntryPoints()
at AspectInjector.BuildTask.Contexts.TargetMethodContext..ctor(MethodDefinition targetMethod)
at AspectInjector.BuildTask.Contexts.MethodContextFactory.GetOrCreateContext(MethodDefinition md)
at AspectInjector.BuildTask.Contexts.TypeContextFactory.b__2(MethodDefinition c)
at System.Linq.Enumerable.WhereSelectEnumerableIterator2.MoveNext() at System.Linq.Buffer
1..ctor(IEnumerable1 source) at System.Linq.Enumerable.ToArray[TSource](IEnumerable
1 source)
at AspectInjector.BuildTask.Contexts.TypeContextFactory.GetOrCreateContext(TypeDefinition td)
at AspectInjector.BuildTask.Processors.ModuleProcessors.InjectionProcessor.<>c__DisplayClass12.b__f(AspectDefinition def)
at System.Linq.Enumerable.WhereSelectListIterator2.MoveNext() at System.Linq.Enumerable.WhereEnumerableIterator
1.MoveNext()
at System.Collections.Generic.List1..ctor(IEnumerable
1 collection)
at System.Linq.Enumerable.ToList[TSource](IEnumerable1 source) at AspectInjector.BuildTask.Processors.ModuleProcessors.InjectionProcessor.ProcessAspectDefinitions(MethodDefinition targetMethod, String targetName, IEnumerable
1 aspectDefinitions)
at AspectInjector.BuildTask.Processors.ModuleProcessors.InjectionProcessor.ProcessModule(ModuleDefinition module)
at AspectInjector.BuildTask.Processors.AssemblyProcessor.Process(AssemblyDefinition assembly)
at AspectInjector.BuildTask.AspectInjectorBuildTask.Execute()
Class to getenerate error:
public class Runner
{
public Runner() : this(0)
{
}
public Runner(int a)
{
}
[Aspect(typeof(Trace))]
public void Method()
{
}
}
public class MyAspect
{
[Advice(InjectionPoints.Before, InjectionTargets.Method)]
public void AspectMethodRealization(
[AdviceArgument(AdviceArgumentSource.Instance)] object instance)
{
Console.WriteLine("Aspect Works!!!");
}
}
[Aspect(typeof(MyAspect))]
public static class MyStatic
{
public static void StaticTest()
{
Console.WriteLine("Static Test");
}
}
class Program
{
static void Main(string[] args)
{
MyStatic.StaticTest();
}
}
System.InvalidProgramException with message "Common Language Runtime detected an invalid program." appears at 'MyStatic.StaticTest();' line. If remove parameter 'object instance' from AspectMethodRealization() - all good.
In my case i need to read CustomAttributes of target method. Also i need to detect IsPublic or IsPrivate properties of target method (method can be static or non-static, does not matter for me). In previous realization (PostSharp) i do it by reflection (a have MethodBase object for target method), but now a have only TargetName property. So i need to correct Instanse property for getting MathodBase property. Or is there some another way to do it?
If I put an aspect on a static method I get the following runtime error when the method is called:
"Common Language Runtime detected an invalid program"
I am using version 0.9.44
The aspect injector does not kick in when i build from VisualStudio. It works when I run msbuild from command line. I see the following statements in console.
"Assembly has been loaded"
"Assembly has been patched"
"Assembly has been written"
But, when i build it from VS, I don't see these lines and the aspect injector attribute doesn't work. Am i missing something here?
Hi, i found this issue when working with static method in a Generic function.
This is my class model:
class Program
{
static void Main(string[] args)
{
SampleClass<int>.Method1(222);
SampleClass<int>.Method2();
Console.ReadLine();
}
}
[Aspect(typeof(MyLogging))]
public class SampleClass<T>
{
public static void Method1(int x)
{
Console.WriteLine("x");
//...
}
public static int Method2()
{
Console.WriteLine("x");
return 1;
}
}
[Aspect(typeof(Logger < LogToFileProvider>))]
This code fails with "Unhandled Exception: System.BadImageFormatException: An attempt was made to load a program with an incorrect format."
using AspectInjector.Broker;
using System;
namespace ReproduceBug
{
class Program
{
class EmptyAspect
{
[Advice(InjectionPoints.Around, InjectionTargets.Method)]
public object GetResult(
[AdviceArgument(AdviceArgumentSource.Target)] Func<object[], object> target,
[AdviceArgument(AdviceArgumentSource.Arguments)] object[] args)
{
return target.Invoke(args);
}
}
[Aspect(typeof(EmptyAspect))]
static string Execute<T>(T input)
{
return input.ToString();
}
static void Main(string[] args)
{
Execute(0);
}
}
}
In order to have more control over injections we need to make them lazy (via Func provided)
Hi.
I'm investigating your library. It looks like very flexible solution for AOP.
I've tried to use it in Net Core projects but it doesn't look to work.
{
"version": "1.0.0-*",
"buildOptions": {
"emitEntryPoint": true
},
"dependencies": {
"AspectInjector": "1.0.0-beta4"
},
"frameworks": {
"net461": {
}
}
}
using System;
namespace AspectInjectorTest
{
using AspectInjector.Broker;
public class Program
{
public static void Main(string[] args)
{
var container = new Container();
container.Load();
container.Load();
container.Save();
Console.ReadLine();
}
}
[Aspect(typeof(TraceAspect))]
public class Container
{
public string Name { get; set; }
public void Load() { }
public void Save() { }
}
public class TraceAspect
{
private int count;
[Advice(InjectionPoints.Before, InjectionTargets.Method)]
public void CallCountTrace()
{
Console.WriteLine("Call #{0}", count);
count++;
}
}
}
It doesn't show any errors but in console is nothing. The same sample work in previous .Net.
Will you add support of .Net Core for this lib?
Regards.
Igor.
Steps to reproduce:
Error 202 Exception: Cannot find base class ctor call
at AspectInjector.BuildTask.Extensions.MemberExtensions.FindBaseClassCtorCall(MethodDefinition md)
at AspectInjector.BuildTask.Contexts.TargetMethodContext.SetupEntryPoints()
at AspectInjector.BuildTask.Contexts.TargetMethodContext..ctor(MethodDefinition targetMethod)
at AspectInjector.BuildTask.Contexts.MethodContextFactory.GetOrCreateContext(MethodDefinition md)
at AspectInjector.BuildTask.Contexts.TypeContextFactory.b__2(MethodDefinition c)
at System.Linq.Enumerable.WhereSelectEnumerableIterator2.MoveNext() at System.Linq.Buffer
1..ctor(IEnumerable1 source) at System.Linq.Enumerable.ToArray[TSource](IEnumerable
1 source)
at AspectInjector.BuildTask.Contexts.TypeContextFactory.GetOrCreateContext(TypeDefinition td)
at AspectInjector.BuildTask.Processors.ModuleProcessors.InjectionProcessor.<>c__DisplayClassd.b__a(CustomAttribute attr)
at System.Linq.Enumerable.WhereSelectListIterator2.MoveNext() at System.Linq.Enumerable.WhereEnumerableIterator
1.MoveNext()
at System.Collections.Generic.List1..ctor(IEnumerable
1 collection)
at System.Linq.Enumerable.ToList[TSource](IEnumerable1 source) at AspectInjector.BuildTask.Processors.ModuleProcessors.InjectionProcessor.ProcessAspectAttributes(MethodDefinition targetMethod, String targetName, IEnumerable
1 aspectAttributes)
at AspectInjector.BuildTask.Processors.ModuleProcessors.InjectionProcessor.ProcessModule(ModuleDefinition module)
at AspectInjector.BuildTask.Processors.AssemblyProcessor.Process(AssemblyDefinition assembly)
at AspectInjector.BuildTask.AspectInjectorBuildTask.Execute()
OR.WebApplication
InvalidCastException: Unable to cast object of type 'Mono.Cecil.GenericInstanceMethod' to type 'Mono.Cecil.TypeReference'.
at AspectInjector.BuildTask.Processors.ModuleProcessors.Janitor.IsInstructionReferencesBroker(Instruction instruction)
at System.Linq.Enumerable.Any[TSource](IEnumerable1 source, Func
2 predicate)
at AspectInjector.BuildTask.Processors.ModuleProcessors.Janitor.IsMethodBodyReferencesBroker(MethodBody methodBody)
at AspectInjector.BuildTask.Processors.ModuleProcessors.Janitor.CheckMethodReferencesBroker(MethodDefinition method)
at System.Collections.Generic.List1.ForEach(Action
1 action)
at AspectInjector.BuildTask.Processors.ModuleProcessors.Janitor.CheckTypeReferencesBroker(TypeDefinition type)
at System.Collections.Generic.List1.ForEach(Action
1 action)
at AspectInjector.BuildTask.Processors.ModuleProcessors.Janitor.ProcessModule(ModuleDefinition module)
at AspectInjector.BuildTask.Processors.AssemblyProcessor.Process(AssemblyDefinition assembly)
at AspectInjector.BuildTask.AspectInjectorBuildTask.Execute()
Hi.
Trying to use Your library on linux with mono. Created simple aspect and trying to compile project with xbuild. Got next error on build stage:
Aspect Injector has started for TestAspectInjector.exe
Assembly has been loaded
Assembly has been patched
Assembly has been written
: error : Error building target AfterCompile: Exception has been thrown by the target of an invocation.
Done building project "/opt/TestAspectInjector/TestAspectInjector.csproj".-- FAILED
Is it compatible with mono?
I have an aspect that is set up to inject before a property setter, I've found that I get the below compilation issue if I only provide a setter on the property. The compilation issue goes away when a getter is provided.
AspectInjector.0.9.44\build\AspectInjector.targets(5,5): error : NullReferenceException: Object reference not set to an instance of an object.
AspectInjector.0.9.44\build\AspectInjector.targets(5,5): error : at AspectInjector.BuildTask.Contexts.TargetMethodContext.get_MethodResultVariable()
AspectInjector.0.9.44\build\AspectInjector.targets(5,5): error : at AspectInjector.BuildTask.Injectors.AdviceInjector.InjectMethodCallWithResultReplacement(AdviceInjectionContext context, Instruction injectionPoint, Instruction returnPoint, FieldReference sourceMember)
AspectInjector.0.9.44\build\AspectInjector.targets(5,5): error : at AspectInjector.BuildTask.Injectors.AdviceInjector.Inject(AdviceInjectionContext context)
AspectInjector.0.9.44\build\AspectInjector.targets(5,5): error : at AspectInjector.BuildTask.Processors.AspectProcessors.AdviceProcessor.Process(AspectContext context)
AspectInjector.0.9.44\build\AspectInjector.targets(5,5): error : at AspectInjector.BuildTask.Processors.ModuleProcessors.InjectionProcessor.ProcessAspectDefinitions(MethodDefinition targetMethod, String targetName, IEnumerable`1 aspectDefinitions)
AspectInjector.0.9.44\build\AspectInjector.targets(5,5): error : at AspectInjector.BuildTask.Processors.ModuleProcessors.InjectionProcessor.ProcessModule(ModuleDefinition module)
AspectInjector.0.9.44\build\AspectInjector.targets(5,5): error : at AspectInjector.BuildTask.Processors.AssemblyProcessor.Process(AssemblyDefinition assembly)
AspectInjector.0.9.44\build\AspectInjector.targets(5,5): error : at
AspectInjector.BuildTask.AspectInjectorBuildTask.Execute()
My aspect is set up like below
[Advice( InjectionPoints.Before, InjectionTargets.Setter )] public void BeforePropertySetterSecurityCheck( [AdviceArgument( AdviceArgumentSource.AbortFlag )] ref bool abortFlag, [AdviceArgument( AdviceArgumentSource.RoutableData )] object data, [AdviceArgument( AdviceArgumentSource.Instance )] object instance )
and applied on the property like this
[UserRoleRequired( "Basic") ] public int SomeProperty { set { } }
This is a great project. Is simple but powerful. There is a feature that maybe you should consider. If I define a class with an abstract method decorated with an Aspect attribute, I'd like to all implementations of that method should have the aspect injected inside his code. I tested this with 1.0.0-beta3.
Error 202 ArgumentException: Member 'System.Exception' is declared in another module and needs to be imported
at Mono.Cecil.MetadataBuilder.LookupToken(IMetadataTokenProvider provider)
at Mono.Cecil.SignatureWriter.WriteTypeSignature(TypeReference type)
at Mono.Cecil.SignatureWriter.WriteMethodSignature(IMethodSignature method)
at Mono.Cecil.MetadataBuilder.GetMemberRefSignature(MemberReference member)
at Mono.Cecil.MetadataBuilder.CreateMemberRefRow(MemberReference member)
at Mono.Cecil.MetadataBuilder.GetMemberRefToken(MemberReference member)
at Mono.Cecil.MetadataBuilder.LookupToken(IMetadataTokenProvider provider)
at Mono.Cecil.Cil.CodeWriter.WriteOperand(Instruction instruction)
at Mono.Cecil.Cil.CodeWriter.WriteInstructions()
at Mono.Cecil.Cil.CodeWriter.WriteResolvedMethodBody(MethodDefinition method)
at Mono.Cecil.Cil.CodeWriter.WriteMethodBody(MethodDefinition method)
at Mono.Cecil.MetadataBuilder.AddMethod(MethodDefinition method)
at Mono.Cecil.MetadataBuilder.AddMethods(TypeDefinition type)
at Mono.Cecil.MetadataBuilder.AddType(TypeDefinition type)
at Mono.Cecil.MetadataBuilder.AddTypeDefs()
at Mono.Cecil.MetadataBuilder.BuildTypes()
at Mono.Cecil.MetadataBuilder.BuildModule()
at Mono.Cecil.ModuleWriter.b__0(MetadataBuilder builder, MetadataReader _)
at Mono.Cecil.ModuleDefinition.Read[TItem,TRet](TItem item, Func`3 read)
at Mono.Cecil.ModuleWriter.BuildMetadata(ModuleDefinition module, MetadataBuilder metadata)
at Mono.Cecil.ModuleWriter.WriteModuleTo(ModuleDefinition module, Stream stream, WriterParameters parameters)
at Mono.Cecil.ModuleDefinition.Write(Stream stream, WriterParameters parameters)
at Mono.Cecil.ModuleDefinition.Write(String fileName, WriterParameters parameters)
at AspectInjector.BuildTask.AspectInjectorBuildTask.Execute()
OR.Data.Core
First of all - thank you for the library - it is great alternative for PostSharp.
But I have one question about the implementation of the CustomAspect's feature - is it possible to use several attributes on the target?
For example:
TestAspectAttribute source code:
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Constructor | AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Event, AllowMultiple = true)]
[CustomAspectDefinition(typeof(FacSetupAspectImplementation))]
public class TestAspectAttribute : Attribute
{
public string Header { get; private set; }
public string Value { get; set; }
public int data = 42;
public TestAspectAttribute(string header)
{
Header = header;
}
}
TestAspectImplementation
public class TestAspectImplementation
{
[Advice(InjectionPoints.After, InjectionTargets.Method)]
public void AfterMethod([AdviceArgument(AdviceArgumentSource.RoutableData)] object data)
{
var a = (data as TestAspectAttribute);
Checker.Passed = a.Header == "TestHeader" && a.Value == "ololo" && a.data == 43;
}
}
TestClass
public class TestClass
{
[TestAspect("TestHeader", Value = "ololo", data = 43)] // first
[TestAspect("Another", Value = "Hehe", data = 0)] //second
public void Do()
{
Console.Write("");
}
}
And in the decompiled sources we've got:
public class TestClass
{
private FacSetupAspectImplementation __a$_FacSetupAspectImplementation;
[TestAspect("Another", Value = "Hehe", data = 0), TestAspect("TestHeader", Value = "ololo", data = 43)]
public void Do()
{
this.__a$_FacSetupAspectImplementation.AfterMethod(this, new TestAspectAttribute("Another")
{
Value = "Hehe",
data = 0
});
Console.Write("");
}
public TestClass()
{
this.__a$_initializeInstanceAspects();
}
private void __a$_initializeInstanceAspects()
{
if (this.__a$_FacSetupAspectImplementation == null)
{
this.__a$_FacSetupAspectImplementation = new FacSetupAspectImplementation();
}
}
}
Could you please say if it is possible to fix?
static void Main(string[] args)
{
var p = new Program();
p.GetLengthLong();
}
[Aspect(typeof(LoggingAspect))]
public void GetLengthLong()
{
Thread.Sleep(2000);
}
class LoggingAspect
{
[Advice(InjectionPoints.Before, InjectionTargets.Method)]
public void Log([AdviceArgument(AdviceArgumentSource.Method)] MethodInfo method)
{
Console.WriteLine("Calling '{0}'", method.ToString());
}
}
[Aspect(typeof(LoggingAspect))]
class Program
{
static Program()
{
Log(MethodBase.GetCurrentMethod());
}
Program()
{
Log(MethodBase.GetCurrentMethod());
}
static void Main(string[] args)
{
var p = new Program();
Log(MethodBase.GetCurrentMethod());
}
public static void Log(MethodBase method)
{
var baseType = method is MethodInfo ? "Info" : "Base";
Console.WriteLine("Type of method '{0}' is '{1} : Method{2}'", method.ToString(),
method.GetType().Name, baseType);
}
class LoggingAspect
{
[Advice(InjectionPoints.Before, InjectionTargets.Constructor)]
public void Log([AdviceArgument(AdviceArgumentSource.Name)] String name
/*, [AdviceArgument(AdviceArgumentSource.Method)] MethodBase method*/)
{
Console.WriteLine("Calling '{0}'", name);
}
}
}
Source:
class Program
{
static void Main(string[] args)
{
Test();
}
[Aspect(typeof(LoggingAspect))]
static void Test()
{
Console.WriteLine("Processing");
}
}
class LoggingAspect
{
[Advice(InjectionPoints.Around, InjectionTargets.Method)]
public Object Log(
[AdviceArgument(AdviceArgumentSource.Name)] String name,
[AdviceArgument(AdviceArgumentSource.Method)] MethodBase method,
[AdviceArgument(AdviceArgumentSource.Arguments)] Object[] args,
[AdviceArgument(AdviceArgumentSource.Target)] Func<Object[], Object> target)
{
if (name != method.Name) Console.WriteLine("{0} != {1}", name, method.Name);
return target(args);
}
}
Result:
Compiled source:
internal class Program
{
private static LoggingAspect __a$_LoggingAspect;
private static void Main(string[] args)
{
Program.Test();
}
private static void Test()
{
object[] array = new object[0];
object obj = Program.__a$w0_Test(array);
}
private static void __a$_initializeTypeAspects()
{
if (Program.__a$_LoggingAspect == null)
{
Program.__a$_LoggingAspect = new LoggingAspect();
}
}
static Program()
{
// Note: this type is marked as 'beforefieldinit'.
Program.__a$_initializeTypeAspects();
}
private static void __a$o_Test()
{
Console.WriteLine("Processing");
}
[DebuggerHidden, CompilerGenerated]
private static object __a$u_Test(object[] array)
{
Program.__a$o_Test();
return null;
}
[DebuggerHidden, CompilerGenerated]
private static object __a$w0_Test(object[] args)
{
return Program.__a$_LoggingAspect.Log("Test", (MethodBase)MethodBase.GetMethodFromHandle(methodof(Program.__a$o_Test()).MethodHandle), args, delegate
{
Program.__a$o_Test();
return null;
});
}
}
We are using AspectInjector Version 0.9.41 in our portal class library (Targets .NET Framework 4.5+ Windows 8 + Windows Phone 8.1 + Windows Phone Silverlight 8) and Windows phone 8.0 Silverlight app.
Visual Studio 2013 compiles the Solution without any build error.
Visual Studio 2015 compiles the Solution with following errors with Stacktrace
Error PdbDebugException: Unknown custom metadata item kind: 7 at Microsoft.Cci.Pdb.PdbFunction.ReadCustomMetadata(BitAccess bits) at Microsoft.Cci.Pdb.PdbFunction..ctor(ManProcSym proc, BitAccess bits) at Microsoft.Cci.Pdb.PdbFunction.LoadManagedFunctions(BitAccess bits, UInt32 limit, Boolean readStrings) at Microsoft.Cci.Pdb.PdbFile.LoadFuncsFromDbiModule(BitAccess bits, DbiModuleInfo info, IntHashTable names, ArrayList funcList, Boolean readStrings, MsfDirectory dir, Dictionary2 nameIndex, PdbReader reader) at Microsoft.Cci.Pdb.PdbFile.LoadFunctions(Stream read, Dictionary2& tokenToSourceMapping, String& sourceServerData) at Mono.Cecil.Pdb.PdbReader.PopulateFunctions() at Mono.Cecil.Pdb.PdbReader.ProcessDebugHeader(ImageDebugDirectory directory, Byte[] header) at Mono.Cecil.ModuleDefinition.ProcessDebugHeader() at Mono.Cecil.ModuleDefinition.ReadSymbols(ISymbolReader reader) at Mono.Cecil.ModuleReader.ReadSymbols(ModuleDefinition module, ReaderParameters parameters) at Mono.Cecil.ModuleReader.CreateModuleFrom(Image image, ReaderParameters parameters) at Mono.Cecil.ModuleDefinition.ReadModule(Stream stream, ReaderParameters parameters) at Mono.Cecil.ModuleDefinition.ReadModule(String fileName, ReaderParameters parameters) at AspectInjector.BuildTask.AspectInjectorBuildTask.Execute()
Error PdbDebugException: Unknown custom metadata item kind: 6 at Microsoft.Cci.Pdb.PdbFunction.ReadCustomMetadata(BitAccess bits) at Microsoft.Cci.Pdb.PdbFunction..ctor(ManProcSym proc, BitAccess bits) at Microsoft.Cci.Pdb.PdbFunction.LoadManagedFunctions(BitAccess bits, UInt32 limit, Boolean readStrings) at Microsoft.Cci.Pdb.PdbFile.LoadFuncsFromDbiModule(BitAccess bits, DbiModuleInfo info, IntHashTable names, ArrayList funcList, Boolean readStrings, MsfDirectory dir, Dictionary2 nameIndex, PdbReader reader) at Microsoft.Cci.Pdb.PdbFile.LoadFunctions(Stream read, Dictionary2& tokenToSourceMapping, String& sourceServerData) at Mono.Cecil.Pdb.PdbReader.PopulateFunctions() at Mono.Cecil.Pdb.PdbReader.ProcessDebugHeader(ImageDebugDirectory directory, Byte[] header) at Mono.Cecil.ModuleDefinition.ProcessDebugHeader() at Mono.Cecil.ModuleDefinition.ReadSymbols(ISymbolReader reader) at Mono.Cecil.ModuleReader.ReadSymbols(ModuleDefinition module, ReaderParameters parameters) at Mono.Cecil.ModuleReader.CreateModuleFrom(Image image, ReaderParameters parameters) at Mono.Cecil.ModuleDefinition.ReadModule(Stream stream, ReaderParameters parameters) at Mono.Cecil.ModuleDefinition.ReadModule(String fileName, ReaderParameters parameters) at AspectInjector.BuildTask.AspectInjectorBuildTask.Execute()
Please fix this issue.
Show stopper in version AspectInjector 0.9.21
Has been checked at:
Console Application
MVC Application
I have two classes: Base and Child. There is a method in Base that's overriden in Child and that has an Around aspect. Overriden method calls base implementation, but it calls himself instead resulting in StackOverflow exception.
base.GetType() == this.GetType()
returns true
[AspectScope(Instance)]
class AdviceClass{}
[Aspect(AdviceClass)]
class TargetClass {}
So we force scope on advice level? What if my TargetClass is static?
Error: An unhandled exception of type 'System.TypeLoadException' occurred in mscorlib.dll
Source:
[Aspect(typeof(LoggingAspect))]
class Program
{
static Program()
{
Console.WriteLine("Processing .cctor");
}
public Program()
{
Console.WriteLine("Processing .ctor");
}
static void Main(string[] args)
{
var p = new Program();
}
}
class LoggingAspect
{
[Advice(InjectionPoints.Around, InjectionTargets.Constructor)]
public Object Log(
[AdviceArgument(AdviceArgumentSource.Name)] String name,
[AdviceArgument(AdviceArgumentSource.Arguments)] Object[] args,
[AdviceArgument(AdviceArgumentSource.Target)] Func<Object[], Object> target)
{
Console.WriteLine("Calling '{0}'", name);
var ret = target(args);
Console.WriteLine("Called '{0}'\n", name);
return ret;
}
}
Compiled source:
internal class Program
{
private static LoggingAspect __a$_LoggingAspect;
static Program()
{
object[] array = new object[0];
object obj = Program.__a$w0_.cctor(array);
}
public Program()
{
object[] array = new object[0];
object obj = this.__a$w0_.ctor(array);
}
private static void Main(string[] args)
{
Program p = new Program();
}
private static void __a$_initializeTypeAspects()
{
if (Program.__a$_LoggingAspect == null)
{
Program.__a$_LoggingAspect = new LoggingAspect();
}
}
private static void cctor()
{
Program.__a$_initializeTypeAspects();
Console.WriteLine("Processing .cctor");
}
[DebuggerHidden, CompilerGenerated]
private static object cctor(object[] array)
{
Program.__a$o_.cctor();
return null;
}
[DebuggerHidden, CompilerGenerated]
private static object cctor(object[] args)
{
return Program.__a$_LoggingAspect.Log(".cctor", args, delegate
{
Program.__a$o_.cctor();
return null;
});
}
public void ctor()
{
base..ctor();
Console.WriteLine("Processing .ctor");
}
[DebuggerHidden, CompilerGenerated]
public object ctor(object[] array)
{
this.__a$o_.ctor();
return null;
}
[DebuggerHidden, CompilerGenerated]
public object ctor(object[] args)
{
return Program.__a$_LoggingAspect.Log(".ctor", args, delegate
{
this.__a$o_.ctor();
return null;
});
}
}
I trying to mark my static methods by aspect - its not work. On non-static members its work fine. Its bug or i something missing?
The fact is compiler doesn't necessary have to put attributes into an assembly in order they are stated in the code.
The issue is there. Especially in release configuration.
We might introduce Order parameter into AspectAttribute. Don't know what to do with custom attributes though. What is your opinion?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.