Skip to content
This repository has been archived by the owner on Dec 14, 2018. It is now read-only.

ReflectedActionDescriptorProvider does not ignore private types #610

Closed
pranavkm opened this issue Jun 4, 2014 · 6 comments
Closed

ReflectedActionDescriptorProvider does not ignore private types #610

pranavkm opened this issue Jun 4, 2014 · 6 comments
Assignees
Milestone

Comments

@pranavkm
Copy link
Contributor

pranavkm commented Jun 4, 2014

https://github.com/aspnet/Mvc/blob/dev/src/Microsoft.AspNet.Mvc.Core/ReflectedActionDescriptorProvider.cs#L50 does not filter out non-public types (and possibly other non-interesting types). We need to be more restrictive about the things that get filtered by it.

@pranavkm pranavkm changed the title ReflectedActionDescriptor does not ignore private types ReflectedActionDescriptorProvider does not ignore private types Jun 4, 2014
@puncsky
Copy link

puncsky commented Jun 4, 2014

@yishaigalatzer
Copy link
Contributor

Investigate, compare MVC & Web API, and come up with a recommednation

@puncsky
Copy link

puncsky commented Jun 16, 2014

In summary, I would recommend to add typeInfo.IsPublic (consistent with MVC5.2), which is true if the class is public and not nested in other classes. User-defined controllers should not be exposed to the user when they are private. It gives the user more choices on their controllers' visibility.

On the other hand, this kind of hierarchies below is meaningless because hierarchies are achieved by routes and areas.

public class FirstController
{
    public class SecondController
    {
        public class ThirdController
        {
            // ...

To make it even more explicit, we could also add !typeInfo.IsNested.

Repro and Investigation

public class ClassWithNestedController
{
    public class HomeController : [Api]Controller
    {
        // This controller is invalid in MVC5.2 but valid in Web API.
    }
}

public class ClassWithNestedController
{
    public class InnerController : [Api]Controller
    {
        // This controller is invalid in both MVC5.2 and Web API.
    }
}

The inconsistency is caused by:

MVC5.2:

    internal static bool IsControllerType(Type t)
    {
        return
            t != null &&
            t.IsPublic && // false for both public and private InnerController
            t.Name.EndsWith("Controller", StringComparison.OrdinalIgnoreCase) &&
            !t.IsAbstract &&
            typeof(IController).IsAssignableFrom(t);
    }

Web API:

    internal static bool IsControllerType(Type t)
    {
        Contract.Assert(t != null);
        return
            t != null &&
            t.IsClass &&
            t.IsVisible && // false for private InnerController. true for public InnerController. 
            !t.IsAbstract &&
            typeof(IHttpController).IsAssignableFrom(t) &&
            HasValidControllerName(t);
    }

MVC6.0, neither IsPublic nor IsVisible existes.

    public virtual bool IsController([NotNull] TypeInfo typeInfo)
    {
        if (!typeInfo.IsClass ||
            typeInfo.IsAbstract ||
            typeInfo.ContainsGenericParameters)
        {
            return false;
        }

        if (typeInfo.Name.Equals("Controller", StringComparison.OrdinalIgnoreCase))
        {
            return false;
        }

        return typeInfo.Name.EndsWith("Controller", StringComparison.OrdinalIgnoreCase) ||
               typeof(Controller).GetTypeInfo().IsAssignableFrom(typeInfo);
    }

@puncsky
Copy link

puncsky commented Jun 17, 2014

@yishaigalatzer , what is your idea?

@pranavkm pranavkm assigned rynowak and unassigned puncsky Jul 2, 2014
@danroth27 danroth27 modified the milestones: 6.0.0-alpha3, 1.0.0-alpha3 Jul 7, 2014
@rynowak
Copy link
Member

rynowak commented Jul 15, 2014

Decision here is to use MVC5's behavior. Only public-top-level classes will be considered as controllers by default. This is easy to customize by overriding DefaultActionDiscoveryConventions.IsController.

rynowak added a commit that referenced this issue Jul 15, 2014
This change exludes internal and nested types from being treated as
controllers. This is consistent with MVC5's behavior.

DefaultActionSelectionConventions was primarily tested through running
action selection. I wanted to also test the methods with substantial logic
in this class, so I moved a spate of a classes from private classes inside of the
integration tests to public classes so they could be shared. I also added
tests to fill gaps in DefaultActionSelectionConventions, which is the vast
vast majority of this change.
rynowak added a commit that referenced this issue Jul 16, 2014
This change exludes internal and nested types from being treated as
controllers. This is consistent with MVC5's behavior.

DefaultActionSelectionConventions was primarily tested through running
action selection. I wanted to also test the methods with substantial logic
in this class, so I moved a spate of a classes from private classes inside of the
integration tests to public classes so they could be shared. I also added
tests to fill gaps in DefaultActionSelectionConventions, which is the vast
vast majority of this change.
rynowak added a commit that referenced this issue Jul 16, 2014
This change exludes internal and nested types from being treated as
controllers. This is consistent with MVC5's behavior.

DefaultActionSelectionConventions was primarily tested through running
action selection. I wanted to also test the methods with substantial logic
in this class, so I moved a spate of a classes from private classes inside of the
integration tests to public classes so they could be shared. I also added
tests to fill gaps in DefaultActionSelectionConventions, which is the vast
vast majority of this change.
@rynowak
Copy link
Member

rynowak commented Jul 17, 2014

Fixed by bff94f1

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

5 participants