A simple Dependency Injection Container for Delphi

Delphi 2010, Delphi Dependency Injection, Design Patterns Add comments

As wikipedia says:

“Dependency injection (DI) in computer programming refers to the process of supplying an external dependency to a software component. It is a specific form of inversion of control where the concern being inverted is the process of obtaining the needed dependency. The term was first coined by Martin Fowler to describe the mechanism more clearly.

Many of us have already read this historical article from Martin Fowler about dependency injection pattern, but actually there isn’t a real framework for implement dependency injection in Delphi.

There are already the following implementation for DI in Delphi

  • Emballo (work with pre-D2010 too, but the implementation require changes in the service classes. I really hate it)
  • Delphi Spring Framework (very nice, but still not realeased)

So, I decided to write my own simple DI framework.

You can find the code at google code project here: http://code.google.com/p/delphidicontainer/

This is the first public version and come with sample, documentation and unit tests.

Folow some sample code.

  1. program Test01;
  2. {$APPTYPE CONSOLE}
  3.  
  4. uses
  5.   SysUtils,
  6.   DIContainer in '..\..\src\DIContainer.pas',
  7.   ServiceTestObjectsU in '..\..\UnitTest\ServiceTestObjectsU.pas';
  8.  
  9. var
  10.   DIContainer: TDIContainer;
  11.   s1: TService1;
  12.   s2: TService2;
  13.   s3: TService3;
  14.   s6: TService6;
  15.   s7: TService7;
  16. begin
  17.   try
  18.     DIContainer := TDIContainer.Create;
  19.     try
  20.       // AddComponent with TClass with and   InitType = Singleton
  21.       DIContainer.AddComponent(TService1, TDIContainerInitType.Singleton);
  22.       // AddComponent with QualifiedName and InitType = Singleton
  23.       DIContainer.AddComponent('ServiceTestObjectsU.TService2',
  24.         TDIContainerInitType.Singleton);
  25.       // AddComponent with QualifiedName and InitType = CreateNewInstance
  26.       DIContainer.AddComponent('ServiceTestObjectsU.TService3',
  27.         TDIContainerInitType.CreateNewInstance);
  28.  
  29.       // GetComponent with QualifiedName
  30.       s1 := DIContainer.GetComponent('ServiceTestObjectsU.TService1')
  31.         as TService1;
  32.       s1.Message := 'I''m the first message';
  33.       WriteLn(s1.Message);
  34.  
  35.       // GetComponent with TClass
  36.       s2 := DIContainer.GetComponent(TService2) as TService2;
  37.       s2.Message := 'I''m the second message';
  38.       WriteLn(s2.Message);
  39.  
  40.       // GetComponent with a dependent service (TService3 depends upon TService1 and TService2)
  41.       s3 := DIContainer.GetComponent('ServiceTestObjectsU.TService3')
  42.         as TService3;
  43.       WriteLn(s3.GetCompoundMessage);
  44.       // s3 is not created as Singleton, so after use it I must free it
  45.       s3.Free;
  46.  
  47.       // AddComponent with QualifiedClassName, a custom initializer, an alias.
  48.       // Component will be created as singleton (single instance managed by Container)
  49.  
  50.       DIContainer.AddComponent(DIContainerUtils.GetQualifiedClassName
  51.           (TService6),
  52.           function: TObject
  53.           begin
  54.             Result := TService6.Create(DIContainer.Get(TService1) as TService1,DIContainer.Get(TService1) as TService1);
  55.           end,
  56.           'srv6',
  57.         TDIContainerInitType.Singleton);
  58.  
  59.       s6 := DIContainer.Get('srv6') as TService6;
  60.       WriteLn(s6.ToString);
  61.       s6 := DIContainer.Get('srv6') as TService6;
  62.       WriteLn(s6.ToString);
  63.  
  64.       // AddComponent with QualifiedClassName, a custom initializer, an alias.
  65.       // Component will be created as singleton (single instance managed by Container)
  66.       DIContainer.AddComponent(DIContainerUtils.GetQualifiedClassName
  67.           (TService7),
  68.             function: TObject
  69.             begin
  70.               Result := TService7.Create(DIContainer.Get(TService1) as TService1,DIContainer.Get(TService1) as TService1);
  71.             end,
  72.             'srv7intf',
  73.           TDIContainerInitType.Singleton);
  74.  
  75.       s7 := DIContainer.Get('srv7intf') as TService7;
  76.       WriteLn(s7.ToString);
  77.     finally
  78.       DIContainer.Free;
  79.     end;
  80.   except
  81.     on E: Exception do
  82.       WriteLn(E.ClassName, E.Message);
  83.   end;
  84.   readln;
  85. end.

DelphiDIContainer also handle constructor injection with automatic dependency resolution for service.

Enjoy and stay tuned.

10 Responses to “A simple Dependency Injection Container for Delphi”

  1. Paul Says:

    Thanks, Daniele.
    It seems that your implementation will satisfy the basic requirements.

    Since this project is created based on the Delphi 2010 platform. It’ll be great if you consider support for Generics/Attributes which is more natural.

    btw. We’re preparing for the first public release of the Delphi Spring Framework. You’re welcome to give any feedback :)

  2. devsmt Says:

    very interesting, i’m not using delphi a lot today but I was looking at a DIC at the time.
    is it possible to port this to freepascal?
    thanks

  3. Daniele Teti Says:

    @paul:
    Sure I’m planed to support generics and attributes.
    Thanks for the tip

    @devsmt:
    delphidicontainer use a lot the new RTTI. I dont know how RICH is the freepascal RTTI. If you want to try I can help you.

  4. Magno Machado Says:

    Hi, Daniele. I’m the creator of Emballo..
    I’ve recreated it from scratch, now based on D2010 (older Delphi versions won’t be supported) and I’m already using it on an a commercial product I’m developing.
    It isn’t available for public now, but I plan to release this new version on Google Code in a couple of days.
    Could you tell me what didn’t you like on it? I’d be pleased to get your suggestions

  5. Daniele Teti Says:

    @Magno Machado
    I’m looking for new version of Emballo.
    The last version doesn’t support DI with contructor injection (delphidicontainer support only this kind of injection) and require a change in the service constructor.
    Thanks for your work.

  6. Magno Machado Says:

    This is because of the poor reflection capabilities of delphi pre-2010, but the new version does support constructor injection pretty well… I think you’ll like it :)

    As soon as I release it, I’ll leave a notice here

  7. Magno Machado Says:

    I’m glad to announce that I’ve just checked in the new version of Emballo.
    The main improvements are the constructor injection, and the ability to manually ask the framework for an instance of a specific interface, like your DIContainer.GetComponent function. In the previous version, injections were always done on instance fields of objects.

    There is no requirements for the services classes, they doesn’t need to implement any framework specific interface or inherit from some class. The only restriction is that services must be interfaces. Although technically it’s not necessary, I think this is a good practice and I decided to force it.

    This new version is on the same project page as the previous was.

  8. Daniele Teti Says:

    @Magno Machado
    Thanks for this nice news. I’ll check emballo ASAP.
    We really need a solid and supported DI Container for Delphi.

  9. Kylie Batt Says:

    Как это можно определить?…

    The term was first coined by Martin Fowler to describe the mechanism […….

  10. E-bike Says:

    … [Trackback] …

    [...] Read More here: danieleteti.it/2010/01/06/a-simple-dependency-injection-container-for-delphi/ [...] …

Leave a Reply

You must be logged in to post a comment.

WP Theme & Icons by N.Design Studio
Entries RSS Comments RSS Log in