0

Using the following construct for a GZipStream it never seems to call the *Async method of my custom stream when GZipStream is the destination of CopyToAsync.

using (var fs = new System.IO.FileStream(@"C:\BTR\Source\Assemblies\BTR.Rbl.Evolution.Documents.dll", 
        System.IO.FileMode.Open, System.IO.FileAccess.Read, System.IO.FileShare.None, 8192, true))
{
    using (var ss = new GZipStream(new MyCustomStream(), CompressionMode.Compress))
    {
        await fs.CopyToAsync(ss);
    }
}

It seems to only call the BeginWrite/EndWrite mechanisms. Is there a way to derive from GZipStream to make it call WriteAsync instead so that my custom stream doesn't have to implement both the WriteAsync method along with the BeginWrite/EndWrite methods?

You can find a working sample of this here

Update: Callstack when initial Write() method called

SampleStream.Write(buffer, offset, count)
System.IO.Compression.DeflateStream.DoMaintenance(array, offset, count)
System.IO.Compression.DeflateStream.InternalWrite(array, offset, count, isAsync)
System.Runtime.Remoting.Messaging.StackBuilderSink.AsyncProcessMessage(msg, replySink)
System.Runtime.Remoting.Proxies.AgileAsyncWorkerItem.ThreadPoolCallBack(o)
System.Threading.QueueUserWorkItemCallback.WaitCallback_Context(state)
System.Threading.ExecutionContext.RunInternal(executionContext, callback, state, preserveSyncCtx)
System.Threading.ExecutionContext.Run(executionContext, callback, state, preserveSyncCtx)
System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem()
System.Threading._ThreadPoolWaitCallback.PerformWaitCallback()
(Unmanaged code)
Terry
  • 2,148
  • 2
  • 32
  • 53

1 Answers1

2

It would be more correct for your custom stream to implement BeginWrite/EndWrite (and BeginRead/EndRead as well). It's not hard if you use my AsyncEx.Tasks library:

public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count,
    AsyncCallback callback, object state)
{
  var task = WriteAsync(buffer, offset, count);
  return ApmAsyncFactory.ToBegin(task, callback, state);
}

public override void EndWrite(IAsyncResult asyncResult)
{
  ApmAsyncFactory.ToEnd(asyncResult);
}

(ApmAsyncFactory has been added to the 1.2.0-alpha-01 version of AsyncEx.Tasks).

Stephen Cleary
  • 437,863
  • 77
  • 675
  • 810
  • Where is ApmAsyncFactory at? I can't find it in the library. – Terry Oct 27 '16 at 14:02
  • @Terry: You need to install the preview version for `ApmAsyncFactory`. I just haven't rolled out version `1.2.0` yet. – Stephen Cleary Oct 27 '16 at 14:05
  • I haven't looked at your code, but before this question I tried to make `BeginWrite/EndWrite` leverage my `WriteAsync` by trying to follow https://msdn.microsoft.com/en-us/library/hh873178(v=vs.110).aspx. I'm by **no means** a Tasks expert, but my attempt got the same strange result as your code is producing (maybe you are just wrapping their suggestions?). When calling `CopyToAsync` with `Console.WriteLine` in `Write` and `WriteAsync` I get 1 `Write`, then tons of `WriteAsync` then end with 3 `Write`. Any idea why I'm not getting **all** `WriteAsync` dumps? Or is that expected? – Terry Oct 27 '16 at 14:19
  • @Terry: That's strange. I have no idea why `CopyToAsync` would call `Write`. I'd take a look at the stack when it calls your `Write`. – Stephen Cleary Oct 27 '16 at 14:37
  • I updated the question to display the stack. I tried digging into Reference Source, but admittedly, this is beyond my thread coding skills. Do you see anything odd there, or just going with the assumption that all is OK? – Terry Oct 31 '16 at 13:10
  • @Terry: It's odd and inefficient, but it should *work* fine. – Stephen Cleary Oct 31 '16 at 14:00