Dependency Injection in WebAPI with Castle Windsor

前端 未结 3 918
渐次进展
渐次进展 2020-12-23 12:33

I want to implement Dependency Injection in WebApi application using Castle Windsor. I have following sample code -

Interface -

publ         


        
相关标签:
3条回答
  • 2020-12-23 12:51

    I didn't work directly with Castle Windsor, but I believe the logic should be similar:

    Your WatchController ctor should look like this:

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

    And this is where you inject the dependency.

    You should have the equivalent to a Locator in which you register your WatchController class, and tell it which watch it should receive depending on whatever you want ... design/runtime , day of the week, random number ... whatever works or whatever you need...

    The following code is from MVVM-Light, but should clarify the above paragraph:

    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>();
        ...
    }
    
    0 讨论(0)
  • 2020-12-23 12:54

    CodeCaster, Noctis and Cristiano thank you for all your help and guidance.. I just got the solution for my above query -

    The first step is to use nuget to install the Windsor.Castle packages in the WebApi solution.

    enter image description here

    Consider the following code snippet -

    Interface IWatch.cs

    public interface IWatch
    {
         DateTime GetTime();
    }
    

    Class Watch.cs

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

    The ApiController WatchController.cs is defined as follows: -

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

    In the controller we have injected the dependency through IWatch object in the WatchController constructor. I have used IDependencyResolver and IDependencyScope to achieve dependency injection in web api. The IDependencyResolver interface is used to resolve everything outside a request scope.

    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<object> GetServices(Type t)
        {
            return _container.ResolveAll(t).Cast<object>().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<object> GetServices(Type t)
        {
            return _container.ResolveAll(t).Cast<object>().ToArray();
        }
    
        public void Dispose()
        {
            _scope.Dispose();
        }
    }
    

    WatchInstaller.cs

    Installers are simply types that implement the IWindsorInstaller interface. The interface has a single method called Install. The method gets an instance of the container, which it can then register components with using fluent registration 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<IHttpController>()
                                .LifestylePerWebRequest());***
              container.Register(
                  Component.For<IWatch>().ImplementedBy<Watch>()
              );
          }
    }
    

    Finally, we need to replace the default dependency resolver with the Windsor implementation in Global.asax.cs (Application_Start method) and install our dependencies:

        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;
        }    
    
    0 讨论(0)
  • 2020-12-23 13:10

    Read Mark Seemann post about windsor plumbing for webapi.

    0 讨论(0)
提交回复
热议问题