0

嗨,我正在尝试使用 a内部ScriptBlock的特定来执行 a ,但是如果其中有一个管道,它将永远挂起(可能是死锁)。SessionStateICommandPredictorScriptBlock

我有一个在这里重现问题的项目。

要重新创建问题:

  1. 克隆仓库
  2. 在 Visual Studio 2021 中打开
  3. Predictor.cs第 23 行设置断点
  4. 从调试开始
  5. 在打开的终端中输入一个字符。
  6. Visual Studio 应弹出断点命中
  7. 按 F10(跳过)
  8. 因为我们被困住了,你永远不会到达第 2831行。

所以我在执行 ScriptBlocks 的方式上可能做错了什么。但流程是:

  1. 当终端启动时,它会执行Install-ScriptBlock
    1. ScriptBlock使用一个新的 Session 执行 a ,该 Session 又执行set-scriptblockset-scriptblock存储提供ScriptBlock的和新的SessionState
    2. 创建一个 ICommandPredictor 并将其注册到子系统。
  2. 当您在终端中键入ICommandPredictor被调用时,这反过来会尝试执行set-scriptblock使用同一会话保存的脚本块。

我希望这是有道理的,并且我知道流程有些复杂,但是我无法在不破坏我的用例的情况下删除流程中的任何步骤..

那么有什么方法可以改变它以允许我在执行 aScriptBlockICommandPredictor执行SessionStateaScriptBlock而不导致它挂起?

万一我的链接中断了,它有以下代码:

[Cmdlet("Install", "ScriptBlock"), OutputType(typeof(bool))]
public class InstallScriptBlock : PSCmdlet
{


    public static string AssemblyPath
    {
        get
        {
            string codeBase = Assembly.GetExecutingAssembly().Location;
            UriBuilder uri = new UriBuilder(codeBase);
            return Uri.UnescapeDataString(uri.Path); ;
        }
    }

    protected override void ProcessRecord()
    {
        var path = Path.Combine(Path.GetDirectoryName(AssemblyPath), "script.ps1");
        var script = ScriptBlock.Create("set-scriptblock -Expression { @( 'One', ' *$Two' ) | % { $_.trim(\" *$\") } }");
        InvokeCommand.InvokeScript(true, script, new List<object>());
        InvokeCommand.InvokeScript("Set-PSReadLineOption -PredictionSource Plugin");
        SubsystemManager.RegisterSubsystem<ICommandPredictor, Predictor>(new Predictor());
        base.ProcessRecord();
    }

}

public class Predictor : ICommandPredictor
{
    public string Description => "TestHang";

    public Guid Id => new Guid("7959E3B3-8444-478A-A821-48A07FB407DF");

    public string Name => "TestHang";

    public bool CanAcceptFeedback(PredictionClient client, PredictorFeedbackKind feedback)
    {
        return false;
    }

    public SuggestionPackage GetSuggestion(PredictionClient client, PredictionContext context, CancellationToken cancellationToken)
    {
        try
        {
            //The line below will cause a permanent hang of this thread!
            var result = State.InvokeCommand.InvokeScript(State.SessionState, State.ScriptBlock);
            //We never get here!
        }
        catch (Exception ex)
        {
            throw;
        }        

        return default;
    }

    public void OnCommandLineAccepted(PredictionClient client, IReadOnlyList<string> history)
    {
    }

    public void OnCommandLineExecuted(PredictionClient client, string commandLine, bool success)
    {
    }

    public void OnSuggestionAccepted(PredictionClient client, uint session, string acceptedSuggestion)
    {
    }

    public void OnSuggestionDisplayed(PredictionClient client, uint session, int countOrIndex)
    {
    }
}

[Cmdlet("Set", "ScriptBlock"), OutputType(typeof(bool))]
public class SetScriptBlock : PSCmdlet
{
    /// <summary>
    /// <para type="description">Indicates whether the user would like to receive output. </para>
    /// </summary>
    [Parameter(Mandatory = true)]
    public ScriptBlock Expression { get; set; } = null!;


    protected override void ProcessRecord()
    {
        State.ScriptBlock = Expression;
        State.SessionState = SessionState;
        State.InvokeCommand = InvokeCommand;
        base.ProcessRecord();
    }
}

static class State
{
    public static CommandInvocationIntrinsics InvokeCommand { get; set; }
    public static SessionState SessionState { get; set; }
    public static ScriptBlock ScriptBlock { get; set; }
}


4

0 回答 0