Ninject выдает исключение активации в проекте WebApi с несколькими сборками

Мой проект asp.net WebApi состоит из нескольких сборок для служб, ядра и доступа к данным. Пытаясь использовать Ninject в качестве контейнера DI в проекте, я добавил пакет Ninject.Web.Common из NuGet. Затем я реализовал IDependencyResolver как:

public class NinjectDependencyResolver : NinjectDependencyScope, IDependencyResolver
{
    readonly IKernel kernel;

    public NinjectDependencyResolver(IKernel kernel) : base(kernel)
    {
        this.kernel = kernel;
    }

    public IDependencyScope BeginScope()
    {
        return new NinjectDependencyScope(this.kernel.BeginBlock());
    }
}

public class NinjectDependencyScope : IDependencyScope
{
    IResolutionRoot resolver;

    public NinjectDependencyScope(IResolutionRoot resolver)
    {
        this.resolver = resolver;
    }

    public object GetService(System.Type serviceType)
    {
        if (resolver == null)
            throw new ObjectDisposedException("this", "This scope has been disposed");

        var resolved = this.resolver.Get(serviceType);
        return resolved;
    }

    public System.Collections.Generic.IEnumerable<object> GetServices(System.Type serviceType)
    {
        if (resolver == null)
            throw new ObjectDisposedException("this", "This scope has been disposed");

        return this.resolver.GetAll(serviceType);
    }

    public void Dispose()
    {
        IDisposable disposable = resolver as IDisposable;
        if (disposable != null)
            disposable.Dispose();

        resolver = null;
    }
}

Вот мой Ninject.Web.Common.cs.

public static class NinjectWebCommon 
{
    private static readonly Bootstrapper bootstrapper = new Bootstrapper();

    /// <summary>
    /// Starts the application
    /// </summary>
    public static void Start() 
    {
        DynamicModuleUtility.RegisterModule(typeof(OnePerRequestHttpModule));
        DynamicModuleUtility.RegisterModule(typeof(NinjectHttpModule));
        bootstrapper.Initialize(CreateKernel);
    }

    /// <summary>
    /// Stops the application.
    /// </summary>
    public static void Stop()
    {
        bootstrapper.ShutDown();
    }

    /// <summary>
    /// Creates the kernel that will manage your application.
    /// </summary>
    /// <returns>The created kernel.</returns>
    private static IKernel CreateKernel()
    {
        var kernel = new StandardKernel();
        kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
        kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();
        RegisterServices(kernel);

        GlobalConfiguration.Configuration.DependencyResolver = new NinjectDependencyResolver(kernel);
        return kernel;
    }

    /// <summary>
    /// Load your modules or register your services here!
    /// </summary>
    /// <param name="kernel">The kernel.</param>
    private static void RegisterServices(IKernel kernel)
    {
        kernel.Bind(x =>
            x.FromAssembliesInPath(AppDomain.CurrentDomain.RelativeSearchPath)
            .SelectAllIncludingAbstractClasses()
            .BindDefaultInterface()
            .Configure(config => config.InSingletonScope()));

        //kernel.Bind(x => 
        //    {
        //        x.FromAssembliesMatching("*")
        //        .SelectAllClasses()
        //        .BindDefaultInterface()
        //        .Configure(b => b.InTransientScope());
        //    });
        //kernel.Load()
        //kernel.Bind<ISecurityService>().To<SecurityServiceImplementation>();

        //kernel.Bind(x => x
        //    .FromAssembliesMatching("*")
        //    .SelectAllClasses()
        //    .BindDefaultInterface());
        //.Configure(b => b.InTransientScope()));
        //kernel.Load("*.dll");
    }        
}

исключение

[ActivationException: Error activating IHostBufferPolicySelector
No matching bindings are available, and the type is not self-bindable.
Activation path:
1) Request for IHostBufferPolicySelector

Я использовал различные регистрации (закомментированные), но ни одна из них не работает. Сработала точка останова в методе NinjectWebCommon.cs -> CreateKernel(), а также точка останова в методе GetService(System.Type serviceType). AppDomain.CurrentDomain.RelativeSearchPath разрешается в каталог bin приложения и содержит все библиотеки DLL, включая System.Web.Http.dll, который содержит тип IHostBufferPolicySelector.

Как я могу правильно использовать Ninject.Extensions.Conventions для настройки ядра для разрешения типов?


person Umair Ishaq    schedule 12.11.2012    source источник


Ответы (3)


Из подсказок в ответе Ремо и комментария Филипа, а также значительного количества времени на отладку, я обнаружил, что использование this.resolver.Get(serviceType) вместо this.resolver.TryGet(serviceType) в реализации GetService() было виновником моей ситуации.

Я планирую написать об этом подробный пост в блоге, но суть в том, что когда NinjectDependencyResolver подключен к MVC с помощью строки: GlobalConfiguration.Configuration.DependencyResolver = new NinjectDependencyResolver(kernel);, и мы не определяем привязки зависимостей на уровне Framework (например, IHostBufferPolicySelector и т. д.), возникает исключение метод Get() для некоторых зависимостей уровня фреймворка, если они не разрешены через Ninject. Использование TryGet() не вызывает исключения, и платформа возвращается к зависимостям по умолчанию для неразрешенных (также известных как нулевые) зависимостей, таких как IHostBufferPolicySelector. Итак, варианты

  1. Используйте метод TryGet() для разрешения зависимостей.
  2. Оберните Get в Try/Catch и отбросьте исключение.
person Umair Ishaq    schedule 14.11.2012

Попробуйте этот пост. Вместо перехвата исключения Ninject перехватывайте исключение для всех вызовов WebApi. http://blog.greatrexpectations.com/2013/05/15/exception-handling-for-web-api-controller-constructors/ В трассировке стека будет виден конструктор, в котором произошло исключение.

person user2668218    schedule 09.08.2013

Не существует класса HostBufferPolicySelector, поэтому нет класса, для которого IHostBufferPolicySelector является интерфейсом по умолчанию. Вы можете попробовать BindAllInterfaces или BindDefaultInterfaces.

person Remo Gloor    schedule 12.11.2012
comment
Ремо, спасибо за ваше предложение. Когда я изменяю BindDefaultInterface на BindDefaultInterfaces, я получаю следующее: В mscorlib.dll возникло необработанное исключение типа «System.StackOverflowException». Есть идеи? - person Umair Ishaq; 12.11.2012
comment
На самом деле вы должны более точно определить свои соглашения. Такие соглашения, как все классы из всех сборок, включая все сборки System, очень непредсказуемы. Подумайте о том, какие соглашения у вас есть для ваших классов, и определите их с помощью синтаксиса соглашения. Классы, к которым не применяются соглашения, по-прежнему могут быть связаны сами по себе с помощью единого синтаксиса привязки службы. - person Remo Gloor; 12.11.2012
comment
Римо, я могу сделать это для своих сборок и сделаю это. Однако я не уверен, как указать привязки уровня фреймворка (asp.net, mvc, webapi), такие как IHostBufferPolicySelector? Есть ли способ автоматически связать привязки System/Framework? - person Umair Ishaq; 12.11.2012
comment
Реализация по умолчанию для IHostBufferPolicySelector — это WebHostBufferPolicySelector (а не HostBufferPolicySelector), поэтому Ninject не может найти его самостоятельно. Однако, как сказал Ремо - зачем вам связывать системные сборки? Web API может позаботиться о своих собственных зависимостях, и у вас нет причин вмешиваться в них, поэтому я бы определенно избегал универсальной привязки всех классов из всех сборок. - person Filip W; 12.11.2012
comment
Филипп, спасибо за внимание. Я должен упустить что-то действительно очевидное здесь, но когда я заменяю преобразователь зависимостей по умолчанию, используя: GlobalConfiguration.Configuration.DependencyResolver = new NinjectDependencyResolver(kernel); Как WebApi разрешит свои зависимости без указания каких-либо привязок? - person Umair Ishaq; 12.11.2012
comment
Кроме того, я изменил спецификацию привязки к этому kernel.Bind(x => x.FromAssembliesMatching("WebApiTest.*.dll") .SelectAllClasses() .BindAllInterfaces() .Configure(config => config.InTransientScope()));, и он выдает исключение для IHostBufferPolicySelector. Мое намерение состоит в том, чтобы просто внедрить мои зависимости, а не зависимости от фреймворка. Спасибо за вашу помощь. - person Umair Ishaq; 12.11.2012