How to use the `Ninject.Extensions.Factory` to dynamically generate factories for internals classes? - ninject

I need to use the Ninject.Extensions.Factory to generate the constructor of internal classes. Follow one example:
using Ninject.Extensions.Conventions;
using Ninject.Modules;
using Ninject.Extensions.Factory;
namespace ClassLibrary
{
using System;
namespace ClassLibrary
{
internal class Class1
{
public void Print(string message)
{
Console.WriteLine(message);
}
}
internal interface IClass1Factory
{
Class1 Create();
}
public interface IInterface2
{
void PrintMessage();
}
internal class Class2 : IInterface2
{
private readonly IClass1Factory _class1Factory;
public Class2(IClass1Factory class1Factory)
{
_class1Factory = class1Factory;
}
public void PrintMessage()
{
Class1 class1 = _class1Factory.Create();
class1.Print("Class2's IInterface2 'PrintMessage' implementation.");
}
}
public class MyNinjectModule : NinjectModule
{
public override void Load()
{
Kernel.Bind(r => r
.FromThisAssembly()
.IncludingNonePublicTypes()
.SelectAllClasses()
.BindAllInterfaces());
Kernel.Bind<IClass1Factory>().ToFactory();
}
}
}
}
Application using the library:
using ClassLibrary.ClassLibrary;
using Ninject;
namespace ConsoleApplication3
{
class Program
{
static void Main(string[] args)
{
IKernel kernel = new StandardKernel();
kernel.Load<MyNinjectModule>();
IInterface2 interface2 = kernel.Get<IInterface2>();
interface2.PrintMessage();
}
}
}
Even after include [assembly: InternalsVisibleTo(InternalsVisible.ToDynamicProxyGenAssembly2)] I'm getting the following run tine error:
{"Type 'Castle.Proxies.IClass1FactoryProxy' from assembly
'DynamicProxyGenAssembly2, Version=0.0.0.0, Culture=neutral,
PublicKeyToken=null' is attempting to implement an inaccessible
interface.":""}
Any idea how to fix this?

Related

'Could not load type 'System.Runtime.Remoting.RemotingServices' from assembly 'mscorlib in Ninject

I have a problem as stated at the title. I am using Ninject as a Dependency Injection and my Service Locator as below:
internal class ServiceLocator
{
private static readonly IServiceLocator _serviceLocator;
static ServiceLocator()
{
_serviceLocator = new DefaultServiceLocator();
}
public static IServiceLocator Current
{
get
{
return _serviceLocator;
}
}
private class DefaultServiceLocator : IServiceLocator
{
private readonly IKernel kernel; // Ninject kernel
public DefaultServiceLocator()
{
kernel = new StandardKernel();
LoadBindings();
}
public T Get<T>()
{
try
{
return kernel.Get<T>();
}
catch (Exception hata)
{
throw hata;
}
}
private void LoadBindings()
{
kernel.Bind<IErrorDal>().To<ErrorDal>().InSingletonScope().WithConstructorArgument("connectionString", "myConnectionString");
kernel.Bind<IErrorBusinessRule>().To<ErrorBusinessRule>().InSingletonScope();
kernel.Bind<IApplicationBusinessRule>().To<ApplicationBusinessRule>().InSingletonScope();
kernel.Bind<ControlService>().To<ControlService>().InSingletonScope();
}
}
}
I have used ServiceLocator in my class ErrorService class as below:
public class ErrorService : IErrorService
{
private readonly IErrorBusinessRule _errorBusinessRule;
private readonly IApplicationBusinessRule _applicationBusinessRule;
private readonly ControlService _controlService;
public ErrorService()
{
//I am getting the error here.
this._errorBusinessRule = ServiceLocator.Current.Get<IErrorBusinessRule>();
this._controlService = ServiceLocator.Current.Get<ControlService>();
this._uygulamaIsKurali = ServiceLocator.Current.Get<IApplicationBusinessRule>();
}
}
I have got the System.TypeLoadException at the line
this._errorBusinessRule = ServiceLocator.Current.Get();
'Could not load type 'System.Runtime.Remoting.RemotingServices' from assembly 'mscorlib,
After investigation, I have pointed out that my test project type was MsTest Test Project. (.Net Core) When I choose unit test project (.NET Framework) the problem has solved.

Error activating service - Ninject

I am getting the following error whenever I try to inject one of my service's dependency into the MVC controller:
Error activating IFeedService No matching bindings are available, and the type is not self-bindable.
Activation path:
2) Injection of dependency IFeedService into parameter svc of constructor of type FeedController
1) Request for FeedController
Suggestions:
1) Ensure that you have defined a binding for IFeedService.
2) If the binding was defined in a module, ensure that the module has been loaded into the kernel.
3) Ensure you have not accidentally created more than one kernel.
4) If you are using constructor arguments, ensure that the parameter name matches the constructors parameter name.
5) If you are using automatic module loading, ensure the search path and filters are correct.
======================================================================
Here's how my code looks like:
ObjectFactory.cs
private static void RegisterServices(IKernel kernel)
{
// Contexts
kernel.Bind<IEntityObjectContext>().To<Entities>();
kernel.Bind<IAzureObjectContext>().To<AzureTableObjectContext>();
// Repositories
kernel.Bind<IEFRepository>().To<EFRepository>();
kernel.Bind<IAzureRepository>().To<AzureRepository>();
// Services
kernel.Bind<IFeedService>().To<FeedService>();
}
IEFRepository.cs
public interface IEFRepository : IDisposable
{
void SetContext(IEntityObjectContext context);
IQueryable<T> GetAll<T>() where T : class;
}
EFRepository.cs
public class EFRepository : IEFRepository
{
internal IEntityObjectContext context;
private Dictionary<Type, object> objectSets;
public EFRepository(IEntityObjectContext context)
{
this.context = context;
objectSets = new Dictionary<Type, object>();
}
public void SetContext(IEntityObjectContext context)
{
this.context = context;
}
}
IFeedService.cs
public interface IFeedService : IDisposable
{
IQueryable<FeedItem> GetPosts();
}
FeedService.cs
public class FeedService : IFeedService
{
private IEntityObjectContext _context;
private readonly IEFRepository _repo;
public FeedService(IEntityObjectContext context,
IEFRepository repo)
{
_context = context;
_repo = repo;
_repo.SetContext(_context);
}
public IQueryable<FeedItem> GetPosts()
{
using (_repo)
{
return _repo.GetAll<FeedItem>().Take(10);
}
}
}
FeedController.cs
public class FeedController : Controller
{
private readonly IFeedService _svc;
public FeedController(IFeedService svc)
{
_svc = svc;
}
}
As you can see, there are some nested dependency there in action. Not sure though, what needs to be added/removed for this bit to work.
Note: The error is thrown whenever I request the Feed/FetchFeed path. I also tried to comment out the FeedService's constructor portion to see if the nested dependencies are creating any problem, but again same error was thrown.
EDIT 1:
Rest of the code for the ObjectFactory.cs
class ObjectFactory
{
static ObjectFactory()
{
RegisterServices(kernel);
}
static IKernel kernel = new StandardKernel();
public static T GetInstance<T>()
{
return kernel.Get<T>();
}
private static void RegisterServices(IKernel kernel)
{
//...
}
}
EDIT 2:
I even tried to write a fairly basic service, but still the same error. Here's what I tried with:
public interface ITest
{
void CheckItOut();
}
public class Test : ITest
{
public void CheckItOut()
{
}
}
ObjectFactory.cs
kernel.Bind<ITest>().To<Test>();

Ninject issue with contextual binding and Lazy<T>

Ninject doesn't seem to correctly use WhenInjectedInto contstraint while also using Lazy<T>. Check the following example. The OnLandAttack and the OnLandAttackLazy should each be using the Samurai instance. But the Lazy<T> version ends up with the SpecialNinja instance. I'm guessing it's because it's not actually initialized in the contructor? But the type should still be correctly registered I would think. Am I missing something? FYI, this is using Ninject 3.2.2 and the Ninject.Extensions.Factory extension 3.2.1
class Program
{
static void Main(string[] args)
{
var kernel = new StandardKernel();
kernel.Load(new WarriorModule());
var amphibious = kernel.Get<IAttack>("amphibious");
amphibious.Execute();
var onLand = kernel.Get<IAttack>("onLand");
onLand.Execute();
var onLandLazy = kernel.Get<IAttack>("onLandLazy");
onLandLazy.Execute();
Console.ReadKey();
}
}
public class WarriorModule : NinjectModule
{
public override void Load()
{
Bind<IWarrior>().To<Samurai>().WhenInjectedInto<OnLandAttack>();
Bind<IWarrior>().To<Samurai>().WhenInjectedInto<OnLandAttackLazy>();
Bind<IWarrior>().To<SpecialNinja>(); // <-- for everything else
Bind<IAttack>().To<AmphibiousAttack>().Named("amphibious");
Bind<IAttack>().To<OnLandAttack>().Named("onLand");
Bind<IAttack>().To<OnLandAttackLazy>().Named("onLandLazy");
}
}
public interface IWarrior
{
void Attack();
}
public class Samurai : IWarrior
{
public void Attack()
{
Console.WriteLine("\tSamurai Attack");
}
}
public class SpecialNinja : IWarrior
{
public void Attack()
{
Console.WriteLine("\tSpecial Ninja Attack");
}
}
public interface IAttack
{
void Execute();
}
public class OnLandAttack : IAttack
{
private readonly IWarrior warrior;
public OnLandAttack(IWarrior warrior)
{
this.warrior = warrior;
}
public void Execute()
{
Console.WriteLine("Begin OnLand attack");
this.warrior.Attack();
}
}
public class OnLandAttackLazy : IAttack
{
private readonly Lazy<IWarrior> warrior;
public OnLandAttackLazy(Lazy<IWarrior> warrior)
{
this.warrior = warrior;
}
public void Execute()
{
Console.WriteLine("Begin OnLandLazy attack");
this.warrior.Value.Attack();
}
}
public class AmphibiousAttack : IAttack
{
private readonly IWarrior warrior;
public AmphibiousAttack(IWarrior warrior)
{
this.warrior = warrior;
}
public void Execute()
{
Console.WriteLine("Begin Amphibious attack");
this.warrior.Attack();
}
}

Constructor parameter for injected class

Let's say I would like to inject an implementation of this interface:
interface IService { ... }
implemented as:
class MyService : IService
{
public MyService(string s) { }
}
in an instance of this class:
class Target
{
[Inject]
public IService { private get; set; }
}
I do the injection by calling kernel.Inject(new Target()), but what if I would like to specify the parameter s of the constructor depending on some context when calling Inject?
Is there a way to achieve such context-dependant service initialization at injection?
Thanks!
In most cases you should not use Field Injection, it should be
used only in rare cases of circular dependencies.
You should only use the kernel once at the start of your
application and never again.
Example Code:
interface IService { ... }
class Service : IService
{
public Service(string s) { ... }
}
interface ITarget { ... }
class Target : ITarget
{
private IService _service;
public Target(IServiceFactory serviceFactory, string s)
{
_service = serviceFactory.Create(s);
}
}
interface ITargetFactory
{
ITarget Create(string s);
}
interface IServiceFactory
{
IService Create(string s);
}
class NinjectBindModule : NinjectModule
{
public NinjectBindModule()
{
Bind<ITarget>().To<Target>();
Bind<IService>().To<Service>();
Bind<ITargetFactory>().ToFactory().InSingletonScope();
Bind<IServiceFactory>().ToFactory().InSingletonScope();
}
}
Usage:
public class Program
{
public static void Main(string[] args)
{
IKernel kernel = new StandardKernel(new NinjectBindModule());
var targetFactory = kernel.Get<ITargetFactory>();
var target = targetFactory.Create("myString");
target.DoStuff();
}
}
Simply done using parameters...
kernel.Inject(new Target(), new ConstructorArgument("s", "someString", true));

Changing default object scope with Ninject 2.2

Is it possible to change the default object scope in Ninject 2.2? If so, how is it done?
As far as I can tell you could override AddBinding() on the BindingRoot (StandardKernel or NinjectModule) and modify the ScopeCallback property on the binding object.
public class CustomScopeKernel : StandardKernel
{
public CustomScopeKernel(params INinjectModule[] modules)
: base(modules)
{
}
public CustomScopeKernel(
INinjectSettings settings, params INinjectModule[] modules)
: base(settings, modules)
{
}
public override void AddBinding(IBinding binding)
{
// Set whatever scope you would like to have as the default.
binding.ScopeCallback = StandardScopeCallbacks.Singleton;
base.AddBinding(binding);
}
}
This test should now pass (using xUnit.net)
public class DefaultScopedService { }
[Fact]
public void Should_be_able_to_change_default_scope_by_overriding_add_binding()
{
var kernel = new CustomScopeKernel();
kernel.Bind<DefaultScopedService>().ToSelf();
var binding = kernel.GetBindings(typeof(DefaultScopedService)).First();
binding.ScopeCallback.ShouldBe(StandardScopeCallbacks.Singleton);
}
The CustomScopeKernel will also work with Ninject modules.
public class ServiceModule : NinjectModule
{
public override void Load()
{
Bind<DefaultScopedService>().ToSelf();
}
}
[Fact]
public void Should_be_able_to_change_default_scope_for_modules()
{
var module = new ServiceModule();
var kernel = new CustomScopeKernel(module);
var binding = kernel.GetBindings(typeof(DefaultScopedService)).First();
binding.ScopeCallback.ShouldBe(StandardScopeCallbacks.Singleton);
}