Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to check if method has an attribute (with interfaces, casting and abstract)

After reading the post "How to check if method has an attribute" I'm one step to solve a problem that keeps me awake.

I present the situation :

( I'm working with ASP.Net MVC 4 )

These interfaces:

public interface IFlyable
{
    ActionResult Fly();
}    

public interface IRunnable
{
    ActionResult Run();
}

This abstract class :

public abstract class SuperHero : Controller
{
    public void SavePeople()
    {
    }    
}

This controller :

public class SuperManController : SuperHero,IFlyable,IRunnable {

    [Authorize]
    public ActionResult Fly(){
        // Flying...
    }    

    [Authorize]
    public ActionResult Run(){
        // Running...
    }    

}

This abstract class ( for tests )

[TestClass]
public abstract class SuperHeroTest<TSuperHero>{

    protected abstract TSuperHero GetSuperHero();

    [TestMethod]
    public void IfSuperHeroCanFlyMustHaveAuthorizeAttribute(){

        var superHero=GetSuperHero();

        if(superHero is IFlyable)
        {
            var superHeroFlyable = (IFlyable) superHero;

            var have = MethodHasAuthorizeAttribute(() => superHeroFlyable.Fly());

            Assert.IsTrue(have);
        }

    }
}

And finally this class inherited from SuperHeroTest to test SuperManController:

[TestClass]
public class SuperManControllerTest : SuperHeroTest<SuperManController>{

    private SuperManController _superManController;

    public SuperManControllerTest(){
        _superManController=new SuperManController();
    } 


    protected override SuperManController GetSuperHero()
    {
        return _superManController;
    }

}

Method MethodHasAuthorizeAttribute is : (from the post above)

public static MethodInfo MethodOf(Expression<System.Action> expression)
{
    MethodCallExpression body = (MethodCallExpression)expression.Body;
    return body.Method;
}

public static bool MethodHasAuthorizeAttribute( Expression<System.Action> expression )
{
    var method = MethodOf( expression );

    const bool includeInherited = false;
    return method.GetCustomAttributes(typeof(AuthorizeAttribute),includeInherited).Any();
}

My problem is:

The call MethodHasAuthorizeAttribute(() => superHeroFlyable.Fly()) in SuperHeroTest class return false when it should return true.

(The implemented method Fly in class SuperManController has the attribute Authorize ).

I added the attribute Authorize in method Fly into IFlyable and then returns true.

public interface IFlyable
{
    [Authorize]
    ActionResult Fly();
}  

How I can do to make MethodHasAuthorizeAttribute inspect the implementation rather than the interface?

like image 714
Sebastián Guerrero Avatar asked Sep 30 '12 05:09

Sebastián Guerrero


1 Answers

With some modifications to the IfSuperHeroCanFlyMustHaveAuthorizeAttribute() method you can get it to work.

First check if you controller implements the IFlyable interface. If so, get the MethodInfo for the controller's Fly method. Then you only need to check the attributes for the returned MethodInfo. This way you are checking if the implementation has the attribute instead of the interface.

The following works OK:

[TestClass]
public abstract class SuperHeroTest<TSuperHero>
{
    protected abstract TSuperHero GetSuperHero();

    [TestMethod]
    public void IfSuperHeroCanFlyMustHaveAuthorizeAttribute()
    {
        var superHero = GetSuperHero();

        if (superHero is IFlyable)
        {
            var superHeroFlyable = superHero;
            var method = typeof (TSuperHero).GetMethod("Fly");
            var hasAttribute = 
                method.GetCustomAttributes(typeof (AuthorizeAttribute), false).Any();
            Assert.IsTrue(hasAttribute);
        }
    }

    public static MethodInfo MethodOf(Expression<System.Action> expression)
    {
        var body = (MethodCallExpression)expression.Body;
        return body.Method;
    }

    public static bool MethodHasAuthorizeAttribute(Expression<System.Action> expression)
    {
        var method = MethodOf(expression);
        const bool includeInherited = false;
        return method.GetCustomAttributes(
            typeof(AuthorizeAttribute), includeInherited).Any();
    }
}
like image 141
Christophe Geers Avatar answered Nov 15 '22 04:11

Christophe Geers