You are not logged in.
hi there, I've implemented a class which inherited from TInjectableObjectRest.
I need to do some check on ORM, and boom, AV occurs.
My code is something like this:
constructor TSvcCacheXXX.CreateWithResolver(aResolver: TInterfaceResolver;
aRaiseEServiceExceptionIfNotFound: boolean);
begin
inherited;
fModel := Server.Model; // AV! Server is nil here.
if -1 = fModel.GetTableIndex(TSQLXXX) then
fModel.AddTable(TSQLXXX);
Server.CreateMissingTables;
end;
I've done some work, and found relative code in mormot.pas:
function TServiceFactoryServer.CreateInstance(AndIncreaseRefCount: boolean): TInterfacedObject;
var dummyObj: pointer;
begin
case fImplementationClassKind of
ickWithCustomCreate:
result := TInterfacedObjectWithCustomCreateClass(fImplementationClass).Create;
ickInjectable, ickInjectableRest: begin
result := TInjectableObjectClass(fImplementationClass).
CreateWithResolver(Rest.Services,true); // Call of CreateWithResolver
if fImplementationClassKind=ickInjectableRest then begin // Factory and Server was assigned AFTER Create call of TInjectableObjectRest.CreateWithResolver
TInjectableObjectRest(result).fFactory := self; // Assign of Factory
TInjectableObjectRest(result).fServer := RestServer; // Assign of Server
end;
end;
....
I'm I making a wrong use-case of TInjectableObjectRest.CreateWithResolver?
Or, should we do some tweak on the logical sequence of creation call and property assignment?
Last edited by uian2000 (2020-02-01 14:34:43)
Offline
From the code you quote, you can see that fServer is set after then constructor is called.
So within the overloaded constructor, fServer=Server=nil...
The Server should be initialized outside of this constructor.
Offline
Thanks ab, I'll do these works in another procedure.
Offline
Hi ab, I've tried make initialization in another procedure, they are ugly.
so I introduced a new constructor of TInjectedObjectRest to make sure something could be done logically when instance was created.
codes here.
original TInjectableObjectRest
TInjectableObjectRest = class(TInjectableObject)
protected
fFactory: TServiceFactoryServer;
fServer: TSQLRestServer;
public
then goes my new constructor
/// initialize an instance, defining one dependency resolver factory and
// restserver
// - the resolver may be e.g. a TServiceContainer
// - once the DI/IoC is defined, will call the AutoResolve() protected method
constructor CreateWithResolverAndRest(aResolver: TInterfaceResolver;
aFactory: TServiceFactoryServer; aServer: TSQLRestServer;
aRaiseEServiceExceptionIfNotFound: boolean=true); virtual;
and new reference class
/// class-reference type (metaclass) of a TInjectableObjectRest type
TInjectableObjectRestClass = class of TInjectableObjectRest;
implimentation of constructor
{ TInjectableObjectRest }
constructor TInjectableObjectRest.CreateWithResolverAndRest(
aResolver: TInterfaceResolver; aFactory: TServiceFactoryServer;
aServer: TSQLRestServer; aRaiseEServiceExceptionIfNotFound: boolean=true);
begin
inherited CreateWithResolver(aResolver, aRaiseEServiceExceptionIfNotFound);
fFactory := aFactory;
fServer := aServer;
end;
finally modified TServiceFactoryServer.CreateInstance
function TServiceFactoryServer.CreateInstance(AndIncreaseRefCount: boolean): TInterfacedObject;
var dummyObj: pointer;
begin
case fImplementationClassKind of
ickWithCustomCreate:
result := TInterfacedObjectWithCustomCreateClass(fImplementationClass).Create;
ickInjectable:
result := TInjectableObjectClass(fImplementationClass).
CreateWithResolver(Rest.Services,true);
/// modify begin here -- separate ickInjectableRest from previous condition
ickInjectableRest:
result := TInjectableObjectRestClass(fImplementationClass).
CreateWithResolverAndRest(Rest.Services,self,RestServer,true);
/// modify end here
ickFromInjectedResolver: begin
dummyObj := nil;
if not TSQLRestServer(Rest).Services.
TryResolveInternal(fInterface.fInterfaceTypeInfo,dummyObj) then
raise EInterfaceFactoryException.CreateUTF8(
'ickFromInjectedResolver: TryResolveInternal(%)=false',[fInterface.fInterfaceName]);
result := TInterfacedObject(ObjectFromInterface(IInterface(dummyObj)));
if AndIncreaseRefCount then // RefCount=1 after TryResolveInternal()
AndIncreaseRefCount := false else
dec(TInterfacedObjectHooked(result).FRefCount);
end;
....
Could you please merge this patch , only if it is compatible to mormot framework?
Offline
@uian2000, in case patch is done using github merge request maintainer spends 10 second to merge it. In case code blocks are posted in the forum - 10 minutes or more. Let's save ab time, he is one and there are many of us
Offline
thanks @mpv, I'll make a pr of this patch.
Offline
Please check https://synopse.info/fossil/info/ecfb2ccd71
A small fix in the constructor (setting the properties prior to calling the other constructors chain so so that you can just override plain Create).
Offline
You are awesome @ab.
I've failed several times on cloning my fork to local workspace due to my legacy network.
when i've been defeated, awo, it has been done!
I have checked that fix, it works for me!
Thank you for you great work, again.
Offline