我有一系列格式为
的WCF服务[WCFEndpoint]
public class MyWCFEndpoint : WCFSvcBase, IMyWCFEndpoint
{
}
其中WCFEndpoint是PostSharp OnMethodBoundaryAspect:
[Serializable]
public class WCFEndpointAttribute : OnMethodBoundaryAspect
{
}
[WCFEndpoint]的主要目的是通过OverEntry和OnExit的覆盖以及其他诊断信息提供有关WCF调用的持续时间信息。
问题是开发人员偶尔忘记将[WCFEndpoint]添加到新的WCF服务中(编辑:和其他开发代码评论的开发人员忘了提及它!)。
我的目标是保证从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派生自属性,我想以某种方式&#34; print&#34;将[WCFEndpoint](或类似的自定义属性)放入最终编译的程序集元数据中。到目前为止,这是概念上最简单的答案:它在代码中可见,并且在程序集元数据中可见。 有没有办法做到这一点?
我发现this article描述了自动注入自定义属性的TypeLevelAspect的使用,如果我可以从TypeLevelAspect和OnMethodBoundaryAspect派生出WCFEndpointAttribute,那将会很有效(是的,我知道为什么我可以&#t; t去做)。 :)
我考虑过解决这个问题的其他方法是:
1)执行代码解析以确认[WCFEndpoint]是&#34;接近&#34; (上面一行): WCFSvcBase
。这在可维护性/稳健性方面存在明显问题。
2)通过multicasting自动将[WCFEndpoint]附加到从WCFSvcBase派生的所有类。我不喜欢这个,因为它在检查服务代码时模糊了PostSharp /属性的细节,尽管如果没有更优雅的解决方案,它是可能的。
3)创建一个AssemblyLevelAspect,在构建时使用[WCFEndpoint]属性吐出所有类的列表。然后,我可以将此静态列表与从WCFBaseSvc派生的反射生成的类列表进行比较。 AssemblyLevelAspect详细信息here。
我还应该指出,我只限于PostSharp的Free / Express版本。
答案 0 :(得分:2)
我能够通过在方面定义中包含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方面(所以我可以直接查找所有类),但这个元数据足以解决我的直接问题。
感谢所有人帮助缩小范围!
答案 1 :(得分:1)
如果您的WcfEndpoints确实需要使用Aspect进行编织,您可以:
Postsharp有一个功能调用Programmatic Tipping,您可以使用C#编写程序来描述添加方面的位置。将其中一个添加到构建工具链中,完全忘记[WCFEndpoint]属性,让您有更多时间编写代码。