How to fix - The server-side impersonated (RunAs) session tried to invoke a method that is available for client-side processing only
Recently, I was asked to help with an issue in one of our development environments. The scenario was that we were importing bank statements in text format into Dynamics AX and then creating a log file on the system.
I was told that this code was working fine but all of a sudden they were seeing the below error when running the process in batch.
The server-side impersonated (RunAs) session tried to invoke a method that is available for client-side processing only.
The above error occurs only when a code running on Server tries to call a code which is bound to run on client. So whats the bigs issue, you will ask? Why cant the server code call the client code. This will be a problem only when there is no open client. For example, code is running in batch on the server and there is no open client.
To fix this, they had overridden the runsImpersonated() method and were explicitly returning false.
I explained them that, this meant that their batch code will run on the client instead of the server and this was beating the whole purpose of extending from the RunBaseBatch franework.
I traced the error call and it was being thrown from WinAPI::createFile()
I at once knew what the problem was. The WinAPI class is set to RunOn Client while the batch code was running on Server. So, in their case they don’t have a client to invoke this call.
They had two options now,
Either change the RunOn property of WinAPI to Server which they suggested and I rejected,
Use an alternate class. The alternate class in question here is WinAPIServer
Their earlier code was,
I replaced that with,
Now, after removing the runsImpersonated() override, we ran the code again in batch and this time we had a different error
Request for the permission of type 'FileIOPermission' failed.
This was coming from,
(S)\Classes\WinAPIServer\createFile - line 17
The issue here is that the method which we are using is a CAS enabled API. When it is running on the server, it needs permission to be asserted.
Since we were dealing with File IO, I created an object of FileIOPermission and asserted it.
That did it and the issue was solved.
I was told that this code was working fine but all of a sudden they were seeing the below error when running the process in batch.
The server-side impersonated (RunAs) session tried to invoke a method that is available for client-side processing only.
The above error occurs only when a code running on Server tries to call a code which is bound to run on client. So whats the bigs issue, you will ask? Why cant the server code call the client code. This will be a problem only when there is no open client. For example, code is running in batch on the server and there is no open client.
To fix this, they had overridden the runsImpersonated() method and were explicitly returning false.
I explained them that, this meant that their batch code will run on the client instead of the server and this was beating the whole purpose of extending from the RunBaseBatch franework.
I traced the error call and it was being thrown from WinAPI::createFile()
I at once knew what the problem was. The WinAPI class is set to RunOn Client while the batch code was running on Server. So, in their case they don’t have a client to invoke this call.
They had two options now,
Either change the RunOn property of WinAPI to Server which they suggested and I rejected,
Use an alternate class. The alternate class in question here is WinAPIServer
Their earlier code was,
WinAPI::createFile(fileName, #OPEN_EXISTING, #GENERIC_WRITE);
I replaced that with,
WinAPIServer::createFile(fileName);
Now, after removing the runsImpersonated() override, we ran the code again in batch and this time we had a different error
Request for the permission of type 'FileIOPermission' failed.
This was coming from,
(S)\Classes\WinAPIServer\createFile - line 17
The issue here is that the method which we are using is a CAS enabled API. When it is running on the server, it needs permission to be asserted.
Since we were dealing with File IO, I created an object of FileIOPermission and asserted it.
fileIOPermission = new FileIOPermission(fileName, #io_write);
fileIOPermission.assert();
WinAPIServer::createFile(fileName);
That did it and the issue was solved.
Comments
Thank you for a very good post.
The winapi::createFile can be repalced with winapiserver::createFile, but how about winapi::findFirstFile and winapi:findNextFile?
Thanks.
Thank you for demystifying the client and server api.
However, I don't see replacements for winapi::findFirstFile and winapi::findNextFile? I need these to get all teh files in a network directory.
Thanks.
I have issue with "Why cant the server code call the client code. This will be a problem only when there is no open client. For example, code is running in batch on the server and there is no open client."
we can't call to client code from server code. while runsImpersonated returns true.
means, while executing code at server there is no way to call client side code even client is open.