Is it possible to access the entered / woven interfaces and PostSharp members during build?

I am developing a scenario in which two aspects of PostSharp work with each other. I have one aspect ( FirstAspect in the code below) that is designed to introduce an interface, and then another aspect ( SecondAspect in the code below) should work with the interface that was introduced by the first aspect.

However, it does not seem that the interface introduced by the first aspect is always available for the second aspect.

Here is the code I'm working with now:

 public class Tests { [Fact] public void Verify() { // Not really all that significant as the current code does not compile correctly: var sut = new MyClass(); Assert.True( sut is IInterface ); } public interface IInterface { void HelloWorld(); } [IntroduceInterface( typeof(IInterface) )] public class FirstAspect : InstanceLevelAspect, IInterface, IAspectProvider { public void HelloWorld() {} public IEnumerable<AspectInstance> ProvideAspects( object targetElement ) { // Implementing IAspectProvider appears to ensure this aspect is processed first. // This may be a bug. // Please see: http://support.sharpcrafters.com/discussions/problems/3365-runtimeinitialize-does-not-follow-ordering-rules#comment_40824072 // for more information. yield break; } } [AspectTypeDependency( AspectDependencyAction.Order, AspectDependencyPosition.After, typeof(FirstAspect) )] public class SecondAspect : InstanceLevelAspect, IAspectProvider { public IEnumerable<AspectInstance> ProvideAspects( object targetElement ) { var type = (Type)targetElement; if ( !typeof(IInterface).GetTypeInfo().IsAssignableFrom( type ) ) { // This is currently being thrown, as MyClass does not implement // IInterface when the AppDomain is first loaded and initialized: throw new InvalidOperationException( $"Does not implement {typeof(IInterface)}" ); } // How to access the weaved elements from FirstAspect? ... yield break; } } [FirstAspect, SecondAspect] class MyClass {} } 

When building, an InvalidOperationException is InvalidOperationException in SecondAspect.ProvideAspects , because the interface introduced by FirstAspect is not available to SecondAspect during the call. That is, although the interface was woven into the MyClass type, the type found in the currently loaded AppDomain is not marked as an implemented interface.

What I'm looking for is the ability to access and search all known and interwoven interfaces and elements on the target element during assembly.

I looked at ReflectionSearch , and this is close to what I am looking for, but it does not seem to take into account the intertwined elements, calls are made to this API at this time. For example, calling ReflectionSearch.GetMembersOfType does not give the expected IInterface.HelloWorld on MyClass (which is specified in FirstAspect in the above example).

Is there any other API that I should use to access inserted / bound PostSharp elements during build? Is it possible?

+1
source share
1 answer

So this question looks a little old, but I have a similar problem that I still need an answer to (namely: how can I present an attribute to an input method without applying the attribute to the implementation and copying it). However, I may have to ask my own question, as there are some general steps for the template you are asking about that can solve your dilemma but not solve my problem. It seems that you have already experimented with this, but for the sake of others who come, I will tell you in detail.

In short, do not use reflection types to indicate aspect dependency. PostSharp provides attributes that you can use to require the application of aspects or require a specific order (see Considering several aspects of the same goal for an overview), as well as a method for importing participants already provided by other aspects ( fooobar.com/questions/1268451 / ... , although not checked, is the correct answer to this question of the user, and also shows how to use ImportMemberAttribute together with an aspect dependency). ImportMemberAttribute is able to import participants from other aspects if the order is correct; the IsRequired property in this attribute will cause a build error if the member does not exist and was not represented by the aspect.

Now, if you want your second aspect to be applicable to all classes implementing the interface, regardless of whether the interface was applied by your first aspect or not, you should set AspectTypeDependencyAttribute with AspectDependencyAction.Order , but don't set AspectTypeDependencyAttribute with AspectDependencyAction.Required ; if you want the second aspect to be applied to the targets recommended by the first, you can apply several dependency attributes to specify both the requirement and the order, and the Aspect provider is not required (the above answer also shows an alternative implementation applying the Tip to several Pointcuts in one aspect). Similarly, if you want your first aspect to always require your second aspect, you can use the optional AspectTypeDependencyAttribute to indicate the requirement in the other direction (i.e. if both require the other, then you must specify the requirement indicated on both).

The Priority aspect can also be used to identify aspects of an order, although you should use dependencies whenever possible because they are also server documents.

All this implies that you actually do not need to use the Aspect Provider (since your comments imply that this was done for the order). You would not want one Aspect provider to depend on the results of another Aspect provider (this would violate the separation of concerns), instead you should have one aspect yield provider for each target. However, you can use the AspectTypeDependencyAttribute for Aspect providers, for example, you can have a level type provider that orders after the type level aspect that introduces the interface, and then in the provider you can scroll through the methods on the type and injection aspects, which depend on the first aspect (for example, a follower of introducing an interface from a provider that applies method intercept recommendations for members who can now invoke methods presented by the first aspect).

Hope this clears you up (or, given the time the question was asked, someone else who is facing this problem). Some of this information may also be outdated or inaccurate (for all that I know, it is now possible to detect injected interfaces on target types passed to aspect providers under some or all conditions), but I believe that expressed patterns are still preferred practice suggested by PostSharp.

+1
source

Source: https://habr.com/ru/post/1268447/


All Articles