22

我有一个使用 Castle Windsor 的 MVC4 站点,我想添加一些 WebAPI 调用,所以我开始在互联网上进行一些研究。

现在我不知道 IoC 的来龙去脉;我遵循了如何在我的项目中设置 Castle Windsor 的教程,在基本控制器中注入IUnitOfWorkFactoryIApplicationServiceas 公共属性,以及控制器构造函数中需要的一些其他接口。它可以流畅地工作,所以我从来不需要用它做更多的事情。

在我阅读 WebAPI 的任何地方,我都被告知 DI 在使用 Castle Windsor 时效果不佳,并谈到了IDependencyResolverIDependencyScope. 如何解决这个问题有几种解决方法和实现,但我不清楚问题到底是什么。包括代码片段,但假设您知道它们属于哪个类,以及它们是如何被调用的,不幸的是我不知道。此外,我在网上看到的所有示例都指的是一个专有的 WebAPI 项目,而不是一个明智地加入了几个ApiControllers 的 MVC4 项目。我不知道这会如何或是否会影响任何事情。

为什么我在标准控制器上使用的东西不能在 API 控制器上使用?要让 WebAPI 调用和标准 Web 调用在同一个应用程序中工作,需要做什么样的代码杂技?

4

4 回答 4

13

现有 Castle Windsor MVC 配置

假设您有类似于Castle Windsor MVC 教程的 MVC 和 Castle Windsor 设置,使用Mark Seemann 的帖子 添加 IoC 以使 Web API 控制器利用依赖注入非常简单(请注意,他解释了为什么不使用 IDependencyResolver)

从 Castle Windsor 教程中,您应该在Global.asax.cs.

    private static IWindsorContainer container;

    protected void Application_Start()
    {
        //... MVC / Web API routing etc.
        BootStrapper bs = new BootStrapper();
        container = bs.ConfigureCastleWindsorMVC();
    }

BootStrapper.ConfigureCastleWindsorMVC()剪断

        IWindsorContainer container = new WindsorContainer()
            .Install(
                new LoggerInstaller()
                //...,
                , new ControllersInstaller()
            );

        var controllerFactory = new WindsorControllerFactory(container.Kernel);
        ControllerBuilder.Current.SetControllerFactory(controllerFactory);
        return container;

所需的更改

从 Mark Seemann 的帖子中,您需要通过IHttpControllerActivator. 这是您需要的他的适配器实现。

public class WindsorCompositionRoot : IHttpControllerActivator
{
    private readonly IWindsorContainer container;

    public WindsorCompositionRoot(IWindsorContainer container)
    {
        this.container = container;
    }

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

        request.RegisterForDispose(
            new Release(() => this.container.Release(controller)));

        return controller;
    }

    private class Release : IDisposable
    {
        private readonly Action release;

        public Release(Action release) { this.release = release; }

        public void Dispose()
        {
            this.release();
        }
    }
}

使用 IHttpControllerActivator 适配器和 MVC Castle Windsor 容器实现,您只需要在Global.asax.cs(或者如果您使用的话,在 BootStrapper 中)配置它。它必须在 MVC 初始化之后,因为 MVC 初始化具有所有安装程序。

    private static IWindsorContainer container;

    protected void Application_Start()
    {
        // MVC / Web API routing etc.
        BootStrapper bs = new BootStrapper();
        container = bs.ConfigureCastleWindsorMVC();
        // Web API Castle Windsor ++ ADD THIS ++
        GlobalConfiguration.Configuration.Services.Replace(
            typeof(IHttpControllerActivator),
            new WindsorCompositionRoot(container));
    }

最后结果:

Web API 控制器可以像使用 MVC 控制器一样使用注入的依赖项。

public class TestController : ApiController
{
    private readonly ITestService TestService;

    public TestController(ITestService testService)
    {
        this.TestService = testService;
    }

    // GET api/<controller>
    public IEnumerable<string> Get()
    {
        return TestService.GetSomething();
        //return new string[] { "value1", "value2" };
    }
}
于 2014-09-27T14:50:52.520 回答
12

为了使用带有 webapi 的 Windsor,请遵循 http://blog.ploeh.dk/2012/10/03/DependencyInjectioninASP.NETWebAPIwithCastleWindsor/(BEH :固定链接)

另请阅读 ASP.NET Web API 中的 Castle Windsor/DelegatingHandler/IPrincipal 依赖注入 (DI)/控制反转 (IoC)

您可以在同一个应用程序中使用 webapi 和 MVC 控制器(我更喜欢将其分开),但路由和控制器工厂是不同的,您必须设置两个不同的配置并处理路由重叠......对于 MVC 和 Windsor,您可以找到伟大的

于 2013-04-23T03:50:47.410 回答
6

以下示例项目给了我正在寻找的答案。它使用 Castle Windsor 进行依赖注入。我能够在同一个应用程序上使用 MVC 控制器和 Web API 控制器。

mirajavora / WebAPISample


这是详细说明它的帖子:

ASP.NET Web API 入门

于 2013-10-26T23:41:48.663 回答
1

首先,正如 Iko 所说,您需要创建一个实现IHttpControllerActivator.

然后在ContainerBootstrapper添加Bootstrap()以下将默认替换为已实现的:

 //This will help in creating Web api with Dependency injection
 GlobalConfiguration.Configuration.Services.Replace(
 typeof(IHttpControllerActivator),
 new WindsorCompositionRoot(container));

最后,这里没有提到,如果没有它,它对我不起作用,你应该在你实现的IWindsorInstaller服务中添加以下内容install()

container.Register(
    Classes.FromThisAssembly()
    .BasedOn<ApiController>()
    .LifestyleTransient()    
);
于 2018-08-12T08:54:47.430 回答