#1 2020-01-30 19:01:10

uian2000
Member
Registered: 2014-05-06
Posts: 69

[solved.final]AV on accessing property Server of TInjectableObjectRest

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

#2 2020-01-30 20:38:27

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,659
Website

Re: [solved.final]AV on accessing property Server of TInjectableObjectRest

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

#3 2020-01-30 20:58:17

uian2000
Member
Registered: 2014-05-06
Posts: 69

Re: [solved.final]AV on accessing property Server of TInjectableObjectRest

Thanks ab, I'll do these works in another procedure.

Offline

#4 2020-01-30 21:48:22

uian2000
Member
Registered: 2014-05-06
Posts: 69

Re: [solved.final]AV on accessing property Server of TInjectableObjectRest

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

#5 2020-01-31 05:08:50

mpv
Member
From: Ukraine
Registered: 2012-03-24
Posts: 1,571
Website

Re: [solved.final]AV on accessing property Server of TInjectableObjectRest

@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 smile

Offline

#6 2020-01-31 07:55:53

uian2000
Member
Registered: 2014-05-06
Posts: 69

Re: [solved.final]AV on accessing property Server of TInjectableObjectRest

thanks @mpv, I'll make a pr of this patch. wink

Offline

#7 2020-01-31 09:30:52

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,659
Website

Re: [solved.final]AV on accessing property Server of TInjectableObjectRest

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

#8 2020-01-31 16:08:23

uian2000
Member
Registered: 2014-05-06
Posts: 69

Re: [solved.final]AV on accessing property Server of TInjectableObjectRest

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. wink

Offline

Board footer

Powered by FluxBB