Dynamic register controller in C # Web Api

tl; dr: I create Type(by reflection) that spreads ApiController. How can I dynamically register it (it can be registered at startup, no need to do this at runtime).

Long story:

So, in my application I have several interfaces, i.e.:

interface IMyInterface
{
    MyResponse Hello(MyRequest request);
}

What I want to achieve is to create a controller for each interface, which should look like this:

public class IMyInterfaceController : ApiController
{
    public IMyInterface MyInterface { get; set; }

    public MyResponse Hello([FromBody] MyRequest request)
    {
        return MyInterface.Hello(request);
    }
}

This controller is already being generated using C # heavy reflection. The thing is, what I want to do right now is to register this controller under /api/{controller}/{action}.

In Global.asaxright now I got this:

public class MvcApplication : System.Web.HttpApplication
{
    private readonly InterfaceReader _reader = new InterfaceReader(); // this class is doing all staff with reflection to create controller class

    protected void Application_Start()
    {
        AreaRegistration.RegisterAllAreas();

        WebApiConfig.Register(GlobalConfiguration.Configuration);
        FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
        RouteConfig.RegisterRoutes(RouteTable.Routes);

        var controller = _reader.CreateController(new MyImplementation()); // MuImplementation implements IMyInterface
    }
}
+4
source share
2

IHttpControllerFactory

, factory:

public class MyHttpControllerFactory : IHttpControllerFactory
{
    private readonly InterfaceReader _reader;
    private readonly HttpConfiguration _configuration;

    public MyHttpControllerFactory(InterfaceReader reader, HttpConfiguration configuration)
    {
        _reader = reader;
        _configuration = configuration;
    }

    public IHttpController CreateController(HttpControllerContext controllerContext, string controllerName)
    {
        if (controllerName == null)
        {
            throw new HttpException(404, string.Format("The controller for path '{0}' could not be found.", controllerContext.Request.RequestUri.AbsolutePath));
        }

        // Change the line below to whatever suits your needs.
        var controller = _reader.CreateController(new MyImplementation());
        controllerContext.Controller = controller;
        controllerContext.ControllerDescriptor = new HttpControllerDescriptor(configuration, controllerName, controller.GetType());

        return controllerContext.Controller;
    }

    public void ReleaseController(IHttpController controller)
    {
        // You may want to be able to release the controller as well.
    }
}

Global.asax factory:

public class MvcApplication : System.Web.HttpApplication
{
    private readonly InterfaceReader _reader = new InterfaceReader(); // this class is doing all staff with reflection to create controller class

    protected void Application_Start()
    {
        AreaRegistration.RegisterAllAreas();

        WebApiConfig.Register(GlobalConfiguration.Configuration);
        FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
        RouteConfig.RegisterRoutes(RouteTable.Routes);

        GlobalConfiguration.Configuration.ServiceResolver.SetService(typeof(IHttpControllerFactory), new MyHttpControllerFactory(_reader, GlobalConfiguration.Configuration));
    }
}

IHttpControllerActivator

Web Api 2, IDependencyResolver, IHttpControllerActivator factory. , IHttpControllerActivator - .

public class MyServiceActivator : IHttpControllerActivator
{
    private readonly InterfaceReader _reader;
    private readonly HttpConfiguration _configuration;

    public MyServiceActivator(InterfaceReader reader, HttpConfiguration configuration)
    {
        _reader = reader;
        _configuration = configuration;
    }

    public IHttpController Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)
    {
        // Change the line below to whatever suits your needs.
        var controller = _reader.CreateController(new MyImplementation());
        return controller;
    }
}

Global.asax :

public class MvcApplication : System.Web.HttpApplication
{
    // this class is doing all staff with reflection to create controller class
    private readonly InterfaceReader _reader = new InterfaceReader();

    protected void Application_Start()
    {
        AreaRegistration.RegisterAllAreas();

        WebApiConfig.Register(GlobalConfiguration.Configuration);
        FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
        RouteConfig.RegisterRoutes(RouteTable.Routes);

        HttpConfiguration config = GlobalConfiguration.Configuration;
        config.Services.Replace(typeof(IHttpControllerActivator), new MyServiceActivator(_reader, config));
    }
}

, .

+5

, IHttpControllerActivator

, DI Windsor

public class WindsorCompositionRoot : IHttpControllerActivator
{
    private readonly IWindsorContainer _container;

    public WindsorCompositionRoot(IWindsorContainer container)
    {
        _container = container;
    }

    public IHttpController Create(
        HttpRequestMessage request,
        HttpControllerDescriptor controllerDescriptor,
        Type controllerType)
    {
        var controller =
            (IHttpController) _container.Resolve(controllerType);

        request.RegisterForDispose(
            new Release(
                () => _container.Release(controller)));

        return controller;
    }

    private class Release : IDisposable
    {
        private readonly Action _release;

        public Release(Action release)
        {
            _release = release;
        }

        public void Dispose()
        {
            _release();
        }
    }
}

Global.asax Application_Start()

        Container = new WindsorContainer().Install(FromAssembly.This());

        GlobalConfiguration.Configuration.Services.Replace(
            typeof (IHttpControllerActivator),
            new WindsorCompositionRoot(Container));

Windsor

public class ControllersInstaller : IWindsorInstaller
{
    public void Install(IWindsorContainer container, IConfigurationStore store)
    {
        container.Register(Classes.FromThisAssembly()
                            .BasedOn<IHttpController>()
                            .LifestyleTransient());
    }
}
+1

All Articles