Dependency Injection (به اختصار DI، ترجمه فارسی : تزریق وابستگی) الگویی است که جهت پیاده سازی اصل Dependency Inversion در طراحی شی گراء مطرح شده است. در صورتی که با مفاهیم Dependency Injection و IoC Container آشنایی ندارید، می توانید به مطالعه ی این مقاله از آقای Martin Fowler بپردازید. Castle Windsor یکی از  IoC Container های معروف، رایگان و متن باز نوشته شده برای NET. می باشد. در این مقاله به پیاده سازی این الگو در ASP.NET Web API با کتابخانه ی Castle Windsor میپردازیم.
 
پیاده سازی Controller ها و Service ها
ابتدا Controller ها و کلاس های سرویس مورد نظر را خود را پیاده سازی کنید. سپس با استفاده از Constructor Injection کلاس های سرویس خود را به داخل Controller ها Inject کنید. مثال ساده ی زیر را در نظر بگیرید :

public interface IUserService
{
    List<AppUser> GetList();
}
 
 
public class SimpleUserService : IUserService
{
    public List<AppUser> GetList()
    {
        //
        //   Retrieve some data
        //
    }
}
 

public class UserController : ApiController
{
    private readonly IUserService _userService;
    public UserController(IUserService userService)
    {
        _userService = userService;
    }
 
    public List<AppUser> Get()
    {
        return _userService.GetList();
    } 
}
 
اضافه کردن و Config کتابخانه Castle Windsor به پروژه
جهت اضافه کردن این کتابخانه به پروژه از دستور زیر در Package Manager Console استفاده نمایید :


install-package Castle.Windsor
برای کار با Castle Windsor مانند هر IoCC دیگری، نیاز دارید تا Dependency ها و کلاس های پیاده سازی آنها را معرفی کنید. برای این کار کلاس فوق را در App_Start پروژه ایجاد میکنیم :


using Castle.MicroKernel.Registration;
using Castle.Windsor;
.
.
.
public static class CastleConfig
{
    public static IWindsorContainer GetContainer()
    {
        var container = new WindsorContainer();
        container.Register(Component.For<IUserService>()
                                    .ImplementedBy<SimpleUserService>());
 
        container.Register(Component.For<UserController>().LifestylePerWebRequest());
 
        return container;
    }
}
 کلاس IUserService و پیاده سازی آن و همچنین کلاس UserController را در Container ثبت کردیم. از آنجا که Controller ها به ازای هر Request باید ایجاد شوند، از متد LifestylePerWebRequest برای ثبت UserController استفاده کردیم. در این مثال فرض شده است که UserService یک سرویس Stateless بوده و تعریف آن به صورت Singleton مانعی ندارد. به همین دلیل هیچ نوع LifeStyle خاصی برای آن نوشته نشده است تا Windsor از LifeStyle پیش فرض (یعنی Singleton) استفاده نماید.
حال کافی است تا ControllerActivator مخصوص به خود را نوشته و در آن از Windsor برای ایجاد Controller ها استفاده نماییم. سپس ControllerActivator نوشته شده را به عنوان سرویس پیش فرض تعریف میکنیم تا WebAPI برای ساخت Controller ها از کلاس فوق استفاده نماید.

پیاده سازی ControllerActivator سفارشی
برای ساخت ControllerActivator سفارشی، نیاز به پیاده سازی اینترفیس IHttpControllerActivator دارید :

using System.Net.Http;
using System.Web.Http.Controllers;
using System.Web.Http.Dispatcher;
using Castle.Windsor;
.
.
.
public class CastleControllerActivator : IHttpControllerActivator
{
    private IWindsorContainer _container;
 
    public CastleControllerActivator(IWindsorContainer container)
    {
        _container = container;
    }
 
    public IHttpController Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)
    {
        return (IHttpController)_container.Resolve(controllerType);
    }
}
 همانطور که در کد مشاهده میکنید اینترفیس IWindsorContainer از طریق Constructor به این کلاس تزریق شده است تا Activator نوشته شده بتواند برای ساخت Controller ها از آن استفاده نماید. برای اتمام کار تنها کافی است تا یک نمونه از کلاس CastleControllerActivator را به عنوان ControllerActivator پیش فرض در Global.Asax معرفی کنید :

public class WebApiApplication : System.Web.HttpApplication
{
    protected void Application_Start()
    {
        .
        .
        .  
        var container = CastleConfig.GetContainer();
        var contollerActivator = new CastleControllerActivator(container);
 
        GlobalConfiguration.Configuration.Services.Replace(typeof(IHttpControllerActivator), contollerActivator);
    }
}
 
نکته : در صورتی که تعداد Controller های پروژه ی شما زیاد است، می توانید به جای ثبت تک به تک آنها در Container، از امکانات Windsor برای ثبت دسته ای Dependency ها استفاده بکنید. به مثال اصلاح شده ی فوق دقت کنید :

public static IWindsorContainer GetContainer()
{
    var container = new WindsorContainer();
    container.Register(Component.For<IUserService>()
                                .ImplementedBy<SimpleUserService>());
 
    //container.Register(Component.For<UserController>().LifestylePerWebRequest());
    container.Register(Classes.FromThisAssembly().BasedOn<ApiController>().LifestylePerWebRequest());
 
    return container;
}