Как мне соединить различные части моего кода API веб-интерфейса Castle Windsor?

Как мне соединить различные части моего кода API веб-интерфейса Castle Windsor, чтобы контроллер 's маршрутизация выбирает правильную реализацию интерфейса?

Заметка: После нескольких фальстартов / тупиков и частичных побед (Вот а такжеВот а такжеВот), Я собираюсь поднять это как можно скорее для максимума500 точки. Но я'Я только собираюсь наградить действительно хороший ответ - IOW, достаточно ясный, чтобы я мог его понять, и "включи в мой проект, чтобы я мог подключить конкретный класс к конкретному контроллеру.

Здесь ничего не идет: у меня есть веб-API ("MVC») проект. Правда, у этого серверного проекта нет буквы "V" (Вид), так что, возможно, лучшим аббревиатурой будет MRC (Модель / Репозиторий / Контроллер).

Во всяком случае, яЯ пытаюсь добавить DI к нему с помощью Castle Windsor.

Я использую и копаю концепцию обмена конкретными классами через аргументы интерфейса конструктора. Как реализовать эту функциональность,

был зверем яя боролся сЯ довольно ушибленный и кровавый в настоящее время, с запутанными волосами и инкрустированными грязью ноздрями.

Думаю, у меня есть большая часть кода, который мне нужен, во всяком случае, для начала. Имея в виду DI, ятеперь у нас есть "DIPlumbing» папка и "DIInstallers» папка. "DIPlumbing» папка содержит два класса: WindsorCompositionRoot.cs и WindsorControllerFactory.cs.

"DIInstallers» На данный момент в папке находятся три файла: ISomethingProvider.cs, SomethingProvider.cs и SomethingProviderInstaller.cs.

SomethingProviderInstaller, кажется, является ключевым в соединении интерфейсов / классов в DIInstallers с материалом в папке DIPlumbing.

(Я также изменил Global.asax.cs, чтобы заменить бизнес маршрутизации контроллера по умолчанию заменой Castle Windsor).

Но я'Я не понимаю, какие классы я должен поместить в папку DIInstallers. Должны ли они занять место моих репозиториев (которые также имеют интерфейс и конкретный класс, реализующий этот интерфейс для каждой модели)? IOW, я должен в основном переместить мой код Репозитория в папку DIInstallers - и затем избавиться от модулей IRepository и Repository?

Это, конечно, приведет к необходимым изменениям в классах Controller, которые на данный момент ссылаются на классы репозитория.

Или классы Repositories и DIInstallers сосуществуют? Если да, то какова связь / связь между контроллерами, установщиками и репозиториями?

Кажется, чем больше я читаю о DI и Castle Windsor, тем больше я запутался. Я нене знаю, если яЯ слишком плотный для этого, или если яЯ пытаюсь сделать это сложнее, чем есть, или если проблема заключается в противоречивых стилях его использования / представления. Суть в том, что яЯ застрял в зыбучих песках и нуждаюсь в Джонни Квесте, чтобы вытянуть крепкий бамбуковый жезл.

Наилучшим ответом, возможно, и, вероятно, слишком большим, чтобы спросить, было бы визуальное представление о том, как все эти компоненты - контроллеры, модели, репозитории, установщики, Global.asax.cs, корни композиции, фабрики, поставщики и т. Д. , связаны друг с другом.

Для целей "полное раскрытие," Я добавлю то, что я надеюсь, являются ключевыми элементами моего кода ниже, чтобы показать, что яу нас есть и как (надеюсь) соединяется друг с другом.

Корень композиции:

public class WindsorCompositionRoot : IHttpControllerActivator
{
    private readonly IWindsorContainer container;

    public WindsorCompositionRoot(IWindsorContainer container)
    {
        this.container = container;
    }

    public IHttpController Create(
        HttpRequestMessage request,
        HttpControllerDescriptor controllerDescriptor,
        Type controllerType)
    {
        var controller =
            (IHttpController)this.container.Resolve(controllerType);

        request.RegisterForDispose(
            new Release(
                () => this.container.Release(controller)));

        return controller;
    }

    private class Release : IDisposable
    {
        private readonly Action release;

        public Release(Action release)
        {
            this.release = release;
        }

        public void Dispose()
        {
            this.release();
        }
    }
}

Фабрика контроллеров:

public class WindsorControllerFactory : DefaultControllerFactory
{
    private readonly IKernel kernel;

    public WindsorControllerFactory(IKernel kernel)
    {
        this.kernel = kernel;
        //According to my understanding of http://docs.castleproject.org/Windsor.Typed-Factory-Facility.ashx, I might need this:
        kernel.AddFacility();
    }

    protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
    {
        if (controllerType == null)
        {
            throw new HttpException(404, string.Format("The controller for path '{0}' could not be found.", requestContext.HttpContext.Request.Path));
        }
        return (IController)kernel.Resolve(controllerType);
    }

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

// Обратите внимание "Что-то" ниже, надеюсь, в конце концов будетОтделы» а затем другие классы теперь представлены в моделях и их соответствующих репозиториях и контроллерах

ISomethingProvider:

public interface ISomethingProvider
{
    // These are placeholder methods; I don't know which I will need yet...
    //bool Authenticate(string username, string password, bool createPersistentCookie);
    //void SignOut();
}

SomethingProvider:

public class SomethingProvider : ISomethingProvider
{
    // TODO: Implement methods in ISomethingProvider, once they have been added
}

SomethingProviderInstaller:

public class SomethingProviderInstaller : IWindsorInstaller
{
    public void Install(IWindsorContainer container, IConfigurationStore store)
    {
        container.Register(Classes.FromThisAssembly()
                               .BasedOn(typeof(ISomethingProvider))
                               .WithServiceAllInterfaces());
        // From http://app-code.net/wordpress/?p=676; see also http://devlicio.us/blogs/krzysztof_kozmic/archive/2009/12/24/castle-typed-factory-facility-reborn.aspx
        container.AddFacility();
        container.Register(Component.For().AsFactory()); 
    }
}

контроллер:

public class DepartmentsController : ApiController
{
    private readonly IDepartmentRepository _deptsRepository;

    public DepartmentsController(IDepartmentRepository deptsRepository)
    {
        if (deptsRepository == null)
        {
            throw new ArgumentNullException("deptsRepository is null");
        }
        _deptsRepository = deptsRepository;
    }

    public int GetCountOfDepartmentRecords()
    {
        return _deptsRepository.Get();
    }

    public IEnumerable GetBatchOfDepartmentsByStartingID(int ID, int CountToFetch)
    {
        return _deptsRepository.Get(ID, CountToFetch);
    }
. . .
}

IRepository:

public interface IDepartmentRepository
{
    int Get();
    IEnumerable Get(int ID, int CountToFetch);
}

Repository:

public class DepartmentRepository : IDepartmentRepository
{
    private readonly List departments = new List();

    public DepartmentRepository()
    {
        using (var conn = new OleDbConnection(
            @"Provider=Microsoft.ACE.OLEDB.12.0;[bla]"))
        {
            using (var cmd = conn.CreateCommand())
            {
                cmd.CommandText = "SELECT td_department_accounts.dept_no, IIF(ISNULL(t_accounts.name),'No Name provided',t_accounts.name) AS name FROM t_accounts INNER JOIN td_department_accounts ON t_accounts.account_no = td_department_accounts.account_no ORDER BY td_department_accounts.dept_no";
                cmd.CommandType = CommandType.Text;
                conn.Open();
                int i = 1;
                using (OleDbDataReader oleDbD8aReader = cmd.ExecuteReader())
                {
                    while (oleDbD8aReader != null && oleDbD8aReader.Read())
                    {
                        int deptNum = oleDbD8aReader.GetInt16(0);
                        string deptName = oleDbD8aReader.GetString(1);
                        Add(new Department { Id = i, AccountId = deptNum, Name = deptName });
                        i++;
                    }
                }
            }
        }
    }

    public int Get()
    {
        return departments.Count;
    }

    private Department Get(int ID) // called by Delete()
    {
        return departments.First(d => d.Id == ID);
    }

    public IEnumerable Get(int ID, int CountToFetch)
    {
        return departments.Where(i => i.Id > ID).Take(CountToFetch);
    }
. . .
}

Global.asax.cs:

public class WebApiApplication : System.Web.HttpApplication
{
    private static IWindsorContainer container;

    protected void Application_Start()
    {

        AreaRegistration.RegisterAllAreas();
        GlobalConfiguration.Configure(WebApiConfig.Register);
        BootstrapContainer();

        FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
        RouteConfig.RegisterRoutes(RouteTable.Routes);
        BundleConfig.RegisterBundles(BundleTable.Bundles);
    }

    private static void BootstrapContainer()
    {
        container = new WindsorContainer().Install(FromAssembly.This());
        var controllerFactory = new WindsorControllerFactory(container.Kernel);

        ControllerBuilder.Current.SetControllerFactory(controllerFactory);

        GlobalConfiguration.Configuration.Services.Replace(
            typeof(IHttpControllerActivator), new WindsorCompositionRoot(container));
    }

    protected void Application_End()
    {
        container.Dispose();
    }
ОБНОВИТЬ

При попытке запустить сервер, чтобы он мог проверить его с помощью Fiddler2, чтобы увидеть, что именно передается, он потерпел неудачу в этой строке в WindsorControllerFactory:

public WindsorControllerFactory(IKernel kernel)
{
    this.kernel = kernel;
    kernel.AddFacility();  it == typeof(WindsorInfrastructureInstaller));

        var retVal = new List();
        retVal.Add(windsorInfrastructureInstaller);
        retVal.AddRange(installerTypes
            .Where(it =>
                typeof(IWindsorInstaller).IsAssignableFrom(it) &&
                !retVal.Contains(it)
                ));

        return retVal;
    }
}

WindsorInfrastructureInstaller.cs:

public class WindsorInfrastructureInstaller : IWindsorInstaller
{
    public void Install(IWindsorContainer container, IConfigurationStore store)
    {
        container.AddFacility();
    }
}

В вашем global.asax вы 'создам ииспользовать ваш завод-установщик следующим образом

   var installerFactory = new PlatypusInstallerFactory();
   container.Install(FromAssembly.This(installerFactory));

Если да, что это будет делать для меня? Вышеуказанное автоматически регистрирует мой класс Controller и / или Repository?

ОБНОВЛЕНИЕ 3

Я сейчас использую много кода из [http://blog.kerbyyoung.com/2013/01/setting-up-castle-windsor-for-aspnet.html#comment-form]

Ключевые части, я думаю:

Global.asax.cs:

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

WindsorDependencyResolver.cs:

namespace HandheldServer
{
    public class WindsorDependencyResolver : System.Web.Http.Dependencies.IDependencyResolver
    {
        private readonly IWindsorContainer _container;

        public WindsorDependencyResolver(IWindsorContainer container)
        {
            _container = container;
        }

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

        public object GetService(Type serviceType)
        {
            if (!_container.Kernel.HasComponent(serviceType))
            {
                return null;
            }
            return this._container.Resolve(serviceType);
        }

        public IEnumerable GetServices(Type serviceType)
        {
            if (!_container.Kernel.HasComponent(serviceType))
            {
                return new object[0];
            }

            return _container.ResolveAll(serviceType).Cast();
        }

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

    public class WindsorDependencyScope : IDependencyScope
    {
        private readonly IWindsorContainer _container;
        private readonly IDisposable _scope;

        public WindsorDependencyScope(IWindsorContainer container)
        {
            this._container = container;
            this._scope = container.BeginScope(); 
        }

        public object GetService(Type serviceType)
        {
            if (_container.Kernel.HasComponent(serviceType))
            {
                return _container.Resolve(serviceType);
            }
            else
            {
                return null;
            }
        }

        public IEnumerable GetServices(Type serviceType)
        {
            return this._container.ResolveAll(serviceType).Cast();
        }

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

    public class ApiControllersInstaller : IWindsorInstaller
    {
        public void Install(Castle.Windsor.IWindsorContainer container, Castle.MicroKernel.SubSystems.Configuration.IConfigurationStore store)
        {
            container.Register(Classes.FromThisAssembly() // should it be Types instead of Classes?
             .BasedOn()
             .LifestylePerWebRequest());
        }
    }

    // This idea from https://github.com/argeset/set-locale/blob/master/src/client/SetLocale.Client.Web/Configurations/IocConfig.cs
    public class ServiceInstaller : IWindsorInstaller
    {
        public void Install(IWindsorContainer container, IConfigurationStore store)
        {
            container.Register(
                Component.For().ImplementedBy().LifestylePerWebRequest(),
                Component.For().ImplementedBy().LifestylePerWebRequest(),
                Component.For().ImplementedBy().LifestylePerWebRequest(),
                Component.For().ImplementedBy().LifestylePerWebRequest(),
                Component.For().ImplementedBy().LifestylePerWebRequest(),
                Component.For().ImplementedBy().LifestylePerWebRequest(),
                Component.For().ImplementedBy().LifestylePerWebRequest());
        }
    }
}
ОБНОВЛЕНИЕ 4

Этот вопрос вероятно, слишком общий для SO, поэтому я разместил его наПрограммисты»

ОБНОВЛЕНИЕ 5

Примечание: согласноД.И. Шепот " (Mark Seemann), IDependencyResolver не следует использовать, поскольку в нем отсутствует метод Release (стр. 207 его книги)

Ответы на вопрос(3)

Ваш ответ на вопрос