Load previously compiled scripts

135 views
Skip to first unread message

Nicolas Esteban

unread,
Apr 29, 2013, 9:47:17 AM4/29/13
to cs-s...@googlegroups.com
Hi,

We have to compile and use around ten .cs scripts when our application start. So we use with success this line code :

CSScript.LoadWithConfig(csScript, dllFile, false, cssSettings, "")

We can execute scripts methods without errors.

Now, because scripts don't change often and to avoid long compile time at application start, we tried to load previously generated dll files.
We manage to load it in assemblies like this for each dll files :

byte[] b = File.ReadAllBytes(dllFile);
ass = Assembly.Load(b);


But when we tried to execute methods loaded, with the same code than the first case, we got a general exception 'Exception raised by target' (translated from french, sorry)
The call of our methods :

the_methodname.Invoke("methodName", params);

Anyone has an idea ?

Thanks in advance.

Oleg Shilo

unread,
Apr 29, 2013, 8:52:33 PM4/29/13
to cs-s...@googlegroups.com
Hi Nicolas,

Using  Assembly.Load(byte[]) seems a s a very attractive option but it brings lot's of complications. I found it the hard way. The "killer" one is that it makes Assembly probing very problematic. You can "assist" CLR with AddDomain.Current.ResolveAssembly += <custom probing routine> but it doesn't solve the problem completely.

The following is the fragment from my yesterday post that is very relevant to your case:

As a generic comment...you should be aware about other opportunities while ensuring concurrency of the compiled script assembly.  
    • CS-Script can load the script assembly as a byte array instead of a file. You just to set CSScript.GlobalSettings.InMemoryAsssembly to true and the script engine will read all bites from the assembly file and load the data without locking the file. Though this loading model can trigger some unexpected assembly probing behavior by CLR. That is why InMemoryAsssembly false by default. 

    • Starting from v3.5.0 CS-Script allows script execution under the Mono "compiler as service". Thus there is no need for the temporary AppDomain as well as there is no need to the script assembly (all compilation and loading is done in memory). The feature is described in details here: http://www.csscript.net/Help/evaluator.html   
Also keep in mind that CS-Script does the script caching for you automatically. CSScript.LoadWithConfig(...) never compiles the script again if it was not changed since the last execution. Instead it just loads the assembly in the calling AppDomain.

Cheers,
Oleg

--
You received this message because you are subscribed to the Google Groups "CS-Script" group.
To unsubscribe from this group and stop receiving emails from it, send an email to cs-script+...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

Nicolas Esteban

unread,
Apr 30, 2013, 2:39:28 AM4/30/13
to cs-s...@googlegroups.com, osh...@gmail.com
(I made a miss action to answer, so I did it again)

Thanks Oleg for your answer.

We use Assembly way because CSScript.LoadWithConfig always compiles scripts at each application start.It takes around 15s for 10 scripts.
Is there an option to avoid the compilation ?

Thanks in advance.

Oleg Shilo

unread,
Apr 30, 2013, 8:47:12 AM4/30/13
to cs-s...@googlegroups.com, osh...@gmail.com
Hi Nicolas,

I have done some extra testing and indeed LoadWithConfig does not recompile the script if it is not changed since the last compilation. However cache probing ("IsScriptChanged") mechanism CS-Script is using does not only check the the timestamps of the script and the compiled script but also timestamps of all script dependencies. 

This includes imported scripts and all referenced assemblies. And this actually can lead to the not fully obvious behavior. For example if your script is referencing the host assembly and you keep recompiling it then the script (when loaded) will be recompiled too as the script dependency (host app) is changed.

While it is not necessarily a problem for the production code as the host application will not be recompiled after the deployment it is still an inconvenience during the development. To address this issue I have implemented the custom cache probing that can be defined in the host application. Thus you can define a custom routine for determining if the script needs to be recompiled. And it can be as simple as follows:

CSScript.IsOutOfDate = (script, compiledScript) =>
                       {
                           return File.GetLastWriteTimeUtc(script) != File.GetLastWriteTimeUtc(compiledScript);
                       };
The code above will ensure that script will not be recompiled unless the script timestamp is changed, even if some other dependencies are out of date.

The updated CSScriptLibrary.dll is available from NuGet.

Because your 15 seconds per 10 scripts seems too extreme I added to the sample very simple profiling and you can see that loading a single cached script takes ~ 30 milliseconds. And this time does not depend on the assembly size.

Inline image 1

Oleg

Nicolas Esteban

unread,
Apr 30, 2013, 8:55:54 AM4/30/13
to cs-s...@googlegroups.com, osh...@gmail.com
Thanks Oleg for your answers !

I don't have CSScript.IsOutOfDate properties despite I've download the last dll.
I also see Evaluator class is not present on every version of dll. We are using CSScriptLibrary.v3.5.dll version, because our application is stuck on this framework version.




2013/4/30 Oleg Shilo <oleg....@gmail.com>

--
You received this message because you are subscribed to a topic in the Google Groups "CS-Script" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/cs-script/IqjYl7i9BNc/unsubscribe?hl=en.
To unsubscribe from this group and all its topics, send an email to cs-script+...@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages