我有一系列的WCF服务,形式如下
[WCFEndpoint]
public class MyWCFEndpoint : WCFSvcBase, IMyWCFEndpoint
{
}
其中WCFEndpoint是PostSharp OnMethodBoundaryAspect:
[Serializable]
public class WCFEndpointAttribute : OnMethodBoundaryAspect
{
}
[WCFEndpoint]的主要目的是通过覆盖OnEntry和OnExit提供有关WCF调用的持续时间信息,以及其他诊断信息。
问题在于,开发人员有时会忘记将[WCFEndpoint]添加到新的WCF服务中(编辑:AND其他进行代码审阅的开发人员都忘了提及它!)。
我的目标是确保从WCFSvcBase派生的每个类都装饰有[WCFEndpoint]属性。我的计划是编写一个自动化(NUnit)测试,以查找从WCFSvcBase派生的所有类,然后浏览自定义属性并确认WCFEndpointAttribute在该集中(为简化起见而简化):
Assembly assm = Assembly.GetAssembly(typeof(ReferenceSvc));
Type[] types = assm.GetTypes();
IEnumerable<Type> serviceTypes =
types.Where(type => type.IsSubclassOf(typeof(WCFSvcBase)) && !type.IsAbstract );
foreach (Type serviceType in serviceTypes)
{
if (!serviceType.GetCustomAttributes(true).Any(x => x.GetType() == typeof(WCFEndpointAttribute)))
{
Assert.Fail( "Found an incorrectly decorated svc!" )
}
}
我的问题是WCFEndpointAttribute没有出现在GetCustomAttributes(true)中-即使它是从System.Attribute派生的。我也通过查看.Net Reflector中的程序集来确认这一点。
理想情况下,因为OnMethodBoundaryAspect是从Attribute派生的,所以我想以某种方式将[WCFEndpoint](或类似的自定义属性)“打印”到最终的已编译程序集元数据中。从概念上讲,这是迄今为止最简单的答案:它在代码中可见,并且在程序集元数据中可见。有没有办法做到这一点?
我发现this article描述了自动注入自定义属性的TypeLevelAspect的用法,如果我可以从TypeLevelAspect和OnMethodBoundaryAspect派生WCFEndpointAttribute的话,这将非常有用(是的,我知道为什么我不能这样做)。 :)
我考虑解决此问题的其他方法是:
1)执行代码解析,以确认[WCFEndpoint]在“附近”(上方一行)
: WCFSvcBase
。这在可维护性/鲁棒性方面存在明显的问题。2)通过multicasting自动将[WCFEndpoint]附加到从WCFSvcBase派生的所有类。我不喜欢这样做,因为它在检查服务代码时掩盖了PostSharp /属性在起作用的细节,尽管没有更好的解决方案也是可能的。
3)创建一个AssemblyLevelAspect以在构建时吐出具有[WCFEndpoint]属性的所有类的列表。然后,我可以将此静态列表与从WCFBaseSvc派生的类的反射生成的列表进行比较。 AssemblyLevelAspect详细信息here。
我还应该指出,我仅限于PostSharp的免费/快速版本。
最佳答案
通过在方面定义中包含PersistMetadata = true,我能够保留WCFEndpoint属性:
[Serializable]
[MulticastAttributeUsage(PersistMetaData = true)]
public class WCFEndpointAttribute : OnMethodBoundaryAspect
{
}
查看.Net Reflector中的元数据,我现在看到
public class MyWCFEndpoint : WCFSvcBase, IMyWCFEndpoint
{
[WCFEndpoint]
static MyWCFEndpoint();
[WCFEndpoint]
public MyWCFEndpoint();
[WCFEndpoint]
public void EndpointFn1();
[WCFEndpoint]
public void EndpointFn2();
}
存储在元数据中的WCFEndpointAttribute的定义是
public WCFEndpointAttribute()
{
}
从这里,我可以将验证规则调整为“如果从WCFSvcBase派生的具有WCFEndpoint属性的类上至少存在一个方法,则验证通过;否则,验证失败。”
验证码变为
IEnumerable<Type> serviceTypes =
types.Where(type => type.IsSubclassOf(typeof(WCFSvcBase))
&& !type.IsAbstract );
foreach (Type serviceType in serviceTypes)
{
var members = serviceType.GetMembers();
if (!members.Exists( member => member.GetCustomAttributes(true).Any(attrib => attrib.GetType() == typeof(WCFEndpointAttribute))))
{
Assert.Fail( "Found an incorrectly decorated svc!" )
}
}
我当然没有意识到OnMethodBoundaryAspect已被多播给所有成员(私有,公共,静态等),尽管事后看来确实很有意义。我可能最终创建一个复合方面,其中包括用于类的TypeLevelAspect和用于成员的OnMethodBoundaryEntry方面(因此我可以直接查找所有类),但是此元数据足以解决我的紧迫问题。
感谢所有人为缩小范围提供的帮助!
关于c# - 如何确定在构建或运行时是否用PostSharp方面装饰了类,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/24070246/