Pregunta

I have an ASP.NET MVC application, which uses Windsor for dependency injection.

Now, I have started to build an API inside the application under /controllers/api .

In my first API controller, I need access to some services from my domain project, which is added by Windsor. This works perfectly for normal controllers. However, whwen I for instance access /api/officeproduct/gettest , I get the following error:

This XML file does not appear to have any style information associated with it. The document tree is shown below.
<Error>
<script id="tinyhippos-injected"/>
<Message>An error has occurred.</Message>
<ExceptionMessage>
Type 'LetterAmazer.Websites.Client.Controllers.Api.OfficeProductController' does not have a default constructor
</ExceptionMessage>
<ExceptionType>System.ArgumentException</ExceptionType>
<StackTrace>
at System.Linq.Expressions.Expression.New(Type type) at System.Web.Http.Internal.TypeActivator.Create[TBase](Type instanceType) at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.GetInstanceOrActivator(HttpRequestMessage request, Type controllerType, Func`1& activator) at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)
</StackTrace>
</Error>

I really don't know how to fix it, despite using a lot of time so way. Any ideas how to get it to work?

My API controller:

  public class OfficeProductController : ApiController
    {
        private IOfficeProductService officeProductService;
        public OfficeProductController(IOfficeProductService officeProductService)
        {
            this.officeProductService = officeProductService;
        }

        [System.Web.Http.HttpPost]
        public ActionResult Create(OfficeProductViewModel model)
        {
            var officeProduct = new OfficeProduct()
            {
                CountryId = 1,
                ProductScope = ProductScope.Single,
                LetterDetails = new LetterDetails()
                {
                    LetterColor = LetterColor.BlackWhite,
                    LetterPaperWeight = LetterPaperWeight.Eight,
                    LetterProcessing = LetterProcessing.Dull,
                    LetterSize = LetterSize.A4,
                    LetterType = LetterType.Pres
                },
                OfficeId = 1
            };

            officeProductService.Create(officeProduct);

            return new JsonResult();
        }

        [System.Web.Http.HttpPost]
        public ActionResult Test(string id)
        {
            return new ContentResult() { Content = id };
        }

        [System.Web.Http.HttpGet]
        public ActionResult Gettest()
        {
            return new ContentResult() {Content ="hej"};
        }
    }

Web API registration:

 public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );
        }
    }

Global.asax:

public class MvcApplication : System.Web.HttpApplication, IContainerAccessor
    {
        protected void Application_Start()
        {
            log4net.Config.XmlConfigurator.Configure();

            InitializeContainer();

            AreaRegistration.RegisterAllAreas();

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

        private void InitializeContainer()
        {
            var oldProvider = FilterProviders.Providers.Single(f => f is FilterAttributeFilterProvider);
            FilterProviders.Providers.Remove(oldProvider);

            Container.Register(Component.For<IWindsorContainer>().Instance(this.Container));
            Container.Install(new BootstrapInstaller());

            registerCustom();

            Container.Install(new WebWindsorInstaller());

            var provider = new WindsorFilterAttributeFilterProvider(this.Container);
            FilterProviders.Providers.Add(provider);

            DependencyResolver.SetResolver(new WindsorDependencyResolver(ServiceFactory.Container));
        }

        private void registerCustom()
        {
            // All services in service DLL
            var assembly = Assembly.LoadFrom(Server.MapPath("~/bin/LetterAmazer.Business.Services.dll"));
            ;
            Container.Register(
                Classes.FromAssembly(assembly)
                    .InNamespace("LetterAmazer.Business.Services.Services")
                    .WithServiceAllInterfaces());

            Container.Register(
                Classes.FromAssembly(assembly)
                    .InNamespace("LetterAmazer.Business.Services.Services.FulfillmentJobs")
                    .WithServiceAllInterfaces());

            Container.Register(
                Classes.FromAssembly(assembly)
                    .InNamespace("LetterAmazer.Business.Services.Services.PaymentMethods.Implementations")
                    .WithServiceAllInterfaces());



            // All factories in service DLL
            Container.Register(
                Classes.FromAssembly(assembly)
                    .InNamespace("LetterAmazer.Business.Services.Factory")
                    .WithServiceAllInterfaces());


            Container.Register(Component.For<LetterAmazerEntities>());
        }

        public IWindsorContainer Container
        {
            get { return ServiceFactory.Container; }
        }
    }

Windsor - dependency resolver:

/// <summary>
    /// Reference: http://stackoverflow.com/questions/4140860/castle-windsor-dependency-resolver-for-mvc-3
    /// </summary>
    public class WindsorDependencyResolver : IDependencyResolver
    {
        private readonly IWindsorContainer container = null;

        /// <summary>
        /// 
        /// </summary>
        /// <param name="container"></param>
        public WindsorDependencyResolver(IWindsorContainer container)
        {
            this.container = container;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="serviceType"></param>
        /// <returns></returns>
        public object GetService(Type serviceType)
        {
            return container.Kernel.HasComponent(serviceType) ? container.Resolve(serviceType) : null;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="serviceType"></param>
        /// <returns></returns>
        public IEnumerable<object> GetServices(Type serviceType)
        {
            return container.Kernel.HasComponent(serviceType) ? container.ResolveAll(serviceType).Cast<object>() : new object[] {};
        }
    }

Windsor - controller factory

/// <summary>
    /// Controller Factory class for instantiating controllers using the Windsor IoC container.
    /// </summary>
    public class WindsorControllerFactory : DefaultControllerFactory
    {
        private static readonly ILog logger = LogManager.GetLogger(typeof(WindsorControllerFactory));
        private readonly IWindsorContainer container = null;

        /// <summary>
        /// 
        /// </summary>
        /// <param name="container"></param>
        public WindsorControllerFactory(IWindsorContainer container)
        {
            if (container == null)
            {
                throw new ArgumentNullException("container");
            }
            this.container = container;
        }

        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 or it does not implement IController.",
                    requestContext.HttpContext.Request.Path));
            }

            IController controller = (IController)container.Resolve(controllerType);
            return controller;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="controller"></param>
        public override void ReleaseController(IController controller)
        {
            var disposable = controller as IDisposable;

            if (disposable != null)
            {
                disposable.Dispose();
            }

            container.Release(controller);
        }
¿Fue útil?

Solución

You need to create a class that implements IHttpControllerActivator then register it when you initialize the container.

WindsorHttpControllerActivator

public class WindsorHttpControllerActivator : IHttpControllerActivator
{
    private readonly IWindsorContainer _container;
    public WindsorHttpControllerActivator(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;
    }

    private class Release : IDisposable
    {
        private readonly Action _release;

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

        public void Dispose()
        {
            _release();
        }
    }
}

Register HttpControllerActivator

   private void InitializeContainer()
    {
        var oldProvider = FilterProviders.Providers.Single(f => f is FilterAttributeFilterProvider);
        FilterProviders.Providers.Remove(oldProvider);

        Container.Register(Component.For<IWindsorContainer>().Instance(this.Container));
        Container.Install(new BootstrapInstaller());

        registerCustom();

        Container.Install(new WebWindsorInstaller());

        var provider = new WindsorFilterAttributeFilterProvider(this.Container);
        FilterProviders.Providers.Add(provider);

        DependencyResolver.SetResolver(new WindsorDependencyResolver(ServiceFactory.Container));

        // register WebApi controllers
        GlobalConfiguration.Configuration.Services.Replace(typeof(IHttpControllerActivator), new WindsorHttpControllerActivator(ServiceFactory.Container));
    }
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top