GithubHelp home page GithubHelp logo

tyrrrz / cliwrap Goto Github PK

View Code? Open in Web Editor NEW
4.2K 4.2K 261.0 903 KB

Library for running command-line processes

License: MIT License

C# 100.00%
cli command-line dotnet dotnet-core dotnet-standard event-stream pipe-stderr pipe-stdin pipe-stdout piping process shell stderr stdin stdout

cliwrap's Issues

CancellationToken not always being honored

Hi, thank you for your work here. I've enjoyed using it for over a year now.

I have generally observed no issues at all with your library around clean-up, signal management, output redirection, native handles, etc.

But the cancellations are often not picked up until after the process has exited and well beyond the original time of cancellation. So I am guessing that's this location:

_cancellationToken.ThrowIfCancellationRequested();

Sometimes it works, though (immediate cancellation).

The output callbacks keep getting invoked after cancellation and while the process is still running. That's what I'd expect would happen because we don't want to lose process output, but I thought I'd mention it.

This particular invocation is a build script that starts processes of its own (npm, etc.).

Do you have any suspicion what might cause this behavior? Is the cancellation callback guaranteed to get an execution slot or could it be stuck waiting for the ExecuteAsync task to yield control?

I noticed that your TryKill code is relatively simple and doesn't look at exceptions and other outcomes too hard . May I suggest additions of the following nature? This is taken from some process management code I wrote at some point. Not sure how the API surface maps to what's available on .NET Standard, but I think the general ideas apply.
The important idea being: Check if the termination succeeded or not. And if not handle it in some way.

bool closed;
try
{
    if (!p.HasExited)
    {
        p.CloseMainWindow();
        closed = p.WaitForExit(2000);
    }
    else
    {
        closed = true;
    }
}
catch
{
    closed = false;
}

if (!closed)
{
    try
    {
        if (!p.HasExited)
        {
            p.Kill();

            if (!p.WaitForExit(10000))
            {
                throw new SomeException(
                    $"Most likely failed to terminate process (process ID {processId})'. Termination reason: {reason}. Started with:\n{call}"
                );
            }
        }
    }
    catch (InvalidOperationException) when (process.HasExited)
    {
    }
    catch (Exception ex)
    {
      // ?
    }
}

Setup:

CliWrap 2.3.0 in a NetCoreApp 2.2 project running on Windows directly as a Kestrel host.

// in this instance: powershell -File ".\build_client.ps1"
var cli = Cli.Wrap(executable)
    .EnableExitCodeValidation(isEnabled: false)
    .EnableStandardErrorValidation(isEnabled: false)
    .SetWorkingDirectory(workingDirectory.FullName)
    .SetArguments(command.Arguments ?? "")
    .SetCancellationToken(cancellationToken);

cli
    .SetStandardOutputCallback(async stdOutLine =>
    {
        if (httpTracing)
        {
            await logAsync(stdOutLine);
        }
        lock (writeLock1)
        {
            // StreamWriter backed by a file stream
            writerStdOut.WriteLine(GetLine(stdOutLine));
        }
    })
    .SetStandardErrorCallback(async stdErrLine =>
    {
        if (httpTracing)
        {
            await logAsync(stdErrLine);
        }
        lock (writeLock2)
        {
            // StreamWriter backed by a file stream
            writerStdErr.WriteLine(GetLine(stdErrLine));
        }
    });

output = await cli.ExecuteAsync();

Send SIGINT (Ctrl+C) on cancellation

The current cancellation token kills that application which is needed in some cases but it would also be great to have one that could close the application so the application has time to close gracefully and cleanup. I have a few processes there it would be ideal that i could close them and only kill them as a last resort if the close does not work after a short period of time.

System.InvalidOperationException: No process is associated with this object

I'm getting System.InvalidOperationException while trying to start the process.

System.InvalidOperationException: No process is associated with this object.
   at System.Diagnostics.Process.EnsureState(State state)
   at System.Diagnostics.Process.get_HasExited()
   at CliWrap.Internal.ProcessEx.Dispose()
   at CliWrap.Command.ExecuteAsync(ProcessEx process, CancellationToken cancellationToken)

What it actually means is that targetFilePath pointed to non-existing exe and the process didn't even start. Which is fine, but it throws an exception in wrong place and the exception message is misleading.

Could we have a check whether the process actually started?

Stdin piping doesn't work with a stream that never resolves

Hello,

In our CLI program, we are invoking git mergetool on the user's behalf, and we want to pipe input and output unaltered between the parent process, and the target process (git) for the duration of the target command execution.

We have tried various variations of the following:

await using var stdIn = Console.OpenStandardInput();
await using var stdOut = Console.OpenStandardOutput();
await using var stdErr = Console.OpenStandardError();

var cmd =
	Cli.Wrap("git")
		.WithWorkingDirectory(@"C:\SomeRepository")
		.WithArguments("mergetool")
		.WithStandardInputPipe(PipeSource.FromStream(stdIn))
		.WithStandardOutputPipe(PipeTarget.ToStream(stdOut))
		.WithStandardErrorPipe(PipeTarget.ToStream(stdErr));

var result = await cmd.ExecuteAsync();

The piping of stdout and stderr seem to work as expected. However, input from stdin does not seem to get passed to the target process, because it does absolutely nothing in response to the input while prompting.

To illustrate:
image

What are we doing wrong? Any advice would be greatly appreciated.

Piping ffmpeg into another process doesn't seem to do anything

I am trying to achieve the following pipe with CliWrap:

ffmpeg.exe -y -i "C:\input.mp4" -pix_fmt yuv420p -f yuv4mpegpipe - | aomenc.exe -v -w 1920 -h 1080 --passes=2 --pass=1 --fpf=".\out.stats" -t 1 --cq-level=30 --end-usage=q -o ".\out.ivf" -

This command works as it should in Command Prompt and PowerShell.

To do this, I am using CliWrap like so:

var ffProcess = Cli.Wrap( "C:\\ffmpeg.exe" ).WithArguments( ffArgs );
var aomProcess = Cli.Wrap( "C:\\aomenc.exe" ).WithArguments( aomArgs );
await ( ffProcess | aomProcess ).ExecuteBufferedAsync();

This launches the processes, but seems to just sit there until terminated. When launched manually, these two processes take up 50% CPU, but with CliWrap, they just sit there at 0%. This happens with both ExecuteAsync() and ExecuteBufferedAsync().

Ideally, I would like to use ListenAsync() so that I can read from the StdErr of aomenc.exe and parse the progress it outputs, but that doesn't seem to work either.

Pass arguments as list

I've transformed some Process.Start() calls into Cli.Wrap calls. I've noticed i have to get pretty funky with quotation marks to make it work, at least with one specific application.

Previously i used ProcessStartInfo.ArgumentList (which i guess was introduced with netstandard?).

For one process all i had to do is cli.SetArguments(string.Join(" ", argumentList)) and it worked.

For the other, problematic one i had to try a lot and ended up with a) putting almost (!) every argument set in quotation marks and b) also triple-quotation marks around a "string".
"\"-D RENDER=\"\"\"SINGLE\"\"\"\"" what previously was just "-D RENDER=\"SINGLE\"".

The argument parser in the other application may be buggy. But still, i don't know why it worked with ProcessStartInfo.ArgumentList before.

Looking into your implementation i see you're using "plain old" ProcessStartInfo.Arguments. Maybe using the ProcessStartInfo.ArgumentList and adding an API like ICli.AddArgument would help for these cases.

Can't execute ipconfig

Здравствуйте. С помощью вашей библиотеки я хочу выполнить запросы в консоли cmd. Но у меня не выполняются команды.
Вот пример кода:
string cmd = "ipconfig";
var result = Cli.Wrap("cmd.exe").SetArguments(cmd).Execute();
Console.WriteLine(result.StandardOutput);
Console.ReadKey();
Я хочу выполнить команду ipconfig, но результат работы я не получаю.
И поправьте меня, если я делаю что-то не так.

DebuggerDisplay for command events

A tiny improvement would be to add [DebuggerDisplay("{Text}")] to StandardOutputCommandEvent and StandardErrorCommandEvent. This way when you're looking at command outputs in the debugger you'd see their contents right away, not just after opening the Text property.

What do you think? I can submit a PR.

Older net-framework versions support

Hey, any chance to release support for old netframework versions for tools like installers that need to aim for atleast net3.5 that comes by default with windows 7?

It doesn't have to have async methods, so you can reduce the overhead with BCL libs.

Regards, Eli.

Provide some way to get Process Id

Hi there! Thanks for this greaty utility! It makes my life a lot easier :)
Is there a chance to get some after process Start Callback in order to get the process Id right after the start? I'd do a PR if desired :)

Parsing percentage status (no new lines)

Hi again Alexey,
Please, may you suggest an approach using CliWrap to parse the status as show the application below:
status
Such status will be show in a WinForm.
I tried something similar to the following method
public async Task I_can_execute_a_command_that_pipes_its_stdout_into_an_async_delegate() at PipingSpec.cs, but I just get the calling when there is a new line, at the end of the status, i.e. 100%.
Any guidance on which approach use is appreciated.
Thanks

PipeTarget.ToDelegate splits output into smaller chunks when merged with another pipe

Create a simple console app that prints one, long, continuous string:

	class Program
	{
		static void Main(string[] args)
		{
			Console.Out.Write(new String('x', 100000));
		}
	}

Now, create two unit tests:

[TestFixture]
public class Tests
{

	[Test]
	public async Task Test1()
	{
		var outputBuilder = new StringBuilder();

		await Cli.Wrap(@"<pathToTestApp>")
			.WithStandardOutputPipe(PipeTarget.ToStringBuilder(outputBuilder))
			.ExecuteAsync();

		var output = outputBuilder.ToString();

		Assert.False(output.Contains(Environment.NewLine));
	}

	[Test]
	public async Task Test2()
	{
		var outputBuilder = new StringBuilder();

		await Cli.Wrap(@"<pathToTestApp>")
			.WithStandardOutputPipe(PipeTarget.ToDelegate(line => {outputBuilder.AppendLine(line); }))
			.ExecuteAsync();

		var output = outputBuilder.ToString();

		Assert.False(output.Contains(Environment.NewLine));
	}
}

The first will pass, as expected. The second will fail.

It appears that the delegate PipeTarget is splitting a single, long line in to multiple lines. We're using the delegate target because we want to do some other things to the output than just writing to the StringBuilder (i.e. logging).

How to cancel ongoing process?

Sorry for beginner question, I used this library to create an automated Build (msbuild.exe), my question is let's say for some reason it's taking too long, and I want to cancel the process. How do I do that?

My current app is created using SignalR so every user can see the terminal output on real time.

var cli = Cli.Wrap(command).WithValidation(CommandResultValidation.None).WithArguments(arguments);
            var output = "";

            await foreach (var cmdEvent in cli.ListenAsync())
            {
                switch (cmdEvent)
                {
                    case StartedCommandEvent started:
                        output = "ProcessID : " + started.ProcessId;
                        break;
                    case StandardOutputCommandEvent stdOut:
                        output = stdOut.Text;
                        break;
                    case StandardErrorCommandEvent stdErr:
                        output = stdErr.Text;
                        break;
                    case ExitedCommandEvent exited:
                        output = "ExitCode : " + exited.ExitCode;
                        break;
                }

                //send to all client
                await Clients.All.SendAsync("BuildOutput", output);
            }

Exception out of try-catch scope?

Hi
I'm using CliWrap to running multiple ffmpeg (about 300 in one moment) processes all the time (each process lives for like 5 seconds). Recently i got this exception on my global error handler dispite the fact that every call to Cli.Execute is wrapped by try-catch. Any idea why this might be the case? It's like super rare, but still..

System.AggregateException: One or more errors occurred. ---> System.ComponentModel.Win32Exception: Access is denied
   at System.Diagnostics.Process.Kill()
   at CliWrap.Internal.Extensions.KillIfRunning(Process process)
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Threading.CancellationCallbackInfo.ExecuteCallback()
   at System.Threading.CancellationTokenSource.CancellationCallbackCoreWork(CancellationCallbackCoreWorkArguments args)
   at System.Threading.CancellationTokenSource.ExecuteCallbackHandlers(Boolean throwOnFirstException)
   --- End of inner exception stack trace ---
   at System.Threading.CancellationTokenSource.ExecuteCallbackHandlers(Boolean throwOnFirstException)
   at System.Threading.CancellationTokenSource.NotifyCancellation(Boolean throwOnFirstException)
   at System.Threading.CancellationTokenSource.TimerCallbackLogic(Object obj)
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.TimerQueueTimer.CallCallback()
   at System.Threading.TimerQueueTimer.Fire()
   at System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem()
   at System.Threading.ThreadPoolWorkQueue.Dispatch()
---> (Inner Exception #0) System.ComponentModel.Win32Exception (0x80004005): Access is denied
   at System.Diagnostics.Process.Kill()
   at CliWrap.Internal.Extensions.KillIfRunning(Process process)
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Threading.CancellationCallbackInfo.ExecuteCallback()
   at System.Threading.CancellationTokenSource.CancellationCallbackCoreWork(CancellationCallbackCoreWorkArguments args)
   at System.Threading.CancellationTokenSource.ExecuteCallbackHandlers(Boolean throwOnFirstException)<---

System.ComponentModel.Win32Exception (0x80004005): Access is denied
   at System.Diagnostics.Process.Kill()
   at CliWrap.Internal.Extensions.KillIfRunning(Process process)
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Threading.CancellationCallbackInfo.ExecuteCallback()
   at System.Threading.CancellationTokenSource.CancellationCallbackCoreWork(CancellationCallbackCoreWorkArguments args)
   at System.Threading.CancellationTokenSource.ExecuteCallbackHandlers(Boolean throwOnFirstException)

Use IObserver<T>/IObservable<T> for stdin/stdout/stderr

Title of the issue is self-explanatory: as a suggestion, stdin might be more flexibly represented by having CliWrap provide an IObserver<String> . In this vein, your library would then expose stdout and stderr as each an instance of the push-oriented interface IObservable<String>.

These changes would allow for better integration with other standard techniques, tools, and libraries such as Reactive Extensions.

Trouble running within Windows Service

I have been testing a Windows Service that uses CliWrap and on my DEV machine it works fine.

However, when I try copying the binaries (including all the assemblies that VS2019 included in the output), I get this stack trace:
System.MissingMethodException: Method not found: 'System.Collections.Generic.IDictionary2<System.String,System.String> System.Diagnostics.ProcessStartInfo.get_Environment()'.
at CliWrap.Command.GetStartInfo()
at CliWrap.Command.ExecuteAsync(CancellationToken cancellationToken)`

Can you help me figure out what dependency CliWrap is looking for? I can't find anything missing as far as I've looked!

FWIW: Building/Targeting .Net 4.6.1

Thanks.

Invalid IL code exception with Xamarin.mac

Youtube.Converter fails in Xamarin.mac, it's not a runtime issue with code, it appears to be something with mono.

{System.InvalidProgramException: Invalid IL code in YoutubeExplode.Converter.Internal.FFmpeg/<ConvertAsync>d__2:MoveNext (): IL_01c0: stloc.2   


  at System.Runtime.CompilerServices.AsyncTaskMethodBuilder.Start[TStateMachine] (TStateMachine& stateMachine) [0x0002c] in /Library/Frameworks/Xamarin.Mac.framework/Versions/Current/src/Xamarin.Mac/mcs/class/referencesource/mscorlib/system/runtime/compilerservices/AsyncMethodBuilder.cs:316 
  at YoutubeExplode.Converter.Internal.FFmpeg.ConvertAsync (System.String outputFilePath, System.Collections.Generic.IReadOnlyList`1[T] inputFilePaths, System.String format, System.String preset, System.Boolean avoidTranscoding, System.IProgress`1[T] progress, System.Threading.CancellationToken cancellationToken) [0x00048] in <941c5308801d480e8150dab71e27de93>:0 
  at YoutubeExplode.Converter.YoutubeConverter.DownloadAndProcessMediaStreamsAsync (System.Collections.Generic.IReadOnlyList`1[T] streamInfos, System.String filePath, System.String format, YoutubeExplode.Converter.ConversionPreset preset, System.IProgress`1[T] progress, System.Threading.CancellationToken cancellationToken) [0x002b5] in /YoutubeExplode.Converter/YoutubeExplode.Converter/YoutubeConverter.cs:91 }

The following code is what is causing the issue:

            await Cli.Wrap(_ffmpegFilePath)
                .WithArguments(arguments.Build())
                .WithStandardErrorPipe(stdErrPipe)
                .ExecuteAsync();

The constructor won't even get called because that code is there, replacing it with:

            var process = new Process
            {
                StartInfo = new ProcessStartInfo
                {
                    FileName = _ffmpegFilePath,
                    Arguments = arguments.Build(),
                    RedirectStandardOutput = true,
                    UseShellExecute = false,
                    CreateNoWindow = true
                }
            };

            process.Start();

            string result = process.StandardOutput.ReadToEnd();

            process.WaitForExit();

The conversion will take place, its a very strange issue, I hoping a work around might be added to your library to make this work

How to interact with prompts

Is it possible to answer multiple command prompts using CliWrap?
image
I'd like to automate configuring RClone but the challenge is that there are multiple questions in the setup and long delays in between each steps (while API calls are made in the background).

Obviously I can figure out the answers to all the prompts ahead of time, I'm just not sure how I'd accomplish triggering the prompt answers with CliWrap.

Create TaskCompletionSource with TaskCreationOptions.RunContinuationsAsynchronously

After looking for a good library doing basically what CliWrap does I think it's by far the best solution I've seen so far, thanks for the great work!

While reading some source code stumbled upon this line

private readonly TaskCompletionSource<object?> _exitTcs = new TaskCompletionSource<object?>();

and had to think of David Fowler's async guidance. I don't know if you considered this and I'm not at all deep enough into your code to know if it might not make sense in this case, but I thought I'd drop a note.

Console.ReadKey problems

Hi, thanks for the library. I'm trying to use it to automate something.

I have a 'client' application that has the following code:

while (true)
{
	try
	{
		switch (Console.ReadKey(true).Key)
		{
		}
	} catch {}
}

Because of this, I get as fast as it can the following errors:

Out> 2020-04-15 16:44:12.9287  [1] ERROR Command.ProcessConsoleInput Error processing action System.InvalidOperationException: Cannot read keys when either application does not have a console or when console input has been redirected. Try Console.Read.
Out>    at System.ConsolePal.ReadKey(Boolean intercept)
Out>    at System.Console.ReadKey(Boolean intercept)
Out>    at ClientApplication.Command.ProcessConsoleInput() in Command.cs:line 45

Can something be done by giving the client application a 'pipe' to read from?

The most beautiful solution would be if this could be redirected from the host application, thanks!

ExecuteAsync throwing error even though command runs fine

Hey, so I just updated CliWrap on my App and changed the usage to use SetArguments.

I'm having trouble now as it throws an error on my ExecuteAsync() line even though the command it executes works 100%. It's using ffmpeg to copy a video.

In the temp folder it outputs to, the file is there and works completely fine. Can't figure out whats erroring here

Error:

  HResult=0x80131500
  Message=Underlying process reported an error:
ffmpeg version N-90649-g9825f77ac7 Copyright (c) 2000-2018 the FFmpeg developers
  built with gcc 7.3.0 (GCC)
  configuration: --enable-gpl --enable-version3 --enable-sdl2 --enable-bzlib --enable-fontconfig --enable-gnutls --enable-iconv --enable-libass --enable-libbluray --enable-libfreetype --enable-libmp3lame --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenjpeg --enable-libopus --enable-libshine --enable-libsnappy --enable-libsoxr --enable-libtheora --enable-libtwolame --enable-libvpx --enable-libwavpack --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxml2 --enable-libzimg --enable-lzma --enable-zlib --enable-gmp --enable-libvidstab --enable-libvorbis --enable-libvo-amrwbenc --enable-libmysofa --enable-libspeex --enable-libxvid --enable-libaom --enable-libmfx --enable-amf --enable-ffnvcodec --enable-cuvid --enable-d3d11va --enable-nvenc --enable-nvdec --enable-dxva2 --enable-avisynth
  libavutil      56. 13.100 / 56. 13.100
  libavcodec     58. 17.100 / 58. 17.100
  libavformat    58. 11.101 / 58. 11.101
  libavdevice    58.  2.100 / 58.  2.100
  libavfilter     7. 14.100 /  7. 14.100
  libswscale      5.  0.102 /  5.  0.102
  libswresample   3.  0.101 /  3.  0.101
  libpostproc    55.  0.100 / 55.  0.100
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'C:\Users\njord\Videos\nVidia Share\Rocket League\rage_quit.mp4':
  Metadata:
    major_brand     : mp42
    minor_version   : 0
    compatible_brands: isommp42
    creation_time   : 2018-09-29T10:20:37.000000Z
    date            : 2018
  Duration: 00:02:00.23, start: 0.000000, bitrate: 46971 kb/s
    Stream #0:0(und): Video: h264 (High) (avc1 / 0x31637661), yuv420p(tv, smpte170m/smpte170m/bt470m), 1920x1080 [SAR 1:1 DAR 16:9], 46769 kb/s, 59.89 fps, 60 tbr, 90k tbn, 120 tbc (default)
    Metadata:
      creation_time   : 2018-09-29T10:20:37.000000Z
      handler_name    : VideoHandle
    Stream #0:1(und): Audio: aac (mp4a / 0x6134706D), 48000 Hz, stereo, fltp, 195 kb/s (default)
    Metadata:
      creation_time   : 2018-09-29T10:20:37.000000Z
      handler_name    : SoundHandle
[mp4 @ 00000219fa0f44c0] track 1: codec frame size is not set
Output #0, mp4, to 'C:\Users\njord\Videos\temp\fbc9413e-a396-4f6b-8101-861cc592f16b.mp4':
  Metadata:
    major_brand     : mp42
    minor_version   : 0
    compatible_brands: isommp42
    date            : 2018
    encoder         : Lavf58.11.101
    Stream #0:0(und): Video: h264 (High) (avc1 / 0x31637661), yuv420p(tv, smpte170m/smpte170m/bt470m), 1920x1080 [SAR 1:1 DAR 16:9], q=2-31, 46769 kb/s, 59.89 fps, 60 tbr, 90k tbn, 90k tbc (default)
    Metadata:
      creation_time   : 2018-09-29T10:20:37.000000Z
      handler_name    : VideoHandle
    Stream #0:1(und): Audio: aac (mp4a / 0x6134706D), 48000 Hz, stereo, fltp, 195 kb/s (default)
    Metadata:
      creation_time   : 2018-09-29T10:20:37.000000Z
      handler_name    : SoundHandle
Stream mapping:
  Stream #0:0 -> #0:0 (copy)
  Stream #0:1 -> #0:1 (copy)
Press [q] to stop, [?] for help
frame= 5810 fps=0.0 q=-1.0 size=  556800kB time=00:01:37.79 bitrate=46641.5kbits/s speed= 195x    
frame= 7200 fps=0.0 q=-1.0 Lsize=  689458kB time=00:02:00.21 bitrate=46983.7kbits/s speed= 198x    
video:686409kB audio:2871kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 0.025804%

  Source=CliWrap
  StackTrace:
   at CliWrap.Cli.<ExecuteAsync>d__28.MoveNext()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at YouTubeTool.ViewModels.CutVideoViewModel.<Go>d__46.MoveNext() in C:\Source\GitHub\remiX-\YouTubeTool\src\ViewModels\CutVideoViewModel.cs:line 147```

Consider maintaining changelog

Hey,
Great library you have here. I would suggest you to keep some kind of changelog for users, so we can keep up with what is new. Probably simple CHANGELOG.md would be good enough

Cancellation kills Process finishing actions

I'm using the ExecuteAsync() in a start-function and call the cts.Cancel() from a stop-function. The Cli wraps ffmpeg.exe and the hard Process.Kill() prevents the application to finish recording or converting of videofiles.

Maybe you could add a flag like "UseSoftProcessKill" and send the CTRL+C Command this way:
public async Task StopScreenRecordAsync() { if (AttachConsole((uint)ffmpegProcess.Id)) { SetConsoleCtrlHandler(null, true); try { if (!GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0)) { return; } while (!ffmpegProcess.HasExited) { await Task.Delay(200); } } finally { FreeConsole(); SetConsoleCtrlHandler(null, false); } } }

Thank you!

Doesn't work with git.exe

Thanks for creating CliWrap :-)

When I run git.exe it successfully completes, but ExecutionOutput.StandardError is still filled up with text and the ExecutionOutput.HasError is true. Is this a bug in CliWrap or is there something wrong with git.exe?

How to reproduce:

  1. On Windows 10, download and install Git-2.16.2-64-bit.exe from https://git-scm.com/download/win
  2. Make sure C:\temp folder exists.
  3. Run this code:
using (var cli = new Cli(@"C:\Program Files\Git\bin\git.exe", new CliSettings { WorkingDirectory = @"C:\temp" })) {
    var output = await cli.ExecuteAsync("clone -b \"1.8.2\" --single-branch --depth 1 https://github.com/Tyrrrz/CliWrap.git");
    var errortext = output.StandardError;
}

BTW, the StandardError contains this text:

Cloning into 'CliWrap'...
remote: Counting objects: 38, done.
remote: Compressing objects: 100% (34/34), done.
remote: Total 38 (delta 1), reused 18 (delta 0), pack-reused 0
Unpacking objects: 100% (38/38), done.
Note: checking out 'a4f337c2e4549ae5866656f8249cb21d51794f17'.

You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by performing another checkout.

If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -b with the checkout command again. Example:

  git checkout -b <new-branch-name>

Note: This is also an issue when running on Ubuntu 16.04.4

Missing / too much string escaping?

Hello.

The following code (contains RANDOM string):

var cmdTest = Cli.Wrap("myexe")
    .WithArguments(a => a
        .Add(new[]
            {
                "/superstring",
                "ogq77a3auubgQaVHUXhKpVa*NR!YTsEjn8MA2^9$gZwb2D2z3EU^Fk7d8pS&psPg9F8M*jbfyCDWsewF$5osz9LmcsGUf5jV^@WarHuYPxZXN@GU5&AyhE!3t%W&f@ra"
                }));

produces this command argument - no quotes around the superstring while I expect it to be escaped:

/superstring ogq77a3auubgQaVHUXhKpVa*NR!YTsEjn8MA2^9$gZwb2D2z3EU^Fk7d8pS&psPg9F8M*jbfyCDWsewF$5osz9LmcsGUf5jV^@WarHuYPxZXN@GU5&AyhE!3t%W&f@ra

But, if i want to add a single quotation mark with this code:

var cmdTest = Cli.Wrap("myexe")
	.WithArguments(a => a
		.Add(new[]
		{
			"/superstring",
			"\"ogq77a3auubgQaVHUXhKpVa*NR!YTsEjn8MA2^9$gZwb2D2z3EU^Fk7d8pS&psPg9F8M*jbfyCDWsewF$5osz9LmcsGUf5jV^@WarHuYPxZXN@GU5&AyhE!3t%W&f@ra\""
		}));

I get the following command arguments - too many quotes:

/superstring "\"ogq77a3auubgQaVHUXhKpVa*NR!YTsEjn8MA2^9$gZwb2D2z3EU^Fk7d8pS&psPg9F8M*jbfyCDWsewF$5osz9LmcsGUf5jV^@WarHuYPxZXN@GU5&AyhE!3t%W&f@ra\""

My way to overcome this is to create the arguments by myself with StringBuilder and send it to the WithArguments method.

Is there another way to solve it?

Thanks!

How to handle apps that do not give an exit code?

First, very nice library!
Now to my problem, I use it to merge MKV files with mkvmerge (v46) but i have the problem that mkvmerge finishes but gives appenrently no exit code so my app hangs and i need to restart it.

How do you handle this case?

ThrowIfError message should include the StandardError text

When ExecutionOutput.ThrowIfError() is called, the exception message seen in the output log looks something like this:

Unhandled Exception: System.AggregateException: One or more errors occurred.
(Underlying process reported an error. Inspect [StandardError] property for more information.)
---> CliWrap.Exceptions.StandardErrorException:
Underlying process reported an error. Inspect [StandardError] property for more information.

This is "ok" in a development/debug environment, but won't be helpful in a production environment.

The ThrowIfError message should include the StandardError text.

Send command after execution

Let's suppose I have a long-running command-line app that exits on Ctrl+C. How would I model this with CliWrap? Startup is simple but once it runs how can I send it a Ctrl+C command? Would writing a line to a stream piped onto stdin work even after ExecuteAsync()?

Thank you.

How to run an embedded resource executable?

Hello,
Sorry for beginner question.
I would like to use this library to run an embedded resource executable. I cannot find any documentation or reference.
The idea is to hide the application from the user.
Thanks!

How to setup "ProcessStartInfo.StandardOutputEncoding"

I would like to start a CSharp app via cmd which prints UTF-8 Text.
To work correctly I need to execute chcp 65001 first or start it with a non ANS OutputEncoding.

This would be possible by setting StandardOutputEncoding of the class ProcessStartInfo.
The construction of this class is unfortunately handled in a private method. Could you make these internals somehow available? Best would be something like an "OnAdjustProcessStartInfo" event.

I have seen that you have an overload ExecuteAsync which affects the interpretation of the binary output... But it does not "inform" the application about that encoding.

Interface for Cli class

Hello Sir, thank you for the great library.

It will be great to have an interface for Cli as it will be much more easy to create unit tests for classes which use Cli class.
E.g.

public interface ICli
{
    string FilePath { get; }
    CliSettings Settings { get; }
    
    void CancelAll();
    ExecutionOutput Execute(ExecutionInput input, CancellationToken cancellationToken = default(CancellationToken), IBufferHandler bufferHandler = null);
    ExecutionOutput Execute(string arguments, CancellationToken cancellationToken = default(CancellationToken), IBufferHandler bufferHandler = null);
    ExecutionOutput Execute(CancellationToken cancellationToken = default(CancellationToken), IBufferHandler bufferHandler = null);
    void ExecuteAndForget(ExecutionInput input);
    void ExecuteAndForget(string arguments);
    void ExecuteAndForget();
    Task<ExecutionOutput> ExecuteAsync(ExecutionInput input, CancellationToken cancellationToken = default(CancellationToken), IBufferHandler bufferHandler = null);
    Task<ExecutionOutput> ExecuteAsync(string arguments, CancellationToken cancellationToken = default(CancellationToken), IBufferHandler bufferHandler = null);
    Task<ExecutionOutput> ExecuteAsync(CancellationToken cancellationToken = default(CancellationToken), IBufferHandler bufferHandler = null);
}

Regards,

Doesn't work on Ubuntu

System.ComponentModel.Win32Exception (0x80004005): Unable to retrieve the specified information about the process or thread. It may have exited or may be privileged.
at System.Diagnostics.Process.GetStat()
at System.Diagnostics.Process.get_StartTimeCore()
at System.Diagnostics.Process.get_StartTime()
at CliWrap.Cli.Execute(ExecutionInput input, CancellationToken cancellationToken, IBufferHandler bufferHandler)

I tried executing my app with sudo and without, gave file execute permission, I don't really know if it's my problem or the library, although I had it working while using the Process class.

ObjectDisposedException when using SetStandardOutputCallback

Getting:

Unhandled Exception: 
Unhandled Exception:System.ObjectDisposedException: The semaphore has been disposed.
   at System.Threading.SemaphoreSlim.CheckDispose()
   at System.Threading.SemaphoreSlim.Release(Int32 releaseCount)
   at CliWrap.Internal.Signal.Release()
   at CliWrap.Internal.CliProcess.<>c__DisplayClass24_0.<.ctor>b__2(Object sender, DataReceivedEventArgs args)
   at System.Diagnostics.Process.ErrorReadNotifyUser(String data)
   at System.Diagnostics.AsyncStreamReader.FlushMessageQueue()
   at System.Diagnostics.AsyncStreamReader.ReadBuffer(IAsyncResult ar)
   at System.IO.Stream.ReadWriteTask.InvokeAsyncCallback(Object completedTask)
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.IO.Stream.ReadWriteTask.System.Threading.Tasks.ITaskCompletionAction.Invoke(Task completingTask)
   at System.Threading.Tasks.Task.FinishContinuations()
   at System.Threading.Tasks.Task.FinishStageThree()
   at System.Threading.Tasks.Task.FinishStageTwo()
   at System.Threading.Tasks.Task.Finish(Boolean bUserDelegateExecuted)
   at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& currentTaskSlot)
   at System.Threading.Tasks.Task.ExecuteEntry(Boolean bPreventDoubleExecution)
   at System.Threading.Tasks.Task.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem()
   at System.Threading.ThreadPoolWorkQueue.Dispatch()
   at System.Threading._ThreadPoolWaitCallback.PerformWaitCallback()

It appears the events are still getting fired after the Signals are disposed.

The fix appears to be disconnecting the event handlers before disposing of the semaphores.

PR coming soon.

Set environment variables

First of all, just wanted to say good job on this project, it's awesome and I will undoubtedly use it on any of my upcoming projects!

My request is to be able to set environment variables for the process. Exposing ProcessStartInfo.EnvironmentVariables would be enough for the job.

Deadlocking issue with lots of stdout and stderr

We're using CliWrap to invoke R scripts for data modelling (R is a stats/data analysis language). I'm using the event stream usage example that you have posted on Github like this:

           await cmd.Observe().ForEachAsync(cmdEvent => {
                    switch (cmdEvent) {
                        case StandardOutputCommandEvent stdOut:
                            sbOut.AppendLine($"{stdOut.Text}");
                            break;
                        case StandardErrorCommandEvent stdErr:
                            sbErr.AppendLine($"{stdErr.Text}");
                            break;
                        case ExitedCommandEvent exited:
                            //handle exit-code etc
                            break;
                    }
                });

All I do for StandardOutputCommandEvent and StandardErrorCommandEvent is capture the text to 2 different string builders which I dump to a log periodically so we can actually see the script progress in real time. What seems to be happening though is that something locks up and the event stream stops capturing. So I get no further output and the ExitedCommandEvent never fires so it never runs my completion and cleanup code, to my program it just appears as if it is still running. The thing is, the script actually does complete it's execution because at the end it writes out several files and I've verified that those are being written even when the code above hangs.

The other clue is that when I was testing this, it was very sporadic: sometimes it would run to completion, sometimes it would hang-up. As best I can tell the issue seems to be with high volume messages in quick succession. When I would test with a small dataset, the RScript will rip though the numbers very quickly (only 1-2 mins) and since it is quite verbose in it's messaging, you'll get a lot of output happening quickly. But with the large datasets it takes R much longer to execute each step in the script so the messages come though much slower over 30-40 mins which doesn't seem to cause an issue. Not sure if this is a deadlocking issue, but I did see a mention of that in the last release notes. Thank you

I need Process Id exposed through CLI/ICLI so I can kill off the underlying long running process

Lets say I am doing an infinite ping.exe -t (actually something more like sqlite3.exe on a SQL script which does some pretty long queries or large updates/inserts) so:
"TokenSource?.Cancel(); Task?.Wait();" on Window Close/Exit doesn't take effect immediately but waits around and takes a long time if the currently executing query line is a long running one before finishing;
Whilst:
"if (this.Thread?.IsAlive == true) this.Thread?.Abort();" is both rather nasty and whilst it appearing immediate actually leaves a stray ping.exe (or sqlite3.exe) sub-process still up and running to cause havoc and locks or multi writer corruption on SQLite files for example.

I need to kill off the ping.exe (or sqlite3.exe) sub-process explicitly using its Process.Id so I am now compiling your code rather than using the DLL through NuGet so I am going to make the change here which I estimate at around a half dozen lines of code plus an external Kill(int Id) routine of my own.

Let me know if you would like the results to reincorporate back into your code case once I get this up tested and working and then I too can switch back to your newer NuGet DLL down the track!

Sound like a plan?

BTW: I moved to CliWrap from another library and this is the only thing missing. The Stdout and Stderr callbacks work like a treat: I couldn't see any easy way of doing line by line output without this and with any other library it has already made my life significantly easier. SUGGESTION: Make EnableExitCodeValidation and EnableStandardErrorValidation false by default as I started looking at MedallionShell in the beginning when I mistakenly thought that your library like the first I tried wasnt working and was giving me grief at first.

Bad transition to task state

This happens sometimes, not sure why.

System.AggregateException: One or more errors occurred. ---> System.AggregateException: One or more errors occurred. ---> System.InvalidOperationException: An attempt was made to transition a task to a final state when it had already completed.
   at System.Threading.Tasks.TaskCompletionSource`1.SetCanceled()
   at CliWrap.Cli.<>c__DisplayClass22_1.<ExecuteAsync>b__3()
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Threading.CancellationCallbackInfo.ExecuteCallback()
   at System.Threading.CancellationTokenSource.CancellationCallbackCoreWork(CancellationCallbackCoreWorkArguments args)
   at System.Threading.CancellationTokenSource.ExecuteCallbackHandlers(Boolean throwOnFirstException)
   --- End of inner exception stack trace ---
   at System.Threading.CancellationTokenSource.ExecuteCallbackHandlers(Boolean throwOnFirstException)
   at System.Threading.CancellationTokenSource.NotifyCancellation(Boolean throwOnFirstException)
   at System.Threading.CancellationTokenSource.LinkedTokenCancelDelegate(Object source)
   at System.Threading.CancellationCallbackInfo.ExecuteCallback()
   at System.Threading.CancellationTokenSource.CancellationCallbackCoreWork(CancellationCallbackCoreWorkArguments args)
   at System.Threading.CancellationTokenSource.ExecuteCallbackHandlers(Boolean throwOnFirstException)
   --- End of inner exception stack trace ---
   at System.Threading.CancellationTokenSource.ExecuteCallbackHandlers(Boolean throwOnFirstException)
   at System.Threading.CancellationTokenSource.NotifyCancellation(Boolean throwOnFirstException)
   at System.Threading.CancellationTokenSource.TimerCallbackLogic(Object obj)
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.TimerQueueTimer.CallCallback()
   at System.Threading.TimerQueueTimer.Fire()
   at System.Threading.TimerQueue.FireNextTimers()
---> (Inner Exception #0) System.AggregateException: One or more errors occurred. ---> System.InvalidOperationException: An attempt was made to transition a task to a final state when it had already completed.
   at System.Threading.Tasks.TaskCompletionSource`1.SetCanceled()
   at CliWrap.Cli.<>c__DisplayClass22_1.<ExecuteAsync>b__3()
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Threading.CancellationCallbackInfo.ExecuteCallback()
   at System.Threading.CancellationTokenSource.CancellationCallbackCoreWork(CancellationCallbackCoreWorkArguments args)
   at System.Threading.CancellationTokenSource.ExecuteCallbackHandlers(Boolean throwOnFirstException)
   --- End of inner exception stack trace ---
   at System.Threading.CancellationTokenSource.ExecuteCallbackHandlers(Boolean throwOnFirstException)
   at System.Threading.CancellationTokenSource.NotifyCancellation(Boolean throwOnFirstException)
   at System.Threading.CancellationTokenSource.LinkedTokenCancelDelegate(Object source)
   at System.Threading.CancellationCallbackInfo.ExecuteCallback()
   at System.Threading.CancellationTokenSource.CancellationCallbackCoreWork(CancellationCallbackCoreWorkArguments args)
   at System.Threading.CancellationTokenSource.ExecuteCallbackHandlers(Boolean throwOnFirstException)
---> (Inner Exception #0) System.InvalidOperationException: An attempt was made to transition a task to a final state when it had already completed.
   at System.Threading.Tasks.TaskCompletionSource`1.SetCanceled()
   at CliWrap.Cli.<>c__DisplayClass22_1.<ExecuteAsync>b__3()
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Threading.CancellationCallbackInfo.ExecuteCallback()
   at System.Threading.CancellationTokenSource.CancellationCallbackCoreWork(CancellationCallbackCoreWorkArguments args)
   at System.Threading.CancellationTokenSource.ExecuteCallbackHandlers(Boolean throwOnFirstException)<---
<---

System.AggregateException: One or more errors occurred. ---> System.InvalidOperationException: An attempt was made to transition a task to a final state when it had already completed.
   at System.Threading.Tasks.TaskCompletionSource`1.SetCanceled()
   at CliWrap.Cli.<>c__DisplayClass22_1.<ExecuteAsync>b__3()
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Threading.CancellationCallbackInfo.ExecuteCallback()
   at System.Threading.CancellationTokenSource.CancellationCallbackCoreWork(CancellationCallbackCoreWorkArguments args)
   at System.Threading.CancellationTokenSource.ExecuteCallbackHandlers(Boolean throwOnFirstException)
   --- End of inner exception stack trace ---
   at System.Threading.CancellationTokenSource.ExecuteCallbackHandlers(Boolean throwOnFirstException)
   at System.Threading.CancellationTokenSource.NotifyCancellation(Boolean throwOnFirstException)
   at System.Threading.CancellationTokenSource.LinkedTokenCancelDelegate(Object source)
   at System.Threading.CancellationCallbackInfo.ExecuteCallback()
   at System.Threading.CancellationTokenSource.CancellationCallbackCoreWork(CancellationCallbackCoreWorkArguments args)
   at System.Threading.CancellationTokenSource.ExecuteCallbackHandlers(Boolean throwOnFirstException)
---> (Inner Exception #0) System.InvalidOperationException: An attempt was made to transition a task to a final state when it had already completed.
   at System.Threading.Tasks.TaskCompletionSource`1.SetCanceled()
   at CliWrap.Cli.<>c__DisplayClass22_1.<ExecuteAsync>b__3()
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Threading.CancellationCallbackInfo.ExecuteCallback()
   at System.Threading.CancellationTokenSource.CancellationCallbackCoreWork(CancellationCallbackCoreWorkArguments args)
   at System.Threading.CancellationTokenSource.ExecuteCallbackHandlers(Boolean throwOnFirstException)<---

System.InvalidOperationException: An attempt was made to transition a task to a final state when it had already completed.
   at System.Threading.Tasks.TaskCompletionSource`1.SetCanceled()
   at CliWrap.Cli.<>c__DisplayClass22_1.<ExecuteAsync>b__3()
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Threading.CancellationCallbackInfo.ExecuteCallback()
   at System.Threading.CancellationTokenSource.CancellationCallbackCoreWork(CancellationCallbackCoreWorkArguments args)
   at System.Threading.CancellationTokenSource.ExecuteCallbackHandlers(Boolean throwOnFirstException)
System.InvalidOperationException: An attempt was made to transition a task to a final state when it had already completed.
   at System.Threading.Tasks.TaskCompletionSource`1.SetCanceled()
   at CliWrap.Cli.<>c__DisplayClass22_1.<ExecuteAsync>b__3()
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Threading.CancellationCallbackInfo.ExecuteCallback()
   at System.Threading.CancellationTokenSource.CancellationCallbackCoreWork(CancellationCallbackCoreWorkArguments args)
   at System.Threading.CancellationTokenSource.ExecuteCallbackHandlers(Boolean throwOnFirstException)

also, i can be connected to other exception:

System.InvalidOperationException: An attempt was made to transition a task to a final state when it had already completed.
   at System.Threading.Tasks.TaskCompletionSource`1.SetResult(TResult result)
   at System.Diagnostics.Process.ErrorReadNotifyUser(String data)
   at System.Diagnostics.AsyncStreamReader.FlushMessageQueue()
   at System.Diagnostics.AsyncStreamReader.ReadBuffer(IAsyncResult ar)
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.IO.Stream.ReadWriteTask.System.Threading.Tasks.ITaskCompletionAction.Invoke(Task completingTask)
   at System.Threading.Tasks.Task.FinishContinuations()
   at System.Threading.Tasks.Task.Finish(Boolean bUserDelegateExecuted)
   at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& currentTaskSlot)
   at System.Threading.Tasks.Task.ExecuteEntry(Boolean bPreventDoubleExecution)
   at System.Threading.ThreadPoolWorkQueue.Dispatch()

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.