Как связать приемники сообщений в объекте, связанном с контекстом (аспектно-ориентированное программирование) - PullRequest
4 голосов
/ 14 сентября 2011

Я пытаюсь использовать ContextBoundObject и приемники сообщений для добавления некоторых аспектов в мой код.

Моя проблема в том, что мой аспект вызывается только один раз - когда я звоню: myFacadee.GetValue("Tie") Я ожидал, что мой аспект кэширования будет вызван дважды

  1. Один раз для метода * GetValue
  2. Во-вторых, для 'GetValues', который вызывается внутри GetValue метод

Однако он вызывается только один раз для первого вызова метода GetValue.

Как можно изменить / исправить следующий код, чтобы убедиться, что все методы в моем объекте MyFacade вызывают активацию аспекта кэширования. Даже если они вызываются другими методами в том же объекте 'MyFacde'?

Вот упрощенный пример того, как выглядит мой код:

Тестовое приложение:

class Program
{
    static void Main(string[] args)
    {
        var myFacadee = new MyFacade();

        System.Console.WriteLine("Value:\t" + myFacadee.GetValue("Tie"));

        System.Console.ReadLine();
    }
}

Фасад:

[Cache]
public class MyFacade : ContextBoundObject
{
    public string GetValue(string name)
    {
        return GetValues().FirstOrDefault(x => x.EndsWith(name));
    }

    public List<string> GetValues()
    {
        return new List<string>
                   {
                       "You asked for a Shirt",
                       "You asked for a Pants",
                       "You asked for a Tie"
                   };
    }
}

CacheAttribute:

[AttributeUsage(AttributeTargets.Class)]
public class CacheAttribute : ContextAttribute
{
    public CacheAttribute() : base("Security") { }

    public override void GetPropertiesForNewContext(IConstructionCallMessage ctorMsg)
    {
        ctorMsg.ContextProperties.Add(new CacheProperty());
    }
}

CacheProperty:

public class CacheProperty : IContextProperty, IContributeObjectSink
{
    public IMessageSink GetObjectSink(MarshalByRefObject o, IMessageSink next)
    {
        return new CacheAspect(next);
    }

    public void Freeze(Context newContext)
    {
        // no op
    }

    public bool IsNewContextOK(Context ctx)
    {
        var newContextLogProperty = ctx.GetProperty("CacheProperty") as CacheProperty;
        if (newContextLogProperty == null)
        {
            Debug.Assert(false);
            return false;
        }
        return (true);
    }

    public string Name { get { return "CacheProperty"; } }
}

CacheAspect:

internal class CacheAspect : IMessageSink
{
    internal CacheAspect(IMessageSink next)
    {
        _next = next;
    }

    private readonly IMessageSink _next;

    public IMessageSink NextSink
    {
        get { return _next; }
    }

    public IMessage SyncProcessMessage(IMessage msg)
    {
        Preprocess(msg);

        var returnMethod = _next.SyncProcessMessage(msg);

        return returnMethod;
    }

    public IMessageCtrl AsyncProcessMessage(IMessage msg, IMessageSink replySink)
    {
        throw new InvalidOperationException();
    }

    private void Preprocess(IMessage msg)
    {
        // We only want to process method calls
        if (!(msg is IMethodMessage)) return;

        var call = msg as IMethodMessage;
        var type = Type.GetType(call.TypeName);
        var callStr = type.Name + "." + call.MethodName;

        var argsString = call.Args.Aggregate((current, next) => current + ", " + next);

        Console.WriteLine("Try to get value form cache : {0} for {1}({2})", callStr, call.MethodName, argsString);
    }
}

Ответы [ 3 ]

2 голосов
/ 14 сентября 2011

Он вызывается только один раз, потому что граница контекста пересекается только один раз.Вызов этого же экземпляра изнутри экземпляра не требует какой-либо сортировки в контексте, поэтому ваш приемник не используется для перехвата сообщения.

0 голосов
/ 01 января 2013

Измените AttributeUsage, чтобы он был нацелен только на Методы, а также укажите «[Cache]» в самом методе, который вам нужен, в вашем случае это должно быть «GetValues», а не «GetValue», что приведет к все элементы, которые будут кэшироваться в коллекции, и позже вы сможете читать из этого кэша.

Один из ведущих компонентов АОП, имеющий репутацию PostSharp

0 голосов
/ 14 сентября 2011

Я не проверял это;Я попробую изменить цель на AttributeTargets.Method.

[AttributeUsage(AttributeTargets.Method)]
public class CacheAttribute : ContextAttribute
...