Castle Windsor ApiController Фабричная реализация для ASP.NET Web API - PullRequest
8 голосов
/ 04 марта 2012

Я знаю, что можно использовать DependancyResolver и зарегистрировать Castle Windsor в MVC, но из-за проблем, описанных в https://stackoverflow.com/a/4889222/139392, мы остановились на методе реализации WindsorControllerFactory в наших проектах MVC.

Однако похоже, что ApiControllers используют какую-то другую фабрику, поскольку Castle Windsor не может внедрить зависимости.

Кто-нибудь выяснил, как использовать Castle Windsor с ASP.NET Web API и MVC без использования DependencyResolver?

Ответы [ 6 ]

7 голосов
/ 15 марта 2012

Благодаря посту Критиано и некоторому поиску в Интернете мне удалось заставить его работать, вот код для всех, у кого есть эта проблема. Я думаю, что он работает с MVC3 и ASP.NET Web Api Beta, но я думаю, что то же решение должно работать для MVC4.

Сначала я создал WindsorHttpControllerFactory, поскольку ApiControllers используют фабрику, отличную от MVC.

public class WindsorHttpControllerFactory : IHttpControllerFactory
{
    private readonly IKernel kernel;
    private readonly HttpConfiguration configuration;

    public WindsorHttpControllerFactory(IKernel kernel, HttpConfiguration configuration)
    {
        this.kernel = kernel;
        this.configuration = configuration;
    }

    public IHttpController CreateController(HttpControllerContext controllerContext, string controllerName)
    {
        if (controllerName == null)
        {
            throw new HttpException(404, string.Format("The controller for path '{0}' could not be found.", controllerContext.Request.RequestUri.AbsolutePath));
        }

        var controller = kernel.Resolve<IHttpController>(controllerName);
        controllerContext.Controller = controller;
        controllerContext.ControllerDescriptor = new HttpControllerDescriptor(configuration, controllerName, controller.GetType());

        return controllerContext.Controller;
    }

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

Хитрая часть была регистрация, которая, кажется, включала в себя регистрацию целого ряда других вещей. Это то, что я закончил.

container.Register(Component.For<IHttpControllerFactory>().ImplementedBy<WindsorHttpControllerFactory>().LifeStyle.Singleton);
container.Register(Component.For<System.Web.Http.Common.ILogger>().ImplementedBy<MyLogger>().LifeStyle.Singleton);
container.Register(Component.For<IFormatterSelector>().ImplementedBy<FormatterSelector>().LifeStyle.Singleton);
container.Register(Component.For<IHttpControllerActivator>().ImplementedBy<DefaultHttpControllerActivator>().LifeStyle.Transient);
container.Register(Component.For<IHttpActionSelector>().ImplementedBy<ApiControllerActionSelector>().LifeStyle.Transient);
container.Register(Component.For<IActionValueBinder>().ImplementedBy<DefaultActionValueBinder>().LifeStyle.Transient);
container.Register(Component.For<IHttpActionInvoker>().ImplementedBy<ApiControllerActionInvoker>().LifeStyle.Transient);
container.Register(Component.For<System.Web.Http.Metadata.ModelMetadataProvider>().ImplementedBy<System.Web.Http.Metadata.Providers.CachedDataAnnotationsModelMetadataProvider>().LifeStyle.Transient);
container.Register(Component.For<HttpConfiguration>().Instance(configuration));

//Register all api controllers
container.Register(AllTypes.FromAssembly(assemblyToRegister)
                            .BasedOn<IHttpController>()
                            .Configure(registration => registration.Named(registration.ServiceType.Name.ToLower().Replace("controller", "")).LifeStyle.Transient));

//Register WindsorHttpControllerFactory with Service resolver
GlobalConfiguration.Configuration.ServiceResolver.SetService(typeof(IHttpControllerFactory), container.Resolve<IHttpControllerFactory>());

Мне пришлось создать свою собственную реализацию ILogger, вы могли бы использовать версию-заглушку, как показано ниже.

* * 1010
2 голосов
/ 25 марта 2012

Я также столкнулся с этой проблемой два дня назад, и эта запись помогла мне.И не забудьте добавить контроллеры WebAPI в загрузчик Windsor.

container.Register(AllTypes.FromThisAssembly().BasedOn<IHttpController>().LifestyleTransient());

ОБНОВЛЕНИЕ для ASP.NET MVC 4 RC: этот полезный пост рассказывает, как использовать Windsor с WebAPIэто работает как шарм.

1 голос
/ 05 марта 2012

Посмотрите на это сообщение

Я еще не переключился на бета-версию mvc 4, включая web.api (я все еще использую веб-API WCF Prev6), но то, что было указано в теме, кажется, путь

0 голосов
/ 20 августа 2015
public class WindsorHttpControllerFactory : IHttpControllerActivator
    {
        readonly IWindsorContainer _container;

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

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

            request.RegisterForDispose(new Release(() => _container.Release(controller)));
            return controller;
        }

        class Release : IDisposable
        {
            readonly Action _release;

            public Release(Action release)
            {
                _release = release;
            }

            public void Dispose()
            {
                _release();
            }
        }
    }
0 голосов
/ 21 апреля 2012

Мне удалось разрешить из моего контейнера Виндзор, используя GlobalConfiguration.Configuration.ServiceResolver.SetResolver, как показано здесь .

Пример кода Виндзора

private void BootStrapWindsorContainer()
{
     _container = new WindsorContainer()
          .Install(FromAssembly.This());

     var controllerFactory = new WindsorControllerFactory(_container.Kernel);

     ControllerBuilder.Current.SetControllerFactory(controllerFactory);
     ServiceLocator.SetLocatorProvider(() => new WindsorServiceLocator(_container));
     GlobalConfiguration.Configuration.ServiceResolver.SetResolver(
         t =>
             {
                 try
                {
                    return _container.Resolve(t);
                }
                catch
                {
                    return null;
                }
            },
            t =>
            {
                try
                {
                    return _container.ResolveAll(t).OfType<object>();
                }
                catch
                {
             return new List<object>();
         }
    });
}

Возвращение нулевого значения, когда вы не можетеРазрешение типов работает, и кажется, что MVC обновит зависимости.

Редактировать: Убедитесь, что у вас есть установщик для IHttpController

0 голосов
/ 21 марта 2012

Я написал пост о том, как это сделать, и подключил его к RavenDB, который может оказаться полезным здесь

...