假设我有一个存储库,它返回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的新手,所以请保持温和。
答案 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分离。
答案 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。
它描述了一种在运行时向对象添加方面的方法,而不是在设计时向类添加方面。看起来这就是你想要的。