You are not logged in.
Hi,
I wanted to use Spring4D to use "virtual methods interceptor" (Nick Hodges presents it here https://www.youtube.com/watch?v=bjVKtac6bAY).
However, it failed, mORMot rejected my interface as incompatible with class (TInterfaceProxy from Spring4D, he is right).
Question:
Is there a way to intercept each method invocation (in interface based service) before and after the execution (on server side)?
Offline
AFAIK there is no Spring.Interception unit in https://bitbucket.org/sglienke/spring4d
You need to use an unstable branch for the feature...
The TServiceFactoryServer.OnMethodExecute event is called before the execution of a method.
It allows to allow/deny execution of the given method.
Then you could use TServiceFactoryServer.SetServiceLog() which allows to log method execution information to a TSQLRecordServiceLog table.
Isn't it enough for you?
Offline
I do not use mORMot tables, an entire layer of DB I'm doing in my own code.
I would just access to BeforeExecute and AfterExecute events for the called service method.
Offline
OK, but what is your exact need?
Security? parameters change? logging? ...?
Did you check TServiceFactoryServer.OnMethodExecute event and TServiceFactoryServer.SetServiceLog() function?
Offline
Yes, I check OnMethodExecute, but it's not enough.
I need:
- perform the measurement of the execution time of my methods and monitor the load of threads
- at the end of execute each service method I need to call a procedure notifying about who called the method (this procedure creates a data packet and puts it into the processing queue - it is kind of billing)
The service method interceptor would be ideal solution. And I know that you could do it quite easily ;-)
Offline
@ab, as a similar question, the last time you asked me to have created a ticket about intercepting all **exceptions** in a single place on the **client** side. Are you still interested in that ticket
Delphi XE4 Pro on Windows 7 64bit.
Lazarus trunk built with fpcupdelux on Windows with cross-compile for Linux 64bit.
Offline
I've added OnBeforeURI, OnAfterURI and OnErrorURI event properties to TSQLRestServer.
It should fit your needs on server side.
See http://synopse.info/fossil/info/52698ae314
Offline
Big thanks Arnaud! :-)
Offline
For the client side, I've added the TSQLRestClientURI.OnFailed centralized event.
See http://synopse.info/fossil/info/7c647a49d6
Offline
Hello,
I'm starting to use these events and came across a minor oversight ;-)
TNotifyBeforeURI = function(Ctxt: TSQLRestServerURIContext): boolean;
TNotifyAfterURI = procedure(Ctxt: TSQLRestServerURIContext);
TNotifyErrorURI = function(Ctxt: TSQLRestServerURIContext; E: Exception): boolean;
Can you add at the end "of object"? :-)
Thx and regards
Last edited by jaclas (2016-01-28 11:59:32)
Offline
Done by http://synopse.info/fossil/info/e89ca864f9
Sorry for the issue.
Offline
Thanks for fast fix.
But, I still have one small problem. You wrote in the documentation:
/// event trigerred when URI() starts to process a request
// - the supplied Ctxt parameter would give access to the command about to
// be executed, e.g. Ctxt.Command=execSOAByInterface would identify a SOA
// service execution, with the corresponding Service and ServiceMethodIndex
// parameters as set by TSQLRestServerURIContext.URIDecodeSOAByInterface <--- this method not exist in class
// - should return TRUE if the method can be executed
// - should return FALSE if the method should not be executed, and set the
// corresponding error to the supplied context e.g.
// ! Ctxt.Error('Unauthorized method',HTML_NOTALLOWED);
// - since this callback would be executed during all TSQLRestServer.URI,
// it should better not make any slow process (like writing to a remote DB)
OnBeforeURI: TNotifyBeforeURI;
but I can't find this method. But nevermind, my question:
How can I find out what method and what parameters is called by client?
How get it from Ctxt: TSQLRestServerURIContext?
Last edited by jaclas (2016-01-28 14:10:44)
Offline
URIDecodeSOAByInterface is defined as an abstract method in TSQLRestServerURIContext, and implemented depending on the REST routing used.
See http://synopse.info/files/html/Synopse% … #TITLE_437
Use the following properties of TSQLRestServerURIContext:
/// the service identified by an interface-based URI
Service: TServiceFactoryServer;
/// the method index for an interface-based service
// - Service member has already be retrieved from URI (so is not nil)
// - 0..2 are the internal _free_/_contract_/_signature_ pseudo-methods
ServiceMethodIndex: integer;
/// the JSON array of parameters for an the interface-based service
// - Service member has already be retrieved from URI (so is not nil)
ServiceParameters: PUTF8Char;
/// the instance ID for interface-based services instance
// - can be e.g. the client session ID for sicPerSession or the thread ID for
// sicPerThread
ServiceInstanceID: cardinal;
Offline
I don't understand :-(
ServiceMethodIndex points to some array/list of methods? Where is this array/list?
Why ServiceParameters is nil in OnBeforeURI()?
Invoked method has 3 parameters.
Offline
Oh my god ... this is deeply buried :-)
It's OK? :
sm := Ctxt.Service.InterfaceFactory.Methods[Ctxt.ServiceMethodIndex];
And how to get the value of any parameter?
Offline
You can use Ctxt.Service.InterfaceFactory.Methods[Ctxt.ServiceMethodIndex] AFTER the method execution,
and Ctxt.Service.InterfaceFactory.Methods[Ctxt.ServiceMethodIndex-3] BEFORE method execution.
Offline
Thx for information.
I don't want to use hardcoded magic value, because it is dangerous (length SERVICE_PSEUDO_METHOD can change).
Can you add public function or class method:
function ServicePseudoMethodCount : Integer;
begin
result := Length(SERVICE_PSEUDO_METHOD);
end;
And I refresh my previous question:
How to get the value of any parameter?
I tried various tricks, but without effect
Offline
When you asked for the callback, you did not mention anything about the parameters.
Is the "user" you wrote about part of the parameters?
Adding a call to your service counting, directly from the implementations methods may do better.
What we have implemented was a high-level hook, for all TSQLRestServer.URI requests (not only interface-based services, but also method-based services and ORM).
Having access to the parameters is tricky, since most of the data is translated directly from JSON into the binary representation in execution stack: it avoids intermediate conversions to TValue for instance (as regular RTTI.pas Invoke does), so uses less memory and allow to pass any kind of content.
So I see two possibilities:
- We may convert the input/output JSON parameters into two TDocVariant, from the input JSON, but it may be resource consuming.
- I guess that what we may also do is to add some other interface instance to be executed, before or after the execution. It would share the same execution stack, and interception code may be able to access the very same variables, on the fly. Execution time would be almost instant, but it may raise some border-side effects, and you would not be able to cancel the execution.
From my point of view, perhaps events with TDocVariant parameters may do the trick.
Offline
I've added new
TServiceFactoryServer.AddInterceptor()
method and new
TServiceMethodExecute.Input/Output
properties.
They would allow to hook interface-based service execution, as you needed.
Offline
Thanks again :-)
But... I well understand?
You're suggesting that I should use method AddInterceptor() RATHER than events OnBeforeURI and OnAfterURI? Because it looks that these solutions are interchangeable. That you mean?
I ask, because variety of solutions now surprised me :-)
best regards
Offline
Yes, TServiceFactoryServer.AddInterceptor() should match your need much better than OnBeforeURI and OnAfterURI.
In practice, TServiceFactoryServer.AddInterceptor() is dedicated to interface-based services interception, whereas OnBeforeURI and OnAfterURI would be triggerred at lower level, for all kind of remote requests.
And TServiceFactoryServer.AddInterceptor() gives you direct access to the executed method information: method name, and even parameters in Input/Output properties.
Offline