首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >使用Castle Windsor实现WebAPI中的依赖注入

使用Castle Windsor实现WebAPI中的依赖注入
EN

Stack Overflow用户
提问于 2013-11-11 19:26:40
回答 3查看 16.9K关注 0票数 21

我想使用Castle Windsor在WebApi应用程序中实现依赖注入。我有以下示例代码:

接口-

代码语言:javascript
复制
public interface IWatch
{
    {
        DateTime GetTime();
    }
}

遵循观察类实现了IWatch接口-

代码语言:javascript
复制
public class Watch:IWatch
{
        public DateTime GetTime()
        {
            return DateTime.Now;
        }
}

WatchController控制器- WebApi,如下所示-

代码语言:javascript
复制
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 Castle依赖注入原理来消除在构造函数中初始化IWatch的依赖。

有没有人能告诉我在这种WebApi情况下实现依赖注入的步骤?提前感谢!

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2013-11-19 20:38:39

CodeCaster,Noctis和Cristiano感谢你们的帮助和指导。我刚刚得到了上面问题的解决方案-

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

考虑下面的代码片段-

Interface IWatch.cs接口

代码语言:javascript
复制
public interface IWatch
{
     DateTime GetTime();
}

Class Watch.cs

代码语言:javascript
复制
public class Watch:IWatch
{
    public DateTime GetTime()
    {
        return DateTime.Now;
    }
}

ApiController WatchController.cs的定义如下:-

代码语言:javascript
复制
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对象注入了依赖项。我已经使用IDependencyResolverIDependencyScope在web中实现了依赖注入。IDependencyResolver接口用于解析请求作用域之外的所有内容。

WindsorDependencyResolver.cs

代码语言:javascript
复制
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<object> GetServices(Type t)
    {
        return _container.ResolveAll(t).Cast<object>().ToArray();
    }

    public IDependencyScope BeginScope()
    {
        return new WindsorDependencyScope(_container);
    }

    public void Dispose()
    {

    }
}

WindsorDependencyScope.cs

代码语言:javascript
复制
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<object> GetServices(Type t)
    {
        return _container.ResolveAll(t).Cast<object>().ToArray();
    }

    public void Dispose()
    {
        _scope.Dispose();
    }
}

WatchInstaller.cs

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

代码语言:javascript
复制
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<IHttpController>()
                            .LifestylePerWebRequest());***
          container.Register(
              Component.For<IWatch>().ImplementedBy<Watch>()
          );
      }
}

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

代码语言:javascript
复制
    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;
    }    
票数 71
EN

Stack Overflow用户

发布于 2013-11-12 16:39:05

阅读Mark Seemann关于windsor plumbing for webapi的帖子。

票数 6
EN

Stack Overflow用户

发布于 2013-11-11 19:40:28

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

您的WatchController ctor应该如下所示:

代码语言:javascript
复制
public WatchController(IWatch watch) 
{
    _watch = watch;
}

这就是你inject依赖的地方。

你应该有一个等同于定位器的东西,你可以在其中注册你的WatchController类,并告诉它应该接收哪个手表,这取决于你想要什么……设计/运行时间、星期几、随机数...不管你需要的是什么.

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

代码语言:javascript
复制
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<IDataService, Design.DesignDataService>();
    }
    // This will run REAL stuff, in runtime
    else
    {
        SimpleIoc.Default.Register<IDataService, DataService>();
    }

    // You register your classes, so the framework can do the injection for you
    SimpleIoc.Default.Register<MainViewModel>();
    ...
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/19905186

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档