【问题标题】:Castle Windsor ApiController Factory implementation for ASP.NET Web APIASP.NET Web API 的 Castle Windsor ApiController Factory 实现
【发布时间】:2012-03-22 09:49:04
【问题描述】:

我知道可以使用 DependencyResolver 并将 Castle Windsor 注册到 MVC,但由于 https://stackoverflow.com/a/4889222/139392 中描述的问题,我们在 MVC 项目中坚持使用 WindsorControllerFactory 实现方法。

但是看起来 ApiControllers 正在使用某种其他类型的工厂,因为 Castle Windsor 无法注入依赖项。

有没有人想出如何在不使用 DependencyResolver 的情况下将 Castle Windsor 与 ASP.NET Web API 和 MVC 一起使用?

【问题讨论】:

标签: c# asp.net asp.net-mvc-3 castle-windsor asp.net-web-api


【解决方案1】:

感谢 Critiano 的帖子和一些在线搜索,我设法让它工作这里是其他人遇到此问题的代码。我已经将它与 MVC3 和 ASP.NET Web Api Beta 一起使用,但我认为相同的解决方案应该适用于 MVC4。

首先,我创建了一个 WindsorHttpControllerFactory,因为 ApiControllers 使用与 MVC 不同的工厂。

public class WindsorHttpControllerFactory : IHttpControllerFactory
{
    private readonly IKernel kernel;
    private readonly HttpConfiguration configuration;

    public WindsorHttpControllerFactory(IKernel kernel, HttpConfiguration configuration)
    {
        this.kernel = kernel;
        this.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));
        }

        var controller = kernel.Resolve<IHttpController>(controllerName);
        controllerContext.Controller = controller;
        controllerContext.ControllerDescriptor = new HttpControllerDescriptor(configuration, controllerName, controller.GetType());

        return controllerContext.Controller;
    }

    public void ReleaseController(IHttpController controller)
    {
        kernel.ReleaseComponent(controller);
    }
}

棘手的部分是注册它似乎涉及注册一大堆其他东西。这就是我最终的结果。

container.Register(Component.For<IHttpControllerFactory>().ImplementedBy<WindsorHttpControllerFactory>().LifeStyle.Singleton);
container.Register(Component.For<System.Web.Http.Common.ILogger>().ImplementedBy<MyLogger>().LifeStyle.Singleton);
container.Register(Component.For<IFormatterSelector>().ImplementedBy<FormatterSelector>().LifeStyle.Singleton);
container.Register(Component.For<IHttpControllerActivator>().ImplementedBy<DefaultHttpControllerActivator>().LifeStyle.Transient);
container.Register(Component.For<IHttpActionSelector>().ImplementedBy<ApiControllerActionSelector>().LifeStyle.Transient);
container.Register(Component.For<IActionValueBinder>().ImplementedBy<DefaultActionValueBinder>().LifeStyle.Transient);
container.Register(Component.For<IHttpActionInvoker>().ImplementedBy<ApiControllerActionInvoker>().LifeStyle.Transient);
container.Register(Component.For<System.Web.Http.Metadata.ModelMetadataProvider>().ImplementedBy<System.Web.Http.Metadata.Providers.CachedDataAnnotationsModelMetadataProvider>().LifeStyle.Transient);
container.Register(Component.For<HttpConfiguration>().Instance(configuration));

//Register all api controllers
container.Register(AllTypes.FromAssembly(assemblyToRegister)
                            .BasedOn<IHttpController>()
                            .Configure(registration => registration.Named(registration.ServiceType.Name.ToLower().Replace("controller", "")).LifeStyle.Transient));

//Register WindsorHttpControllerFactory with Service resolver
GlobalConfiguration.Configuration.ServiceResolver.SetService(typeof(IHttpControllerFactory), container.Resolve<IHttpControllerFactory>());

我必须创建自己的 ILogger 实现,您可以使用像下面这样的存根版本。

public class MyLogger : System.Web.Http.Common.ILogger
{
    public void LogException(string category, TraceLevel level, Exception exception)
    {
        // Do some logging here eg. you could use log4net
    }

    public void Log(string category, TraceLevel level, Func<string> messageCallback)
    {
        // Do some logging here eg. you could use log4net
    }
}

【讨论】:

    【解决方案2】:

    两天前我也遇到了这个问题,这个post 帮助了我。并且不要忘记在 Windsor 引导程序中添加 WebAPI 控制器。

    container.Register(AllTypes.FromThisAssembly().BasedOn<IHttpController>().LifestyleTransient());
    

    ASP.NET MVC 4 RC 更新:useful post 告诉您如何将 Windsor 与 WebAPI 一起使用,它就像一个魅力。

    【讨论】:

      【解决方案3】:

      看看这个post

      我还没有切换到包含 web.api 的 mvc 4 beta(我仍在使用 WCF web api Prev6),但是线程中指出的内容似乎是可行的方法

      【讨论】:

        【解决方案4】:

        我写了一篇关于如何做到这一点并将其连接到 RavenDB 的帖子,您可能会发现它很有用 here

        【讨论】:

          【解决方案5】:

          我已设法通过使用 GlobalConfiguration.Configuration.ServiceResolver.SetResolver 从我的 Windsor 容器中解决问题,如 here 所示。

          温莎代码示例

          private void BootStrapWindsorContainer()
          {
               _container = new WindsorContainer()
                    .Install(FromAssembly.This());
          
               var controllerFactory = new WindsorControllerFactory(_container.Kernel);
          
               ControllerBuilder.Current.SetControllerFactory(controllerFactory);
               ServiceLocator.SetLocatorProvider(() => new WindsorServiceLocator(_container));
               GlobalConfiguration.Configuration.ServiceResolver.SetResolver(
                   t =>
                       {
                           try
                          {
                              return _container.Resolve(t);
                          }
                          catch
                          {
                              return null;
                          }
                      },
                      t =>
                      {
                          try
                          {
                              return _container.ResolveAll(t).OfType<object>();
                          }
                          catch
                          {
                       return new List<object>();
                   }
              });
          }
          

          当您无法解析类型时返回 null 有效,并且似乎 MVC 将新建依赖项。

          编辑: 确保你有 IHttpController 的安装程序

          【讨论】:

          【解决方案6】:
          public class WindsorHttpControllerFactory : IHttpControllerActivator
              {
                  readonly IWindsorContainer _container;
          
                  public WindsorHttpControllerFactory(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;
                  }
          
                  class Release : IDisposable
                  {
                      readonly Action _release;
          
                      public Release(Action release)
                      {
                          _release = release;
                      }
          
                      public void Dispose()
                      {
                          _release();
                      }
                  }
              }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-08-04
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多