0

I'm using Roslyn's scripting API in my application, code snippet as following:

public class ScriptEngine
{
    public static string CodeText;
    public static event Action<string[]> CompileErrorEvent;

    public static async Task<bool> RunScriptAsync(CancellationToken ct)
    {
        try
        {
            var scriptResult = await CSharpScript.RunAsync(CodeText, null, new ScriptHost(), null, ct);
            return true;
        }
        catch (Microsoft.CodeAnalysis.Scripting.CompilationErrorException ex)
        {
             List<string> result = new List<string>();

             foreach (var item in ex.Diagnostics)
             {
                 result.Add(item.ToString());
             }

             if (result.Count > 0)
             {
                 CompileErrorEvent?.Invoke(result.ToArray());
             }

             return false;
         }
         catch (Exception ex)
         {
             IMCP_Base.Dialog.Show.SimpleError("脚本运行", ex.Message, "修改脚本");
             return false;
         }
     } 
     .......
}

public static CancellationTokenSource ScriptCTS;

private async void btnScriptRun_ItemClick(object sender, ItemClickEventArgs e)
{
    ScriptCTS = new CancellationTokenSource();

    if (CheckScriptEditorIsNotNull())
    {
         Script.ScriptEngine.CodeText = ScriptEditor.GetCode();
         bool runSuccess = await Script.ScriptEngine.RunScriptAsync(ScriptCTS.Token);
    }
}   

private void btnScriptStop_ItemClick(object sender, ItemClickEventArgs e)
{
    ScriptCTS?.Cancel();
}

CSharpScript.RunAsync method runs well, but when I click ScriptStop button, ScriptCTS?.Cancel() can't cancel running script.

How can I stop or pause a script running?

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
NPU行者
  • 1
  • 2
  • If you have more then 1 script then this line `ScriptCTS = new CancellationTokenSource();` will make a lot of issues. Since it's static, you can just initialize this at startup `public static CancellationTokenSource ScriptCTS = new CancellationTokenSource();` – mrogal.ski Jan 04 '17 at 13:28
  • 1
    What is the script doing? You can't cancel execution at arbitrary points. If cancelling the token doesn't do what you want, you're at a point where cancellation isn't possible. Don't forget that cancellation is coöperative - it's just a termination signal, not a rude kill. – Luaan Jan 04 '17 at 13:44
  • @m.rogalski yes, it should be. Since the script may run many times, I'm considering remove static modifiers. It would be private CancellationTokenSource ScriptCTS; – NPU行者 Jan 04 '17 at 16:09
  • @Luaan thank you! I want to use this tech in machine assemble logic control, and the production process need terminate at anytime. I need a rude kill or pause but dosen't know how to do this. – NPU行者 Jan 04 '17 at 16:20
  • That's quite tricky. The only way to abort something is a process kill or a thread abort, and a thread abort is inherently unsafe so you don't really want to do it except for when you also tear down the whole app domain. Even / especially in a production process you must make sure that the abort is safe - you need to stop in a place where it's safe to stop and restore good state. There's not really much general advice I can give you. Maybe a simpler (or custom) scripting engine would work better? Something that's actually designed for aborting execution? – Luaan Jan 04 '17 at 16:39
  • @Luaan Thank you again for your advice. – NPU行者 Jan 05 '17 at 00:54
  • If you want cooperative cancellation you should pass the CancellationToken to the script and have the script check it regularly. If that is not possible in case of for instance misbehaving scripts, you could run the script in a separate appdomain and unload that domain if the script does not respond to cancellation within a certain time. – Frank Bakker Jan 07 '17 at 12:22

1 Answers1

0

If you want cancellation points within your scripts, you can use globals, and pass in the CancelationToken, which you can then check in your scripts for cancellation.

Community
  • 1
  • 1
m0sa
  • 10,712
  • 4
  • 44
  • 91