C#webapi中的动态寄存器控制器

C#webapi中的动态寄存器控制器,c#,asp.net-web-api,C#,Asp.net Web Api,tl;dr:我正在创建类型(通过反射),它扩展了ApiController。如何动态注册它(它可以在启动时注册;无需在运行时注册) 长话短说: 因此,在我的应用程序中,我有多个接口,即: interface IMyInterface { MyResponse Hello(MyRequest request); } 我想要实现的是为每个界面创建如下所示的控制器: public class IMyInterfaceController : ApiController { publi

tl;dr:我正在创建
类型
(通过反射),它扩展了
ApiController
。如何动态注册它(它可以在启动时注册;无需在运行时注册)

长话短说:

因此,在我的应用程序中,我有多个接口,即:

interface IMyInterface
{
    MyResponse Hello(MyRequest request);
}
我想要实现的是为每个界面创建如下所示的控制器:

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

    public MyResponse Hello([FromBody] MyRequest request)
    {
        return MyInterface.Hello(request);
    }
}
已经使用重C#反射生成了此控制器。我现在想做的是在
/api/{controller}/{action}
下注册这个控制器

Global.asax
中,我得到了以下信息:

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
    }
}
使用IHTTP控制器工厂的解决方案 我想你需要的是一个控制器工厂:

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.
    }
}
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));
    }
}
然后在
Global.asax
中,您需要注册自定义控制器工厂:

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.
    }
}
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));
    }
}

使用IHTTP控制器激活器的解决方案 如果使用Web Api 2,则解决方案是使用
IDependencyResolver
IHttpControllerActivator
而不是出厂。我想在您的情况下,
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));
    }
}

我希望这会有所帮助。

您需要创建自己的类来实现IHttpControllerActivator

下面是一个我在Windsor中使用的DI示例

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();
        }
    }
}
然后您需要在应用程序_Start()中的Global.asax中将其连接起来

在Windsor安装程序类中安装控制器

public class ControllersInstaller : IWindsorInstaller
{
    public void Install(IWindsorContainer container, IConfigurationStore store)
    {
        container.Register(Classes.FromThisAssembly()
                            .BasedOn<IHttpController>()
                            .LifestyleTransient());
    }
}
公共类控制器安装程序:IWindsorInstaller
{
public void安装(IWindsorContainer、IConfigurationStore)
{
container.Register(Classes.fromthissembly())
.BasedOn()
.生活方式(暂时的);
}
}

在方法
GetControllerInstance
中,我出现错误,因为
ApiController
没有继承
IController
@MAGx2我以前编写的内容适用于MVC而不是WebApi,请查看更新的答案。我没有
IHttpControllerFactory
。当我看到它被替换为@MAGx2时,请再次查看更新的答案。希望使用
IHttpControllerActivator
的解决方案就是您想要的。您能为
InterfaceReader
MyServiceActivator
粘贴一个要点吗?我们需要动态创建控制器。在本例中,我看不到我的控制器在哪里注册。现在我无法通过
/api/MyController/action
.MAGx2访问它们,如果提供的解决方案对您有帮助,请您提供反馈?标记对您有用的答案可能会在将来帮助其他访问者。抱歉,耽搁了。我已经接受了你的回答。