如何确定一类是装饰有PostSharp方面在构建或运行时方面、PostSharp

2023-09-03 21:37:24 作者:最爱你的人

我有一系列的形式WCF服务

I have a series of WCF services of the form

[WCFEndpoint]
public class MyWCFEndpoint : WCFSvcBase, IMyWCFEndpoint
{

}    

在这里WCFEndpoint是PostSharp OnMethodBoundaryAspect:

where WCFEndpoint is a PostSharp OnMethodBoundaryAspect:

[Serializable]
public class WCFEndpointAttribute : OnMethodBoundaryAspect
{

}

的[WCFEndpoint]的主要目的是提供一种持续时间信息上的WCF经由的OnEntry和OnExit的覆盖,以及其他诊断信息调用

The main purpose of [WCFEndpoint] is to provide duration information on WCF calls via overrides of OnEntry and OnExit, as well as other diagnostic information.

问题是,开发者有时会忘记添加[WCFEndpoint]新的WCF服务(编辑:!和其他开发商做code评论忘记提到它)。

The problem is that developers occasionally forget to add the [WCFEndpoint] to new WCF services ( AND other developers doing code reviews forget to mention it!).

我的目标是保证从WCFSvcBase每一个派生类是装饰用[WCFEndpoint]属性。我的计划是写一个自动的(NUnit的)测试,发现从WCFSvcBase派生的所有类,然后期待通过自定义属性,并确认WCFEndpointAttribute是在集(简化的可读性):

My objective is to guarantee that every class derived from WCFSvcBase is decorated with the [WCFEndpoint] attribute. My plan was to write an automated (NUnit) test to find all classes derived from WCFSvcBase, then look through the custom attributes and confirm the WCFEndpointAttribute is in that set (simplified for readability):

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(真) - 尽管它从System.Attribute派生。我看在.net反射的装配以及证实了这一点。

My problem is that the WCFEndpointAttribute is not appearing in GetCustomAttributes(true) - even though it derives from System.Attribute. I confirmed this by looking at the assembly in .Net Reflector as well.

在理想情况下,因为OnMethodBoundaryAspect从属性派生,我想以某种方式打印的[WCFEndpoint](或类似的自定义属性)进入最后的编译的程序集的元数据。这是目前为止最简单的概念答案:这是明显的,在code和它在程序集元数据可见。 有没有办法做到这一点?的

Ideally, because OnMethodBoundaryAspect derives from Attribute, I'd like to somehow "print" the [WCFEndpoint] (or analogous custom attribute) into the final compiled assembly metadata. This is by far the simplest answer conceptually: it's visible in the code and it's visible in the assembly metadata. Is there a way to do this?

我发现这篇文章描述使用TypeLevelAspect自动注入了一个自定义属性,这将工作的伟大,如果我可以从两个TypeLevelAspect和OnMethodBoundaryAspect(是的,我知道得出WCFEndpointAttribute为什么我不能去做)。 :)

I found this article describing the use of a TypeLevelAspect that automatically injects a custom attribute, which would work great if I could derive WCFEndpointAttribute from both TypeLevelAspect and OnMethodBoundaryAspect (and yes, I know why I can't do that). :)

其他的方法,我已经考虑解决这个有:

Other ways I've considered solving this are:

1)执行code解析确认[WCFEndpoint]是近(上面一行):WCFSvcBase 。这与可维护性/稳健性明显的问题。

1) Perform code parsing to confirm [WCFEndpoint] is "near" (one line above) : WCFSvcBase. This has obvious problems with maintainability/robustness.

2)自动附加[WCFEndpoint]从WCFSvcBase派生的所有类通过组播。我不喜欢这一点,因为它掩盖了细节,PostSharp /属性在发挥检查服务code时,虽然它是可能的,如果没有更优雅的解决方案。

2) Automatically attach the [WCFEndpoint] to all classes deriving from WCFSvcBase via multicasting. I dislike this because it obscures the detail that PostSharp/attributes are in play when examining the service code, though it is possible if there are no more elegant solutions.

3)创建AssemblyLevelAspect吐出所有类的[WCFEndpoint]在构建时属性的列表。然后,我会这样静态列表比较了从WCFBaseSvc派生类的反射产生的列表。 AssemblyLevelAspect详情这里。

3) Create an AssemblyLevelAspect to spit out a list of all classes with the [WCFEndpoint] attribute at build time. I could then compare this static list to the reflection-generated list of classes that derive from WCFBaseSvc. AssemblyLevelAspect details here.

我还要指出,我仅限于PostSharp的自由/ EX preSS版本。

I should also point out I'm limited to the Free/Express version of PostSharp.

推荐答案

我能够通过在方面定义PersistMetadata = true来坚持的WCFEndpoint属性:

I was able to persist the WCFEndpoint attribute by including PersistMetadata=true in the aspect definition:

[Serializable]
[MulticastAttributeUsage(PersistMetaData = true)]
public class WCFEndpointAttribute : OnMethodBoundaryAspect
{
}

看着在.net反射的元数据,我现在看到

Looking at the metadata in .Net Reflector, I now see

public class MyWCFEndpoint : WCFSvcBase, IMyWCFEndpoint
{
    [WCFEndpoint]
    static MyWCFEndpoint();

    [WCFEndpoint]
    public MyWCFEndpoint();

    [WCFEndpoint]
    public void EndpointFn1();

    [WCFEndpoint]
    public void EndpointFn2();
}

存储在元数据WCFEndpointAttribute的定义

The definition of WCFEndpointAttribute stored in the metadata is

public WCFEndpointAttribute()
{

}

在这里,我可以调整我的验证规则,如果有对来自WCFSvcBase与属性WCFEndpoint一类的至少一种方法,验证通过;否则失败

From here, I can adjust my validation rule to "If there is at least one method on a class derived from WCFSvcBase with the attribute WCFEndpoint, validation passes; else it fails."

验证code变为

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方面,但是这个元数据是不足以解决我的眼前的问题。

I certainly did not realize the OnMethodBoundaryAspect was being multicast to all members (private, public, static, etc.), though that certainly makes sense in hindsight. I may end up creating a composite aspect that includes a TypeLevelAspect for the class and an OnMethodBoundaryEntry aspect for the members (so I can look for all classes directly), but this metadata is sufficient to solve my immediate problem.

感谢所有的帮助缩小下来!

Thanks to all for the help in narrowing this down!