internal override async Task GetSeriesImagesImpAsync(GetSeriesImagesRequest request, CancellationToken ct)
        {
            var seriesByReq          = new Dictionary <DicomCMoveRequest, Series>(); // filled below
            var remainingImagesByReq = new Dictionary <DicomCMoveRequest, int>();    // filled below
            var totalImages          = request.Series.Sum(s => s.NumberOfSeriesRelatedInstances);

            object progressLock = new object();

            DicomCMoveRequest.ResponseDelegate handler = (req, resp) =>
            {
                lock (progressLock)
                {
                    remainingImagesByReq[req] = resp.Remaining;
                    var remainingImages = remainingImagesByReq.Sum(kvp => kvp.Value);
                    var progress        = (double)(totalImages - remainingImages) / totalImages;

                    if (progress < 0.99)
                    {
                        request.RaiseProgress((int)(progress * 100));
                    }
                }

                if (resp.Remaining == 0)
                {
                    var series = seriesByReq[req];
                    series.ImagesUri = CStoreScp.GetSeriesImagesUri(series.SeriesInstanceUid);
                    request.RaiseSeriesDone(series);
                }
            };

            foreach (var series in request.Series)
            {
                var cmove = series.CreateCMoveRequest(_settings.DicomSettings);
                cmove.OnResponseReceived   += handler;
                seriesByReq[cmove]          = series;
                remainingImagesByReq[cmove] = series.NumberOfSeriesRelatedInstances;
            }

            var client = _settings.DicomSettings.CreateClient();
            await client.AddRequestsAsync(seriesByReq.Keys);

            await client.SendAsync(ct);

            request.RaiseProgress(100);
        }
        private async Task GetImageAsync(Request[] requests, DicomSearchServiceSettings settings, CancellationToken ct, Action <Image> progress)
        {
            var requestsByDicom = new Dictionary <DicomCMoveRequest, Request>(); // filled below

            DicomCMoveRequest.ResponseDelegate handler = (dicomReq, dicomResp) =>
            {
                if (ct.IsCancellationRequested || dicomResp.Status.State != DicomState.Success)
                {
                    return;
                }

                var request      = requestsByDicom[dicomReq];
                var midImageDesc = request.ImagesDesc.OrderBy(id => id.InstanceNumber).ElementAt(request.ImagesDesc.Count() / 2);

                var image = LoadImage(midImageDesc);
                if (image == null)
                {
                    return;
                }

                if (request.Series.Orientation == FDCSeriesOrientation.eFDC_NO_ORIENTATION &&
                    image.Orientation != FDCSeriesOrientation.eFDC_NO_ORIENTATION)
                {
                    request.Series.Orientation = image.Orientation;
                }

                progress(image);
            };

            foreach (var request in requests)
            {
                var count = request.ImagesDesc.Count();
                if (count <= 0)
                {
                    continue;
                }

                var midImageDesc = request.ImagesDesc.OrderBy(id => id.InstanceNumber).ElementAt(count / 2);
                var localImage   = LoadImage(midImageDesc);
                if (localImage != null)
                {
                    _logger.Debug("no need to get image for series {SeriesInstanceUid}, it's on the disk", midImageDesc.SeriesInstanceUid);

                    if (request.Series.Orientation == FDCSeriesOrientation.eFDC_NO_ORIENTATION &&
                        localImage.Orientation != FDCSeriesOrientation.eFDC_NO_ORIENTATION)
                    {
                        request.Series.Orientation = localImage.Orientation;
                    }

                    progress(localImage);
                    continue;
                }

                var dicomRequest = midImageDesc.CreateCMoveRequest(settings.DicomSettings);

                dicomRequest.OnResponseReceived += handler;
                requestsByDicom[dicomRequest]    = request;
            }

            if (requestsByDicom.Count == 0)
            {
                return;
            }

            _logger.Debug("Getting mid images");

            var client = settings.DicomSettings.CreateClient();
            await client.AddRequestsAsync(requestsByDicom.Keys);

            using (var timeoutCts = CancellationTokenSource.CreateLinkedTokenSource(ct))
            {
                timeoutCts.CancelAfter(settings.SeriesImageSettings.GetImageTimeoutMs * requestsByDicom.Count);
                await client.SendAsync(timeoutCts.Token);
            }
        }