Search code examples
c#metaprogrammingaoppostsharp

How to share certain metadata between several aspects applied on the same object?


I have these three aspects, applied on certain class:

[Serializable]
[MulticastAttributeUsage(PersistMetaData = true)]
public class MetaDataAspect : LocationInterceptionAspect, IInstanceScopedAspect
{
    public MetaData ThisMetaData = new MetaData();

    public object CreateInstance(AdviceArgs adviceArgs) { return MemberwiseClone(); }
    public void RuntimeInitializeInstance() {}
}

[Serializable]
[MulticastAttributeUsage(MulticastTargets.Method)]
public class CallInterceptionAspect : MethodLevelAspect, IMethodInterceptionAspect
{
    public void OnInvoke(MethodInterceptionArgs args){
        GetMetaData().ThisMetaData.Id = args.Arguments[0];
    }
}

[Serializable]
[MulticastAttributeUsage(MulticastTargets.Property)]
public class WmiClassPropertyAspect : LocationInterceptionAspect
{
    public override void OnGetValue(LocationInterceptionArgs args)
    {
        args.Value = GetMetaData().ThisMetaData.Id;
    }
}

How do I implement the GetMetaData() method so it gives me the ThisMetaData matadata?


Solution

  • Quick answer - introduce an interface and use it from method-level aspects.

    Basically you need to do the following:

    public interface IThisMetaDataProvider
    {
        Metadata ThisMetadata {get;}
    }
    
    [Serializable]
    [MulticastAttributeUsage(PersistMetaData = true)]
    [IntroduceInterface(typeof(IThisMetadataProvider))]
    public class MetaDataAspect : LocationInterceptionAspect, IInstanceScopedAspect
    {
        public Metadata ThisMetadata {get; private set;}
    
        public void RuntimeInitializeInstance() { ThisMetadata = new Metadata(); }
    
        ...
    }
    
    [Serializable]
    [MulticastAttributeUsage(MulticastTargets.Method)]
    public class CallInterceptionAspect : MethodLevelAspect, IMethodInterceptionAspect
    {
        public void OnInvoke(MethodInterceptionArgs args)
        {
            ((IThisMetadataProvider)args.Instance).ThisMetaData.Id = args.Arguments[0];
        }
    }
    

    You can also use IAspectProvider and IAspectRepositoryService (from 4.0 onward) to provide MetaDataAspect automatically to a class when CallInterception is used on a method.