截取方法调用以获取附加功能的最简单方法是什么?

时间:2010-12-21 07:11:47

标签: structuremap aop interceptor castle-dynamicproxy mixins

假设我有一个存储库,它返回Post的列表。存储库接口有一个GetAll()方法,可以完成它的建议。

现在按照我不应该将域逻辑放在存储库中的理论,我想拦截对具体GetAll()方法的调用,以便我可以将以下逻辑添加到{{1}结果:

GetAll()

我想拦截这个的原因是因为(1)我不想让客户端记得调用扩展方法(return GetAll().OrderByDescending(p => p.Posted).ToList(); 或一些无用的包装器),我想每次都调用它(2)我不想让我所有的具体实现都记得订购OrderByDescending结果 - 我希望这个逻辑在任何存储库外部的一个地方。

最简单的方法是什么?

我已经在使用StructureMap所以如果我可以拦截这个,那么它可能是一个低成本选项。但我不认为SM拦截方法调用,只是创建对象实例?

我需要转到proxy or mixin模式吗?我需要全押城堡Dynamic Proxy吗?或者我应该考虑another method还是组合?

我真的对上面我特定例子的具体建议感兴趣。我是AOP的新手,所以请保持温和。

4 个答案:

答案 0 :(得分:12)

使用DynamicProxy选项。它比我想象的更容易使用。

所有需要的是using Castle.DynamicProxy;参考...

有点IInterceptor ...

public class PostRepoInterceptor : IInterceptor
{
    public void Intercept(IInvocation invocation)
    {
        invocation.Proceed();

        if (invocation.Method.Name.Equals("GetAll", StringComparison.InvariantCultureIgnoreCase))
            invocation.ReturnValue = this.GetModifiedGetAllResult(invocation.ReturnValue);
    }

    private object GetModifiedGetAllResult(object getAllResult)
    {
        return Post.GetOrderedPosts((IList<Post>)getAllResult);
    }
}

StructureMap配置中的两个新行:

    public RepoRegistry()
    {
        var pg = new ProxyGenerator();

        For<IPostRepository>()
            .EnrichAllWith(z => pg.CreateInterfaceProxyWithTarget<IPostRepository>(z, new PostRepoInterceptor()));
    }

..而且已经完成了。 GetAll()现在表现得我想要的。我仍然可以按照我熟悉的方式使用这些接口,并且我将它全部保持干燥并且与DDD分离。

感谢SamAndre

答案 1 :(得分:2)

AFAIK,StructureMap只拦截对象构造,因此使用它不会起作用。

我不知道Castle,但我认为这个想法 - 在这里 - 是应用Decorator pattern,所以你也可以自己做,而不需要按照上面描述的步骤重复到第三方库。上一个链接。

我就是这样做的,因为我不是AOP的忠实粉丝。

HTH

答案 2 :(得分:0)

不,它不能改变返回值。但是,您可以访问目标内部方面以更改目标的属性。假设您已经定义了存储库,这里是添加后处理方面以更改目标属性的代码。

IRepository<decimal> Rep = new Repository();
IRepository<decimal> tpRep = (IRepository<decimal>)ObjectProxyFactory.CreateProxy(Rep,
new String[] { "GetAll" },
null,
new Decoration((x, y) =>
{
    Console.WriteLine("Entering " + x.GetType().ToString());
    if (x.GetType().ToString() == "ThirdPartyHR.Repository")
    {
        List<decimal> decimals = ((Repository)x).RepList;
        IEnumerable<decimal> query = decimals.OrderByDescending(num => num, new SpecialComparer()).ToList<decimal>();
        ((Repository)x).RepList = (List<decimal>)query;
    }
}, null));
tpRep.GetAll();
List<decimal> lstRep = Rep.RepList;

如果需要,我可以向您发送完整的工作代码。并且,如果可能的话,请从文章“使用Dynamic Decorator添加对象”回复我,因为我不会自动在此处收到消息。

答案 3 :(得分:-1)

有一篇文章Add Aspects to Object Using Dynamic Decorator

它描述了一种在运行时向对象添加方面的方法,而不是在设计时向类添加方面。看起来这就是你想要的。