View Full Version : How to obtain custom attributes for a class within Advice?
Hi.
I am confronted with following difficulty: I could not obtain my custom attributes for the class of the target object when it is used with more than one advices.
For example, suppose, ServerSettingsService is the class of the target object. And I want to use two aspects for it: transaction management and authorization. The authorization advice is implemented with using custom attributes for the class and methods.
When ServerSettingsService has joinpoint for the authorization advice only (joinpoint for the transaction management advice is disabled) I can obtain the custom class atribute with using following code:
internal class AuthorizingAroundAdvice
: IMethodInterceptor
{
public object Invoke(IMethodInvocation invocation)
{
...
object[] attrClassArray = invocation.Method.DeclaringType.GetCustomAttribute s(typeof (AuthorizationAttribute), false);
...
}
}
When I enabled joinpoint for the transaction management advice, invocation.Method.DeclaringType is not equal ServerSettingsService.
invocation.Method.DeclaringType is instance of generated proxy class. This proxy class does not inherit custom attributes of the target object :(.
Is it possible to obtain the custom class attribute in this case? If yes, how can I do it?
Thanks,
Nop
Bruno Baia
03-13-2007, 04:16 PM
Hi,
This should work because target type/method attributes are copied to the proxy type (since 1.1 P3).
Have you tried with method attributes ?
Are you using the Spring.Data transaction interceptor ?
Bruno
Hi,
I use Spring.NET-20070304-2218.
And invocation.Method.DeclaringType returns "CompositionAopProxy_17439a98806e41d9815c1067176383 a8".
Are you using the Spring.Data transaction interceptor ?
Yes, I use it. ServerSettingsService is declared as follows:
[Authorization("ServerSettingsService", "The service which gives access to server settings .")]
internal class ServerSettingsService
: IServerSettingsService
{
...
[Transaction(TransactionPropagation.RequiresNew, IsolationLevel.ReadCommitted, ReadOnly = true)]
[Authorization("GetServerSettings", "Get server settings.", Ignored = true)]
public ServerSettings GetServerSettings()
{
...
}
} // end class ServerSettingsService
ServerSettingsService.GetServerSettings is joined to some advices: Transaction Management by DefaultAdvisorAutoProxyCreator, Authorization by my implementation of AbstractAutoProxyCreator (extends ObjectNameAutoProxyCreator with Exclude option).
Have you tried with method attributes ?
invocation.Method has attributes. But "CompositionAopProxy_17439a98806e41d9815c1067176383 a8" does not have any attributes :(.
I am novice at AOP but I think that a substitution of the target object by the proxy has to be transparent for programmer.
Thanks,
Nop.
Bruno Baia
03-14-2007, 08:07 AM
invocation.Method has attributes. But "CompositionAopProxy_17439a98806e41d9815c1067176383 a8" does not have any attributes :(.
It seems Target type attributes are not copied to the proxy type.
File "springnet\Spring.Net\src\Spring\Spring.Aop\Aop\Fra mework\DynamicProxy\CompositionAopProxyTypeBuilder .cs", line 82 :
// apply custom attributes to the proxy type.
//ApplyCustomAttributes(typeBuilder, TargetType);
To work, this code should be uncomented, I'll investigate why it is not.
I am novice at AOP but I think that a substitution of the target object by the proxy has to be transparent for programmer.
You right, in most cases you should not see that.
The problem here is that your object is proxied by different proxy factories, so the second one access to the proxy object.
Bruno
Bruno
Hi, Bruno, thanks a lot.
How can I be informed about destiny of ApplyCustomAttributes?
Best regards,
Nop.
Bruno Baia
03-14-2007, 11:06 AM
I've create an issue in JIRA (http://opensource.atlassian.com/projects/spring/browse/SPRNET-505).
Anyway, I'll keep you informed here.
I should take care of this tonight.
Bruno
Aleks Seovic
03-16-2007, 05:05 AM
I believe the reason ApplyCustomAttributes is commented out is because of the problems cause by Serialized attribute being copied...
Anyway, there is a better way to get attributes from the target instance. Until today, you were able to get target instance by accessing invocation. This property, and you can then call GetType() on the returned target instance.
However, as of today, you can also use new properties exposed on the IMethodInvocation to get the things you need, such as Proxy, Target (same as This at the moment), as well as TargetType. We already had all this information, but unfortunately it wasn't exposed. Now it is...
Regards,
Aleks
Hi, Aleks.
However, as of today, you can also use new properties exposed on the IMethodInvocation to get the things you need, such as Proxy, Target (same as This at the moment), as well as TargetType.
I am glad to read this :) . I'll download a last nightbuild.
Until today, you were able to get target instance by accessing invocation. This property, and you can then call GetType() on the returned target instance.
Please, post the code example. I could not do it as you purposed :( .
Best regards,
Nop.
Bruno Baia
03-16-2007, 03:33 PM
Hi,
I don't know how this can resolve the problem when we got 2 differents proxies applied.
We also need to copy parameter attributes and return attributes to the proxy type.
What happens if we copy the Serializable attribute ?
Why not copy all attributes except the Serializable one ?
With the new Proxy property, we should remove all stuff around ExposeProxy property (PushProxy, PopProxy, etc...).
Bruno
Aleks Seovic
03-16-2007, 08:12 PM
Please, post the code example. I could not do it as you purposed :( .
This should do the job, even without the latest code:
Type targetType = methodInvocation.This.GetType();
// read attributes from the target type...
However, if you download the latest code you should be able to do simply:
methodInvocation.TargetType.GetAttributes(...);
- Aleks
Aleks Seovic
03-16-2007, 08:26 PM
I don't know how this can resolve the problem when we got 2 differents proxies applied.
You are right, if the target is another proxy, this obviously won't do you much good, as all target-related properties will return information about the nested proxy, as they should.
We also need to copy parameter attributes and return attributes to the proxy type.
We should probably do that, as it would solve the previous problem as well. However, at the very minimum user should be able to set a flag specifying whether attributes should be copied or not, as there are cases when it would not be desireable. We can copy them by default and allow users to turn it of either completely or for selectively (type, member, parameter and return value separately).
What happens if we copy the Serializable attribute ?
Proxy type builders now have the logic to make proxy serializable by adding Serializable attribute and implementing ISerializable if both target and all of the advices can be serialized, so Serializable should never be copied.
Why not copy all attributes except the Serializable one ?
That's an option, feel free to override ApplyAttribute method to do it.
With the new Proxy property, we should remove all stuff around ExposeProxy property (PushProxy, PopProxy, etc...).
No, we still need AopContext and ExposeProxy, as that's the only way to get the proxy within the *target* class implementation (although undoubtly it is a bad practice that ties class implementation to the AOP framework, defeating the very purpose of AOP, of being completely non invasive). On the other hand, properties exposed on IMethodInvocation can only be accessed within the *advice* implementation.
- Aleks
Bruno Baia
03-19-2007, 02:16 AM
I committed a fix for target type attributes for now.
Plz give it a try and let me know,
Bruno
Hi Bruno,
sorry for the late reply.
Unfortunately, I faced with the following problem after update:
System.MethodAccessException: MyProj.Service.Settings.Impl.ServerSettingsService .GetServerSettings()
at Spring.DynamicReflection.Method_GetServerSettings_ a8c563f2b4ab42068eab9fab8c9c524c.Invoke(Object target, Object[] args)
at Spring.Aop.Framework.ReflectiveMethodInvocation.In vokeJoinpoint() in c:\projects\daily\Spring.Net\src\Spring\Spring.Aop \Aop\Framework\ReflectiveMethodInvocation.cs:line 87
at Spring.Aop.Framework.AbstractMethodInvocation.Proc eed() in c:\projects\daily\Spring.Net\src\Spring\Spring.Aop \Aop\Framework\AbstractMethodInvocation.cs:line 260
at Spring.Transaction.Interceptor.TransactionIntercep tor.Invoke(IMethodInvocation invocation) in c:\projects\daily\Spring.Net\src\Spring\Spring.Dat a\Transaction\Interceptor\TransactionInterceptor.c s:line 80
at Spring.Aop.Framework.AbstractMethodInvocation.Proc eed() in c:\projects\daily\Spring.Net\src\Spring\Spring.Aop \Aop\Framework\AbstractMethodInvocation.cs:line 283
at Spring.Aop.Framework.DynamicProxy.AdvisedProxy.Inv oke(Object proxy, Object target, Type targetType, MethodInfo targetMethod, Object[] args, IList interceptors) in
Could you advice any reason of this exception?
Best regards,
Nop.
Bruno Baia
03-20-2007, 10:21 AM
Hi,
Seems to be another problem now.
MethodAccessException Class :
The exception that is thrown when there is an invalid attempt to access a private or protected method inside a class.
Is your method visible (not internal, protected or private) ?
Bruno
I checked availability of internal, protected or private attributes for methods...
and remove internal attribute for the class to public attribute.
I got a same exception.
For additional information my interface is:
public interface IServerSettingsService
{
ServerSettings GetServerSettings();
} // end public interface IServerSettingsService
my class is:
[Authorization("ServerSettingsService", "...")]
public class ServerSettingsService
: IServerSettingsService
{
...
[Transaction(TransactionPropagation.RequiresNew, IsolationLevel.ReadCommitted, ReadOnly = true)]
[Authorization("GetServerSettings", "...", Ignored = true)]
public ServerSettings GetServerSettings()
{
...
}
...
} // end class ServerSettingsService
It seems open (visible) to me. Any suggestions about reason of the exception?
Best regards,
Nop.
Hi.
I resolved the problem.
The reason of this exception (Bruno, you are right) is using a public interface and an internal class for spring context objects.
There are no problems with it in early versions of Spring Framework .NET.
May be it is right decision to make context objects to be public, but I think that it is a restriction on visibility, because the user of Spring Framework .NET have to publish implementations of the public interfaces and the user could not hide service implementation of one assembly from another assembly.
May be it was a little hack to load context with objects with internal visibility from different assemblies but I like this hack because this allows me to use Spring Framework .NET without any changes in interaction of PONObjects.
Best regards,
Nop.
Bruno Baia
03-26-2007, 01:10 PM
Hi,
Maybe Aleks can do something in DynamicReflection classes.
Another solution is to use InternalsVisibleTo attribute as shown in this thread (http://opensource.atlassian.com/projects/spring/browse/SPRNET-500).
Bruno
Bruno Baia
03-28-2007, 10:30 AM
Hi,
I revert changes to use standard reflection in spring.Aop until we resolve the problem with dynamic reflection.
Give a try to the latest nightly build (http://www.springframework.net/downloads/nightly/).
Bruno
Hi all!
Many thanks all for help!
Attributes are obtained, AOP works perfectly. :)
With thanks,
Nop.
vBulletin® v3.7.3, Copyright ©2000-2009, Jelsoft Enterprises Ltd.