From fefe5638e79fcb16be93eb88d034931b75896418 Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Thu, 7 Mar 2019 11:24:31 -0800 Subject: [PATCH] Update the task-based async APIs added to PowerShell to return a Task object directly (#9079) Update the task-based async APIs added to PowerShell to not use the `aysnc/await` keywords, but to return a `Task` object directly. There is nothing to continue on after the `Task.Factory.FromAsync` call in those methods, so there is not need to use `aysnc` and `await` keywords, which turns the method into a state machine class unnecessarily. --- .../engine/hostifaces/PowerShell.cs | 28 ++++++++----------- .../Api/TaskBasedAsyncPowerShellAPI.Tests.ps1 | 15 +++++----- 2 files changed, 20 insertions(+), 23 deletions(-) diff --git a/src/System.Management.Automation/engine/hostifaces/PowerShell.cs b/src/System.Management.Automation/engine/hostifaces/PowerShell.cs index 4fea236d9b..2014d3d5cb 100644 --- a/src/System.Management.Automation/engine/hostifaces/PowerShell.cs +++ b/src/System.Management.Automation/engine/hostifaces/PowerShell.cs @@ -3083,10 +3083,8 @@ namespace System.Management.Automation /// /// Object is disposed. /// - public async Task> InvokeAsync() - { - return await Task>.Factory.FromAsync(BeginInvoke(), _endInvokeMethod).ConfigureAwait(false); - } + public Task> InvokeAsync() + => Task>.Factory.FromAsync(BeginInvoke(), _endInvokeMethod); /// /// Invoke a PowerShell command asynchronously. @@ -3126,8 +3124,8 @@ namespace System.Management.Automation /// /// Object is disposed. /// - public async Task> InvokeAsync(PSDataCollection input) - => await Task>.Factory.FromAsync(BeginInvoke(input), _endInvokeMethod).ConfigureAwait(false); + public Task> InvokeAsync(PSDataCollection input) + => Task>.Factory.FromAsync(BeginInvoke(input), _endInvokeMethod); /// /// Invoke a PowerShell command asynchronously. @@ -3177,8 +3175,8 @@ namespace System.Management.Automation /// /// Object is disposed. /// - public async Task> InvokeAsync(PSDataCollection input, PSInvocationSettings settings, AsyncCallback callback, object state) - => await Task>.Factory.FromAsync(BeginInvoke(input, settings, callback, state), _endInvokeMethod).ConfigureAwait(false); + public Task> InvokeAsync(PSDataCollection input, PSInvocationSettings settings, AsyncCallback callback, object state) + => Task>.Factory.FromAsync(BeginInvoke(input, settings, callback, state), _endInvokeMethod); /// /// Invoke a PowerShell command asynchronously. @@ -3225,8 +3223,8 @@ namespace System.Management.Automation /// /// Object is disposed. /// - public async Task> InvokeAsync(PSDataCollection input, PSDataCollection output) - => await Task>.Factory.FromAsync(BeginInvoke(input, output), _endInvokeMethod).ConfigureAwait(false); + public Task> InvokeAsync(PSDataCollection input, PSDataCollection output) + => Task>.Factory.FromAsync(BeginInvoke(input, output), _endInvokeMethod); /// /// Invoke a PowerShell command asynchronously and collect @@ -3284,8 +3282,8 @@ namespace System.Management.Automation /// /// Object is disposed. /// - public async Task> InvokeAsync(PSDataCollection input, PSDataCollection output, PSInvocationSettings settings, AsyncCallback callback, object state) - => await Task>.Factory.FromAsync(BeginInvoke(input, output, settings, callback, state), _endInvokeMethod).ConfigureAwait(false); + public Task> InvokeAsync(PSDataCollection input, PSDataCollection output, PSInvocationSettings settings, AsyncCallback callback, object state) + => Task>.Factory.FromAsync(BeginInvoke(input, output, settings, callback, state), _endInvokeMethod); /// /// Begins a batch execution. @@ -3808,10 +3806,8 @@ namespace System.Management.Automation /// /// Object is disposed. /// - public async Task StopAsync(AsyncCallback callback, object state) - { - await Task.Factory.FromAsync(BeginStop(callback, state), _endStopMethod).ConfigureAwait(false); - } + public Task StopAsync(AsyncCallback callback, object state) + => Task.Factory.FromAsync(BeginStop(callback, state), _endStopMethod); #endregion diff --git a/test/powershell/engine/Api/TaskBasedAsyncPowerShellAPI.Tests.ps1 b/test/powershell/engine/Api/TaskBasedAsyncPowerShellAPI.Tests.ps1 index 1d3d62cc39..8130eade2a 100644 --- a/test/powershell/engine/Api/TaskBasedAsyncPowerShellAPI.Tests.ps1 +++ b/test/powershell/engine/Api/TaskBasedAsyncPowerShellAPI.Tests.ps1 @@ -84,15 +84,16 @@ try { It 'cannot invoke a single script asynchronously in a runspace that has not been opened' { $rs = [runspacefactory]::CreateRunspace() $ps = [powershell]::Create($rs) + try { - $r = $ps.AddScript('@(1..10).foreach{Start-Sleep -Milliseconds 500}').InvokeAsync() # This test is designed to fail. You cannot invoke PowerShell asynchronously # in a runspace that has not been opened. - $r.IsFaulted | Should -Be $true - $r.Exception -is [System.AggregateException] | Should -Be $true - $r.Exception.InnerException -is [System.Management.Automation.Runspaces.InvalidRunspaceStateException] | Should -Be $true - $r.Exception.InnerException.CurrentState | Should -Be 'BeforeOpen' - $r.Exception.InnerException.ExpectedState | Should -Be 'Opened' + $err = { $ps.AddScript('1+1').InvokeAsync() } | Should -Throw -ErrorId "InvalidRunspaceStateException" -PassThru + + $err.Exception | Should -BeOfType "System.Management.Automation.MethodInvocationException" + $err.Exception.InnerException | Should -BeOfType "System.Management.Automation.Runspaces.InvalidRunspaceStateException" + $err.Exception.InnerException.CurrentState | Should -Be 'BeforeOpen' + $err.Exception.InnerException.ExpectedState | Should -Be 'Opened' } finally { $ps.Dispose() $rs.Dispose() @@ -117,7 +118,7 @@ try { # This test is designed to fail. You cannot invoke PowerShell asynchronously # in the current runspace because nested PowerShell instances cannot be # invoked asynchronously - $err = { InvokeAsyncHelper -PowerShell $ps -Wait } | Should -Throw -ErrorId 'AggregateException' -PassThru + $err = { $ps.AddScript('1+1').InvokeAsync() } | Should -Throw -ErrorId 'PSInvalidOperationException' -PassThru GetInnerErrorId -Exception $err.Exception | Should -Be 'InvalidOperation' } finally { $ps.Dispose()