ArgumentNullException in WindsorControllerActivator

时间:2016-10-20 20:10:26

标签: asp.net-mvc asp.net-web-api dependency-injection castle-windsor

I have a project with multiple layers(assemblies). I used Castle Windsor to solve Dependency Injection. Also create my controllers with castle. so I installed and used castle in Web API and WebUI Layers too. Beside I have a bootstrapper layer which registers all services and repositories.

First my web API:

In WebApiConfig.cs file, I registered UI Dependencies with flowing code:

public static void Register(HttpConfiguration config)
    {

        var corsAttr = new EnableCorsAttribute("*", "*", "*");
        config.EnableCors(corsAttr);

        // Web API configuration and services
        var container = Bootstrapper.WireUp();// to register services and repositories
        RegisterControllers(container);
        config.Services.Replace(typeof(IHttpControllerActivator), new WindsorControllerActivator(container));

    }

    private static void RegisterControllers(IWindsorContainer container)
    {
        //container.Register(Component.For<VisitorController>().LifestylePerWebRequest());
        //container.Register(Component.For<ValueController>().LifestylePerWebRequest());
        //container.Register(Component.For<ValidateController>().LifestylePerWebRequest());
        //container.Register(Component.For<CaptchaImageController>().LifestylePerWebRequest());
        container.Register(Classes.FromAssemblyContaining<VisitorController>()
            .BasedOn<ApiController>().LifestyleTransient());
    }

And activator factory is like this:

 public class WindsorControllerActivator : IHttpControllerActivator
{
    private readonly IWindsorContainer _container;
    public WindsorControllerActivator(IWindsorContainer container)
    {
        _container = container;
    }

    public IHttpController Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)
    {
        return (IHttpController)_container.Resolve(controllerType);//System.ArgumentNullException: Value cannot be null. error
    }
}

Also in WebUI project I used Castle Windsor to create my controllers. But when I run the project I get "System.ArgumentNullException: Value cannot be null." error when is resolving Controller.I mean in this line:

(IHttpController)_container.Resolve(controllerType);

I also tried "LifeStylePerWebRequest" for my controllers and nothing were changed.

Whats more, nothing is wrong with WireUp Method,(Registering service and repositories works fine). This problem is just for controllers(in WebUI and WebApi projects). Same problem happens for WebUI project.

1 个答案:

答案 0 :(得分:1)

我通常使用IDependencyResolver而不是IHttpControllerActivator的实现。你可以改用这种方法。添加floowing类:

public class WindsorDependencyResolver : IDependencyResolver
{
    readonly IWindsorContainer _container;

    public WindsorDependencyResolver(IWindsorContainer container)
    {
        if (container == null)
        {
            throw new ArgumentNullException(nameof(container));
        }

        _container = container;
    }

    public IDependencyScope BeginScope()
    {
        return new WindsorDependencyScope(this, _container.Release);
    }

    public void Dispose()
    {
    }

    public object GetService(Type t)
    {
        var ret = _container.Kernel.HasComponent(t) ? _container.Resolve(t) : null;
        return ret;
    }

    public IEnumerable<object> GetServices(Type t)
    {
        var ret = _container.ResolveAll(t).Cast<object>().ToArray();
        return ret;
    }
}

依赖项解析器需要此类:

public class WindsorDependencyScope : IDependencyScope
    {
        readonly List<object> _instances;
        readonly Action<object> _release;
        readonly IDependencyScope _scope;

        public WindsorDependencyScope(IDependencyScope scope, Action<object> release)
        {
            if (scope == null)
            {
                throw new ArgumentNullException(nameof(scope));
            }

            if (release == null)
            {
                throw new ArgumentNullException(nameof(release));
            }

            _scope = scope;
            _release = release;
            _instances = new List<object>();
        }

        public void Dispose()
        {
            foreach (object instance in _instances)
            {
                _release(instance);
            }

            _instances.Clear();
        }

        public object GetService(Type t)
        {
            var service = _scope.GetService(t);
            AddToScope(service);

            return service;
        }

        public IEnumerable<object> GetServices(Type t)
        {
            var services = _scope.GetServices(t);
            AddToScope(services);

            return services;
        }

        void AddToScope(params object[] services)
        {
            if (services.Any())
            {
                _instances.AddRange(services);
            }
        }
    }

这就是你在Register方法中注册依赖项解析器的方法:

config.DependencyResolver = new WindsorDependencyResolver(container);

我建议在生活方式瞬态注册你的控制器,因为依赖解析器负责处理它们。