Dependency Injection

 

Scenario:

Handle class dependencies in project.

Solution:

Inject Dependencies using Ninject framework.

  1. It solves dependency resolver & testability (DI pattern) using containers ( Inversion of Control - Giving responsibility of instantiation of class from one actor to other in this case DI container) and makes applications loosely coupled.
  2. Using DI you can inject different classes in the main project and different like mock in Rest projects as for Unit testing you need to isolate the units to test.
  3. This means that control is now inverted; instead of given class deciding which implementation to use, the calling code does.
  4. There are different DI containers like Ninject, AutoFac, Unity etc. : In case of Ninject, each assembly has a Ninject Module class which registers the available interface-to-implementation bindings. 
      public class Bindings : NinjectModule
      	{
      		 public override void Load()
      		 {
      			 Bind<IMailSender>().To<MailSender>();
      			 Bind<IMailSender>().To<MockMailSender>();
      		 }
      	}
        5. In Program.cs
      var kernel = new AspNetCoreKernel(settings,
      	    new NinjectModule());
      
      
      kernel.Load(typeof(AspNetCoreHostConfiguration).Assembly);
      
      
      var serviceProviderFactory = new NinjectServiceProviderFactory(kernel);
      
      
      var startup = new Startup(serviceProviderFactory);
      
      
      startup.ConfigureServices(builder.Services);
        6. One of the common way is to use  Constructor injection and procedural registration (i.e. through                 code, other way is config). Ninject does not need to register Concrete  classes (without interface),             some  other DI  do. If the. If the is nested dependency, it first instantiates the inner most objects                 and then keeps coming back till it has 
        7. Singleton scope
    • Bind<ILogger>().To<Log4netLogger>().InSingletonScope();
    • If we want to change the dependecy based on web.config:
      • Bind<ICache>().To<MemoryCache>().InSingletonScope().WithMetadata("Cache", typeof(MemoryCache).FullName);
      • Bind<ICache>().To<RedisCache>().InSingletonScope().WithMetadata("Cache", typeof(RedisCache).FullName);
      •  Test project  Web.config - <appSettings file="user.appSettings.config">
      •   <add key="Cache" value="MemoryCache" />
      •  Web Web.config - <appSettings file="user.appSettings.config">
      •  <add key="Cache" value="RedisCache" />
      • The controller would look like:
                      public  AuthService( [AppSettingsBinding(Name = "Cache")]     ICache cache)
                    {
       cache…
                  }
      • To use without constructor injection:
        • private readonly IKernel _kernel;
        • var logger = _kernel.Get(type) --type = ILogger
8. Self Binding scope
    1. The ToSelf() binding is equivalent to Bind<Foo>().To<Foo>().
    2. Bind<MapperUtils>().ToSelf().InSingletonScope();
    3. Good for:
      • Caching service
      • Global Configurations
      • Business rules
      • Http Client
        9. Transient scope
    1. New instance is created for each request..
    2.  Bind(typeof(IDataRepo<>)).To(typeof(AdoRepo<>)).InTransientScope().Named("AdoRepo");
    3. Transient for services depends on the service, you don't want your Memory Cache to be transient, otherwise it will get wiped after you are finished using it.
    4. Good for:
      • Database Access
      • File Access
      • Services that should dispose of their state
     10. InRequest scope
    1. New instance is created for each HttpContext. 
    2. Database Context opens a connection which you don't want to persist if there is no data  going over the wire. Make this Scoped incase many services use the context at the same time, you don't have to re-open the connection.
    3. If we use transient scoped dependency for DbContext then it passed to 2 different services would be distinct references. This leads to problems where Service A calls another service to retrieve entities that it wants to associate with an entity it loaded and is trying to update. These entities are associated to a different DbContext resulting in errors or issues like duplicate data being created.
    4. Making your DbContext a Singleton and reusing it throughout the application can cause problems like concurrency and memory leak issues.
    5. For Web apps bind both context and repository in the scope of an HttpRequest. This means that only the current request thread will be able to save changes..
    6. Good for:
      • Persist state through the request.
      11. ToMethod 
    1. When a class implements 2 or more interfaces
      Bind<ScheduleService>().ToSelf().InSingletonScope();
      Bind<IScheduleService>().ToMethod(ctx => ctx.Kernel.Get<ScheduleService>()).InSingletonScope();
      Bind<IJobService>().ToMethod(ctx => ctx.Kernel.Get<ScheduleService>()).InSingleton();

No comments:

Post a Comment

Move Github Sub Repository back to main repo

 -- delete .gitmodules git rm --cached MyProject/Core git commit -m 'Remove myproject_core submodule' rm -rf MyProject/Core git remo...