Spring4D seems to do a very good job for Dependency injection in Delphi. I only started to experiment with it recently and things were working fine until I tried to use it in a dynamic library.
The main application registers a class via an interface and then gets an instance from the container to call a method. The library tries to get an instance and call the method too.
The interface is as follows:
type
IOutputHandler = interface ['{B6C24A62-971F-4D44-85E5-61D1EFC09469}']
procedure WriteMessage(const AMessage: string);
end;
The implementation is:
type
TOutputHandler = class(TInterfacedObject, IOutputHandler)
procedure WriteMessage(const AMessage: string);
end;
implementation
procedure TOutputHandler.WriteMessage(const AMessage: string);
begin
WriteLn(AMessage);
end;
The dynamic library code is:
var
LocalContainer: TContainer;
procedure InitDI(const AContainer: TContainer);
begin
Guard.CheckNotNull(Acontainer, 'AContainer');
LocalContainer := AContainer;
end;
procedure WriteMessage(const AMessage: string);
begin
var service := LocalContainer.Resolve<IOutputHandler>();
service.WriteMessage(AMessage);
end;
exports
InitDI,
WriteMessage;
The application code is:
type
TInitDIProc = procedure(const AContainer: TContainer);
TWriteMessageProc = procedure(const AMessage: string);
...
var container := GlobalContainer();
container.RegisterType<IOutputHandler, TOutputHandler>();
container.Build();
var service := container.Resolve<IOutputHandler>();
service.WriteMessage('Message from main application');
var handle := SafeLoadLibrary('DynamicLibrary.dll');
var initDI := TInitDIProc(GetProcAddress(handle, 'InitDI'));
var writeMessage := TWriteMessageProc(GetProcAddress(handle, 'WriteMessage'));
initDI(container);
writeMessage('Message from dynamic library');
The problem comes in LocalContainer.Resolve<IOutputHandler>(), where an exception is thrown:
EResolveException: Cannot resolve type: IOutputHandler.
The reason is most likely that TypeInfo(IOutputHandler) in the application differs from TypeInfo(IOutputHandler) in the DLL.
Is there a way to fix this and make DI work with DLLs? I can send the code for the entire solution if needed.
The solution is based on passing an interface to the DLL, which is used to resolve the references. This interface is defined as:
The class implementing it in the main applciation (EXE) is as follows:
Another class is used in the DLLs to resolve the references and it is passed an
IDiResolverupon DLL initialization after loading it by the EXE. The class is as follows:Finally, the code in the DLL is even simpler than the initial variant:
The code in the main application (EXE) is changed very little - an instance of the
TDiResolverclass is created and passed to the initialization code in the DLL as an interface:Please have in mind the registration of all interfaces in the DI container is done in the main application and the
IDiResolveris used only in the DLLs.