3

I'm building event-oriented Powershell scripts. For asynchronous network operations, I usually use Begin/End calls such as BeginAcceptTcpClient / EndAcceptTcpClient for a System.Net.Sockets.TcpListener object. These calls use an IAsyncResult object to reference the asynchronous operation.

To generate events that can be easily used by Powershell and mixed with native Powershell events, I use the New-ScriptblockCallback function provided by Microsoft.

function New-ScriptblockCallback {
  param (
    [parameter(Mandatory = $True)]
    [ValidateNotNullOrEmpty()]
    [ScriptBlock] $Callback
  )
  # is this type already defined?
  if (-not ("CallbackEventBridge" -as [type])) {
    Add-Type @"
      using System;
      public sealed class CallbackEventBridge
      {
        public event AsyncCallback CallbackComplete = delegate { };
        private CallbackEventBridge() {}
        private void CallbackInternal(IAsyncResult result)
        {
          CallbackComplete(result);
        }
        public AsyncCallback Callback
        {
          get { return new AsyncCallback(CallbackInternal); }
        }
        public static CallbackEventBridge Create()
        {
          return new CallbackEventBridge();
        }
      }
"@
  }
  $bridge = [callbackeventbridge]::create()
  Register-ObjectEvent -InputObject $bridge -EventName callbackcomplete -Action $Callback -MessageData $args > $null
  $bridge.callback
}

This function can easily be used in asynchronous calls. For instance

$this.AcceptBlock = {
  param( System.IAsyncResult] $AsyncResult )
  [object] $listener = $AsyncResult.AsyncState
  [System.Net.Sockets.TcpClient] $tcpClient = $listener.tcpListener.EndAcceptTcpClient($AsyncResult)

    …. perform custom operations

}

$this.AcceptContextHandler = New-ScriptblockCallback -Callback $this.AcceptBlock
$this.tcpListener = New-Object System.Net.Sockets.TcpListener( $this.IP, $this.port)
$this.tcpListener.Start()
$this.AcceptIAsyncResult = $this.tcpListener.BeginAcceptTcpClient( $this.AcceptContextHandler, $this )

Then the event ‘callbackcomplete’ is raised when the operation completes and the ($this.)AcceptBlock scriptblock is called with the ‘IAsyncResult’ as parameter.

But, from what I've read/understood, the Begin/End methods are going to be abandoned, and what's more, some network calls no longer support/not supported these methods (e.g. Net.WebSockets.ClientWebSocket). Microsoft recommends using the ‘somethingAsync’ methods, which use a 'Task' object to reference the operation.

So my questions are: How can I get these calls to generate an event that can be used simply by Powershell when they are completed ? Is there a function similar to New-ScriptblockCallback that could help me?

I tried to use the Task object in place of IAsyncResult object without any success. To be honest, I wasn't very confident about the results of my tests, even having read that it was possible to cast the Task object as an IAsyncResult object.

jonrsharpe
  • 115,751
  • 26
  • 228
  • 437
Alain
  • 31
  • 1

0 Answers0