Ninject Factory Custom Instance Provider - ninject

I'm using the Ninject Factory Extension and creating a custom instance provider explained in the wiki:
class UseFirstArgumentAsNameInstanceProvider : StandardInstanceProvider
{
protected override string GetName(System.Reflection.MethodInfo methodInfo, object[] arguments)
{
return (string)arguments[0];
}
protected override Parameters.ConstructorArgument[] GetConstructorArguments(System.Reflection.MethodInfo methodInfo, object[] arguments)
{
return base.GetConstructorArguments(methodInfo, arguments).Skip(1).ToArray();
}
}
I've defined the following factory interface:
interface IFooFactory
{
IFoo NewFoo(string template);
}
I've created the following bindings:
kernel.Bind<IFooFactory>().ToFactory(() => new UseFirstArgumentAsNameInstanceProvider());
kernel.Bind<IFoo>().To<FooBar>().Named("Foo");
Now when I call the following I will get an instance of FooBar:
var foobar = fooFactory.NewFoo("Foo");
This all works great. What I would like however is something a little more like this:
interface IFooTemplateRepository
{
Template GetTemplate(string template);
}
I have a repository that will bring back a template based on the name ("Foo") and I want to pass the template as a constructor argument.
public class FooBar
{
public FooBar(Template template)
{
}
}
Is this possible? I'm not sure what should have the dependency on ITemplateRepository.

Don't use the IoC container to create instances of entities. This is business logic and therefore it does not belong in the composition root. The correct way to handle this is to use the ORM directly (e.g. with the repository pattern you are using).
var template = this.templateRepository.Get("SomeTemplate");
var fooBar = this.fooBarFactory.CreateFooBar(template);

Related

Repository pattern dependency injection using Dapper

My Startup.cs contains 40 repositories:
services.AddScoped<IUserRepository, UserRepository>();
services.AddScoped<IXRepository, XRepository>();
... 40 more lines ...
I'm trying to find a way to have this mess in a single line, but I'm failing miserably to put my head around this, I have several methods that are not available in the interface. Can someone provide some help? I understand why it is not working, it does not have a concrete repository, but I'm no closer to making this work.
InvalidOperationException: Unable to resolve service for type...
// IRepository.cs
public interface IRepository
{
}
// IUserRepository.cs
public interface IUserRepository : IRepository
{
User ReadToken(string email, string password);
}
// BaseRepository.cs
public class BaseRepository : IDisposable
{
protected IDbConnection PostgreSQL;
public BaseRepository(IDbConnection postgreSQL)
{
PostgreSQL = postgreSQL;
}
public void Dispose()
{
}
}
// UserRepository.cs
public class UserRepository : BaseRepository, IUserRepository
{
public UserRepository(IDbConnection postgreSQL) : base(postgreSQL)
{
}
public User ReadToken(string email, string password)
{
object parameters;
string sql;
parameters = new
{
email,
password
};
sql =
#"
SELECT
user_id AS id,
token
FROM users
WHERE
email = #email AND
password = CRYPT(#password, password) AND
active = TRUE;
";
var user = base.PostgreSQL.Query<User>(sql, parameters).SingleOrDefault();
if (user == null)
throw new UnauthorizedException("User", "User not found.");
return user;
}
}
// UsersController.cs
public class UsersController : ControllerBase
{
protected IUserRepository UserRepository;
public UsersController(IUserRepository userRepository)
{
UserRepository = userRepository;
}
}
// Startup.cs
services.AddTransient<IRepository, BaseRepository>();
You can do that with Scrutor
It offers assembly scanning and decoration extensions for Microsoft.Extensions.DependencyInjection
All those repositories can be summed up to something like this:
services.Scan(x => x.FromAssemblyOf<IAnAssemblyRegistrationMarker>()
.AddClasses(filter => filter.AssignableTo(typeof(IRepository)))
.AsImplementedInterfaces()
.WithScopedLifetime());
IAnAssemblyRegistrationMarker is an empty interface to point at the assembly (project) you want to scan
AddClasses Adds all public, non-abstract classes from the selected assemblies that matches the requirements specified in the
AsImplementedInterfaces Registers each matching concrete type as all of its implemented interfaces
WithScopedLifetime Registers each matching concrete type with Scoped Lifetime (You also have WithSingletonLifetime and WithTransientLifetime)
The only requirement in the code example above is that the repositories implement IRepository in order for you to target only the necessary items.
Disclaimer: I am not associated with Scrutor in any way. I just like the thing.
What you are looking for is called convention based registration. This gives you ability register all types which for example ends with Repository as the interfaces they implement. However the built-in ASP.NET Core IOC is very lightweight and doesn't provide such functionality. So you can either wrap it up with your code which scans all referenced assemblies, look for types by a pattern and then add them to ServiceCollection or you can use different IOC implementation that provides this functionality and supports .Net Core e.g. Autofac, StructureMap etc.

CastleWindsor BeginScope analog in Ninject

I am using Scoped lifestyle for some dependencies in code with CastleWindsor and resolving them in scope like this:
using (_container.BeginScope())
{
_implementation = _container.Resolve<IAbstration>();
}
Does Ninject have analogs of such behavior?
There is nothing built-in, but you can easily add this feature by creating a custom class that inherits from DisposableObject:
sealed class Scope : DisposableObject { }
You will have to store Scope instances on the active thread or async context, for instance using AsyncLocal<T>:
static readonly AsyncLocal<Scope> scopeProvider = new AsyncLocal<Scope>();
Now you can create your custom BeginScope() method that uses the scopeProvider as follows:
static Scope BeginScope() => scopeProvider.Value = new Scope();
Now you can implement your use case:
using (BeginScope())
{
_implementation = _kernel.Get<IAbstration>();
}
Registering scoped instances can be done using the InScope method:
static Scope RequestScope(IContext context) => scopeProvider.Value;
void Configure()
{
IKernelConfiguration config = new KernelConfiguration();
config.Bind<IUserService>().To<AspNetUserService>().InScope(RequestScope);
}

Why can't I use Get<ClassNameOfConcreteInstance> as a method name in Ninject Extension Factory?

Look at this very simple example: Calling CreateCar it works, calling GetCar it fails, saying "Error activating ICar: No matching bindings are available, and the type is not self-bindable".
public interface ICar { }
public class Car : ICar
{
public Car(string carType) { }
}
public interface ICarFactory
{
ICar CreateCar(string carType); // this is fine
ICar GetCar(string carType); // this is bad
}
public class CarModule : NinjectModule
{
public override void Load()
{
Bind<ICarFactory>().ToFactory();
Bind<ICar>().To<Car>();
}
}
public class Program
{
public static void Main()
{
using (var kernel = new StandardKernel(new FuncModule(), new CarModule()))
{
var factory = kernel.Get<ICarFactory>();
var car1 = factory.CreateCar("a type");
var car2 = factory.GetCar("another type");
}
}
}
Is assume it must be related to some kind of convention with Get*ClassName* (something like the NamedLikeFactoryMethod stuff). Is there any way to avoid this convention to be applied? I don't need it and I don't want it (I already wasted too much time trying to figure out why the binding was failing, it was just luck that I made a typo in 1 of my 10 factories and I noticed it to work just because the factory method name was "Ger" instead of "Get").
Thanks!
Yes, there is a convention, where the Get is used to obtain instances using a named binding. The factory extension generates code for you so you don't have to create boilerplate code for factories. You don't need to use it, if you don't want to.
But if you do, you are bound to its conventions. Use Create to build instances and Get to retrieve instances via a named binding.
All this is documented in the wiki.

Singleton with StructureMap custom convention in ASP.NET MVC 4

I am having an issue trying to get the singleton lifecycle to work with a custom convention in StructureMap.
Basically I have a custom registry type class that contains a dictionary that I would like to be a singleton so that it is created once at startup of the application.
I created a custom convention that will look at an attribute of a class and determine whether or not the class should be HttpContextScoped or Singleton.
The problem is that when I run the application with the Visual Studio debugger the constructor of the object that should be a singleton gets called every time the web page is loaded instead of happening once as I expected. It looks like the object is behaving as a HttpContextScoped instead of a Singleton.
Here are some details:
StructuremapMvc class in app_start folder
public static class StructuremapMvc
{
public static void Start()
{
IContainer container = IoC.Initialize();
DependencyResolver.SetResolver(new StructureMapDependencyResolver(container));
GlobalConfiguration.Configuration.DependencyResolver = new StructureMapDependencyResolver(container);
}
}
Ioc class
public static IContainer Initialize()
ObjectFactory.Initialize(x =>
{
x.Scan(scan =>
{
scan.TheCallingAssembly();
scan.AssemblyContainingType<IConfigManager>();
scan.WithDefaultConventions();
scan.Convention<CustomConvention>();
});
CustomConvention : IRegistrationConvention
public void Process(Type type, Registry registry) public void Process(Type type, Registry registry)
{
var attributes = type.GetCustomAttributes(false);
if (attributes.Length > 0)
{
if (attributes[0] is SingletonAttribute)
{
registry.For(type).Singleton();
}
else if (attributes[0] is HttpContextScopedAttribute)
{
registry.For(type).HttpContextScoped();
}
}
}
[Singleton]
public class MyRegistry : IMyRegistry
This questions seems to be quite old but I'll trie to answer it anyway because there could be others which are experiencing the same problem with Structure map. In some cases singleton insances are created "per instance" referring to the instance where they are injected in. This means that you could have different instances of "singleton" when they are injected somewhere else. I've personally seen this behavior with WEBAPI inside MVC app.
The only way I could make it work as "true" global singleton is by using generic interface with specific type parameters to distinguish different types to be used:
public interface ITest<T>
{
}
public class Test1 : ITest<int>
{
}
public class Test2 : ITest<string>
{
}
Scan(x =>
{
x.TheCallingAssembly();
x.IncludeNamespace("MvcApplication1");
x.ConnectImplementationsToTypesClosing(typeof(ITest<>))
.OnAddedPluginTypes(a => a.LifecycleIs(InstanceScope.Singleton));
});
I know that this isn't as ellegant nor usable as approach described above but at least it works as expected. Other approach which works is to do standard mapping one-on-one like:
For<ISingleton>().Singleton().Use<Singleton>();

Ninject property binding, how to do correctly

I have installed Ninject (v4.0.30319) package in test project to test. Create test code below, unfortunately ValidateAbuse.Instance.Repository is always Null. Why Ninject do not bind repository to ValidateAbuse.Repository property?
Some of you may suggest to use constructor binding but I can't use it due to code structure. The below code is just example and I need to find a way to bind to property.
Test method which always fail
[TestMethod]
public void PropertyInjection()
{
using (IKernel kernel = new StandardKernel())
{
kernel.Bind<ISettingsRepository>().To<SettingsRepository>();
Assert.IsNotNull(ValidateAbuse.Instance.Repository);
}
}
The repository interface
public interface ISettingsRepository
{
List<string> GetIpAbuseList();
List<string> GetSourceAbuseList();
}
The repository implementation
public class SettingsRepository : ISettingsRepository
{
public List<string> GetIpAbuseList()
{
return DataAccess.Instance.Abuses.Where(p => p.TypeId == 1).Select(p => p.Source).ToList();
}
public List<string> GetSourceAbuseList()
{
return DataAccess.Instance.Abuses.Where(p => p.TypeId == 2).Select(p => p.Source).ToList();
}
}
The class to which I am trying to bind repository
public class ValidateAbuse
{
[Inject]
public ISettingsRepository Repository { get; set; }
public static ValidateAbuse Instance = new ValidateAbuse();
}
Ninject will only bind properties on an object when it creates an instance of that object. Since you are creating the instance of ValidateAbuse rather than Ninject creating it, it won't know anything about it and therefore be unable to set the property values upon creation.
EDIT:
You should remove the static singleton from ValidateAbuse and allow Ninject to manage it as a singleton.
kernel.Bind<ValidateAbuse>().ToSelf().InSingletonScope();
Then when you ask Ninject to create any class that needs an instance of ValidateAbuse, it will always get the same instance.
It seems like you don't fully understand how Ninject works or how to implement it so I would suggest you read the wiki https://github.com/ninject/ninject/wiki/How-Injection-Works and follow some more basic examples before trying to wire it into an existing application.