ASP.NET WebAPI - How to scan registered Actions

713 Views Asked by At

I have several methods in my WebApi which return HttpResponseMessage. As the response type is unknown, I have to register them in HelpPageConfig using something like

config.SetActualResponseType(typeof(X), "SomeController", "GetX");

I would like to register these using a custom attribute [ActualResponse(typeof(X)] where the controller is declared to avoid creating a large registry object which references everything in a bit messy list.

How can I interrogate the config in order to get a list of the registered controllers and actions and their attributes so that I can call SetActualResponseType automatically?

1

There are 1 best solutions below

1
On BEST ANSWER

I've explored sources of mvc and web api and didn't find place where you can inject such logic. Search of action methods in mvc/web api is not an easy task, because there are number of checks that determine if method is action method or just regular method (based on registered routes etc). In your case you have to process only methods with your custom ActualResponse attribute, right? So you can do it with reflection. Of course, such things are not fast and bring some performance hit. But if you run such logic once on Application_Start I think it's acceptable.

Example of implementation:

public static class ActionMethodsRegistrator
{
    private static readonly Type ApiControllerType = typeof(IHttpController);

    public static void RegisterActionMethods(YourCustomConfig config)
    {
        // find all api controllers in executing assembly            
        var contollersTypes = Assembly.GetExecutingAssembly().GetTypes()
            .Where(foundType => ApiControllerType.IsAssignableFrom(foundType));

        // you may also search for controllers in all loaded assemblies e.g.
        // var contollersTypes = AppDomain.CurrentDomain.GetAssemblies()
        //    .SelectMany(s => s.GetTypes())
        //    .Where(foundType => ApiControllerType.IsAssignableFrom(foundType));                

        foreach (var contollerType in contollersTypes)
        {
            // you may add more restriction here for optimization, e. g. BindingFlags.DeclaredOnly
            // I took search parameters from mvc/web api sources.
            var allMethods = contollerType.GetMethods(BindingFlags.Instance | BindingFlags.Public);

            foreach (var methodInfo in allMethods)
            {
                var actualResponseAttrubute = methodInfo.GetCustomAttribute<ActualResponseAttribute>();
                if (actualResponseAttrubute != null)
                {                       
                    config.SetActualResponseType(actualResponseAttrubute.Type, contollerType.Name, methodInfo.Name);                        
                }
            }
        }
    }
}

Global.asax file:

    protected void Application_Start()
    {
        //....
        YourCustomConfig config = InitializeConfig();
        ActionMethodsRegistrator.RegisterActionMethods(config);
    }