Welcome!

By registering with us, you'll be able to discuss, share and private message with other members of our community.

SignUp Now!

CSScript RoslynEvaluator vs. TCC Plugin Unloading (AppDomain Restrictions)

Aug
2,799
144
Hi @rconn

I am currently developing a C# .NET Framework plugin for TCC (Take Command Console) and running into a conflict between the CSScript RoslynEvaluator and TCC's plugin loader.

I am using the CSScriptLibrary.dll (legacy .NET Framework version) and cannot get the RoslynEvaluator to initialize.

My investigation suggests this is because Roslyn requires a more permissive environment than TCC's restricted AppDomain (which uses custom assembly resolution).

This is a known limitation of Roslyn inside constrained plugin hosts.

I looked through my notes and found a request I made to you in April 2026, regarding the /u (unload) command.

Specifically, that after issuing plugin /u mynet, the mynet.dll file is no longer locked, making it easier to develop .NET plugins.

I can get CodeDomEvaluator working, but I lose the ability to use CS-Script engine directives.

My question is: Is the failure of RoslynEvaluator directly caused by the same AppDomain restrictions that allow the plugin to unload cleanly (releasing the file lock)?

If the answer is "yes," I am fine with that trade-off.

I would prefer to keep the ability to unload the plugin (no file lock) rather than force the RoslynEvaluator to work in this environment.

Ref: cs-script.net-framework/Source/CSScriptLibrary at master · oleg-shilo/cs-script.net-framework

Ref: Done - Load .NET plugin as raw binary data

Joe
 
I managed to get my plugin,
using CSScriptLibrary.dll,
to create temp files,
but if I made a change to the code in a .csx file,
and tried to run it again,
it would error out;

Code:
CSTEST1 error: Access to the path 'C:\Users\jlcav\AppData\Local\Temp\CSSCRIPT\Cache\840006393\CSTemplate.csx.compiled' is denied.

...which is to be expected,
since an assembly cannot be unloaded from memory.

Thus;
Assemblies loaded inside a TCC plugin cannot be unloaded
Assemblies loaded from disk remain locked forever
CS‑Script’s engine (CSScript.Load) always writes a .compiled file
On the next run, CS‑Script tries to delete the previous .compiled file
The delete fails because the file is locked

Result: Access denied

Code:
C:\...\840006393>dir

 Volume in drive C is unlabeled    Serial number is acb2:6a48
 Directory of  C:\Users\jlcav\AppData\Local\Temp\CSSCRIPT\Cache\840006393\*

2026-07-27  11:52         <DIR>    .
2026-07-27  11:52         <DIR>    ..
2026-07-27  11:34              39  css_info.txt
2026-07-27  11:52           2,813  CSTemplate.csx.compiled
2026-07-27  11:34           3,792  prevdate.csx.compiled
               6,644 bytes in 3 files and 2 dirs    12,288 bytes allocated
     222,449,778,688 bytes free

Thus, I am now creating the assemblies in memory,
instead of creating them on the disk.

I've also managed to get some of the CS-Script engine directives to work with the CodeDomEvaluator.

Directives that WILL NOT WORK in my plugin
These require Roslyn or the full preprocessor:

Code:
//css_autoclass freestyle
//css_autoclass (classic autoclass)
//css_import
//css_include (script merging)
//css_prescript
//css_postscript
//css_nuget
//css_searchdir
//css_host
//css_args

Any directive that rewrites the script or generates wrapper classes

These cannot work because:

My plugin cannot load Roslyn (csscodeprovider.dll)
My plugin cannot run the full preprocessor
My plugin is restricted to CodeDom

Directives that DO WORK in my plugin
These are “compiler option” directives — they do not rewrite code:

Code:
//css_co /platform:x64
//css_co /unsafe
//css_co /define:MYFLAG
//css_ref SomeAssembly.dll (if the DLL is loadable in the plugin AppDomain)

These work because they simply pass flags to the CodeDom compiler.

Here is the working routine from my plugin;

Code:
    public int CSTEST1(StringBuilder args)
    {
        try
        {
            CSScript.GlobalSettings.InMemoryAssembly = true;
            CSScript.EvaluatorConfig.Engine = EvaluatorEngine.CodeDom;

            string argsStr = args.ToString().Trim();
            if (string.IsNullOrEmpty(argsStr))
            {
                Console.Error.WriteLine("CSTEST1: No script file specified");
                return 1;
            }

            string[] tokens = argsStr.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
            string scriptFile = tokens[0];
            string[] scriptArgs = tokens.Length > 1 ? tokens.Skip(1).ToArray() : new string[0];

            if (!File.Exists(scriptFile))
            {
                Console.Error.WriteLine($"CSTEST1: File not found: {scriptFile}");
                return 1;
            }

            string scriptCode = File.ReadAllText(scriptFile);
            dynamic script = CSScript.Evaluator.LoadCode(scriptCode);

            string result = script.Run(scriptArgs);
            Console.WriteLine(result);

            return 0;
        }
        catch (Exception ex)
        {
            Console.Error.WriteLine($"CSTEST1 error: {ex.Message}");
            Console.Error.WriteLine($"Stack trace:\n{ex.StackTrace}");
            if (ex.InnerException != null)
            {
                Console.Error.WriteLine($"Inner: {ex.InnerException.Message}");
                Console.Error.WriteLine($"Inner stack trace:\n{ex.InnerException.StackTrace}");
            }
            return 1;
        }
    }

...and here is a .csx file that works with the plugin;

Code:
//css_co /platform:x64
//css_ref System.Data.dll

using System;

public class Script
{
    public string Run(string[] args)
    {
        if (args == null || args.Length == 0)
            return "Hello from plugin-safe script (no arguments)";

        // Join arguments safely
        string joined = string.Join(", ", args);
        return "Hello from plugin-safe script\nArguments: " + joined;
    }
}

Proof;
Code:
Hello from plugin-safe script
Arguments: 10, 20

Thus, using a third-party scripting engine is more difficult than using the csharpProvider that is built-in to the .NET Framework,
which is what I use in the CSScript plugin.

Joe
 
After looking at the Intermediate Language (IL) code for TC-DotNetPluginHost64.dll
I can confirm that I will not be able to use CSScriptLibrary.dll,
which requires the RosylnEvaluator,
in a plugin,
since the TC-DotNetPluginHost64.dll runs in a sandboxed AppDomain.

Now I know.

Joe
 
Back
Top