Blazor:显示收到的命令执行结果

问题描述 投票:0回答:1

我正在使用 Blazor Server (.net 8),我想在输出中显示命令的执行结果。

这是有效但不实时的(所有结果在执行完成后显示)。

@page "/"
@using System.Diagnostics

<Button @onclick="ProcessSomething">execute...</Button>

<InputTextArea @bind-Value="output" />


@code{
    string output = "";

    async Task ProcessSomething()
    {
        Process p = new Process();
        p.StartInfo.UseShellExecute = false;
        p.StartInfo.RedirectStandardOutput = true;
        p.StartInfo.FileName = "cmd.exe";
        p.StartInfo.Arguments = "/c ping 8.8.8.8";

        output = "";
        p.OutputDataReceived += async (sender, args) =>
        {
            Console.WriteLine(args.Data);
            
            output += $"{args.Data}\n";
            
            await InvokeAsync(StateHasChanged);
        };  
        p.Start();  
        p.BeginOutputReadLine();  
        p.WaitForExit();
    }
}

Console.WriteLine(args.Data);
实际上会打印结果,但
InputTextArea
仅在执行完全完成后才会更新。

c# asp.net blazor blazor-server-side .net-8.0
1个回答
0
投票

主要问题是命令代码不是异步的。您在 UI 线程上运行它,因此它会阻止该线程直到完成:事件没有任何效果,因为线程被阻止。

当您在服务器上运行时,您可以将命令分派到线程池线程。这使 UI 可以自由地完成其工作:响应事件并更新 UI。

@page "/"
@using System.Diagnostics
@using System.Text

<button class="btn btn-primary" disabled="@_processing" @onclick="ProcessSomething">execute...</button>

<div class="bg-dark text-white m-2 p-2">
    <pre>@_output</pre>
</div>

@code {
    private StringBuilder _output = new();
    private volatile bool _processing;

    private Task ProcessSomething()
    {
        _output.Clear();
        // The command is blocking
        // so spin the commandoff to a threadpool thread to free up the UI Thread
        Task.Run(RunPingAsync);
        return Task.CompletedTask;
    }

    private async  Task RunPingAsync()
    {
        _processing = true;
        Process p = new Process();
        p.StartInfo.UseShellExecute = false;
        p.StartInfo.RedirectStandardOutput = true;
        p.StartInfo.FileName = "cmd.exe";
        p.StartInfo.Arguments = "/c ping 8.8.8.8";
        p.OutputDataReceived += OnDataReceived;
        p.Start();
        p.BeginOutputReadLine();
        p.WaitForExit();
        _processing = false;
        // Need to call StateHasChanged to update th button state
        await InvokeAsync(StateHasChanged);
    }

    private async void OnDataReceived( object? sender, DataReceivedEventArgs args)
    {
        Console.WriteLine(args.Data);
        _output.AppendLine(args.Data);
        await InvokeAsync(StateHasChanged);
    }
}

输出现在看起来像这样:

© www.soinside.com 2019 - 2024. All rights reserved.