使用Castle Windsor在WebAPI中进行dependency injection

我想使用Castle Windsor在WebApi应用程序中实现dependency injection。 我有以下示例代码 –

界面 –

public interface IWatch { { DateTime GetTime(); } } 

以下Watch类实现了IWatch接口 –

 public class Watch:IWatch { public DateTime GetTime() { return DateTime.Now; } } 

WebApi控制器 – WatchController如下 –

 public class WatchController : ApiController { private readonly IWatch _watch; public WatchController() { _watch = new Watch(); } //http://localhost:48036/api/Watch public string Get() { var message = string.Format("The current time on the server is: {0}", _watch.GetTime()); return message; } } 

目前我在WatchController构造函数中使用Watch启动IWatch对象。 我想删除使用Windsor Castledependency injection原理在构造函数中初始化IWatch的依赖性。

在这种WebApi的情况下,任何人都可以为我提供实现dependency injection的步骤吗? 提前致谢!

CodeCaster,Noctis和Cristiano感谢您的所有帮助和指导..我刚刚得到了上述查询的解决方案 –

第一步是使用nuget在WebApi解决方案中安装Windsor.Castle包。

在此处输入图像描述

请考虑以下代码段 –

接口IWatch.cs

 public interface IWatch { DateTime GetTime(); } 

Watch.cs

 public class Watch:IWatch { public DateTime GetTime() { return DateTime.Now; } } 

ApiController WatchController.cs的定义如下: –

 public class WatchController : ApiController { private readonly IWatch _watch; public WatchController(IWatch watch) { _watch = watch; } public string Get() { var message = string.Format("The current time on the server is: {0}", _watch.GetTime()); return message; } } 

在控制器中,我们通过WatchController构造函数中的IWatch对象注入了依赖项。 我使用了IDependencyResolver和IDependencyScope来实现web api中的dependency injection。 IDependencyResolver接口用于解析请求范围之外的所有内容。

WindsorDependencyResolver.cs

 internal sealed class WindsorDependencyResolver : IDependencyResolver { private readonly IWindsorContainer _container; public WindsorDependencyResolver(IWindsorContainer container) { if (container == null) { throw new ArgumentNullException("container"); } _container = container; } public object GetService(Type t) { return _container.Kernel.HasComponent(t) ? _container.Resolve(t) : null; } public IEnumerable GetServices(Type t) { return _container.ResolveAll(t).Cast().ToArray(); } public IDependencyScope BeginScope() { return new WindsorDependencyScope(_container); } public void Dispose() { } } 

WindsorDependencyScope.cs

 internal sealed class WindsorDependencyScope : IDependencyScope { private readonly IWindsorContainer _container; private readonly IDisposable _scope; public WindsorDependencyScope(IWindsorContainer container) { if (container == null) { throw new ArgumentNullException("container"); } _container = container; _scope = container.BeginScope(); } public object GetService(Type t) { return _container.Kernel.HasComponent(t) ? _container.Resolve(t) : null; } public IEnumerable GetServices(Type t) { return _container.ResolveAll(t).Cast().ToArray(); } public void Dispose() { _scope.Dispose(); } } 

WatchInstaller.cs

安装程序只是实现IWindsorInstaller接口的类型。 该接口有一个名为Install的方法。 该方法获取容器的实例,然后可以使用流畅的注册API注册组件:

 public class WatchInstaller : IWindsorInstaller { public void Install(IWindsorContainer container, IConfigurationStore store) { //Need to Register controllers explicitly in your container //Failing to do so Will receive Exception: //> An error occurred when trying to create //a controller of type //> 'xxxxController'. Make sure that the controller has a parameterless //> public constructor. //Reason::Basically, what happened is that you didn't register your controllers explicitly in your container. //Windsor tries to resolve unregistered concrete types for you, but because it can't resolve it (caused by an error in your configuration), it return null. //It is forced to return null, because Web API forces it to do so due to the IDependencyResolver contract. //Since Windsor returns null, Web API will try to create the controller itself, but since it doesn't have a default constructor it will throw the "Make sure that the controller has a parameterless public constructor" exception. //This exception message is misleading and doesn't explain the real cause. container.Register(Classes.FromThisAssembly() .BasedOn() .LifestylePerWebRequest());*** container.Register( Component.For().ImplementedBy() ); } } 

最后,我们需要使用Global.asax.cs(Application_Start方法)中的Windsor实现替换默认依赖项解析器并安装我们的依赖项:

  private static IWindsorContainer _container; protected void Application_Start() { AreaRegistration.RegisterAllAreas(); WebApiConfig.Register(GlobalConfiguration.Configuration); FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); RouteConfig.RegisterRoutes(RouteTable.Routes); BundleConfig.RegisterBundles(BundleTable.Bundles); ConfigureWindsor(GlobalConfiguration.Configuration); } public static void ConfigureWindsor(HttpConfiguration configuration) { _container = new WindsorContainer(); _container.Install(FromAssembly.This()); _container.Kernel.Resolver.AddSubResolver(new CollectionResolver(_container.Kernel, true)); var dependencyResolver = new WindsorDependencyResolver(_container); configuration.DependencyResolver = dependencyResolver; } 

阅读Mark Seemann关于webapi的温莎管道的文章 。

我没有直接与Castle Windsor合作,但我相信逻辑应该是相似的:

您的WatchController ctor应如下所示:

 public WatchController(IWatch watch) { _watch = watch; } 

这是您inject依赖项的地方。

你应该拥有一个Locator,你可以在其中注册你的WatchController类,并根据你想要的任何东西告诉它应该接收哪个手表…设计/运行时,星期几,随机数…无论什么工作或者其他什么你需要…

以下代码来自MVVM-Light,但应该澄清以上段落:

 static ViewModelLocator() { ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default); // This will run in design mode, so all your VS design data will come from here if (ViewModelBase.IsInDesignModeStatic) { SimpleIoc.Default.Register(); } // This will run REAL stuff, in runtime else { SimpleIoc.Default.Register(); } // You register your classes, so the framework can do the injection for you SimpleIoc.Default.Register(); ... }