Пример #1
0
        public async Task OnCFindRequestAsync_Pending_ShouldRespond()
        {
            var port = Ports.GetNext();

            using (DicomServer.Create <PendingAsyncDicomCFindProvider>(port, logger: _logger.IncludePrefix("DicomServer")))
            {
                var client = new Client.DicomClient("127.0.0.1", port, false, "SCU", "ANY-SCP")
                {
                    Logger = _logger.IncludePrefix(typeof(DicomClient).Name)
                };

                var responses = new ConcurrentQueue <DicomCFindResponse>();
                DicomRequest.OnTimeoutEventArgs timeout = null;
                var request = new DicomCFindRequest(DicomQueryRetrieveLevel.Study)
                {
                    OnResponseReceived = (req, res) => responses.Enqueue(res),
                    OnTimeout          = (sender, args) => timeout = args
                };

                await client.AddRequestAsync(request).ConfigureAwait(false);

                await client.SendAsync().ConfigureAwait(false);

                Assert.Collection(
                    responses,
                    response1 => Assert.Equal(DicomStatus.Pending, response1.Status),
                    response2 => Assert.Equal(DicomStatus.Pending, response2.Status),
                    response3 => Assert.Equal(DicomStatus.Success, response3.Status)
                    );
                Assert.Null(timeout);
            }
        }
        public async Task AcceptStoreContexts()
        {
            int port = Ports.GetNext();

            using (DicomServer.Create <AcceptOnlyEchoStoreProvider>(port))
            {
                var         echoReq    = new DicomCEchoRequest();
                DicomStatus echoStatus = DicomStatus.Pending;
                echoReq.OnResponseReceived += (req, resp) => echoStatus = resp.Status;

                var         storeReq    = new DicomCStoreRequest(@".\Test Data\CT1_J2KI");
                DicomStatus storeStatus = DicomStatus.Pending;
                storeReq.OnResponseReceived += (req, resp) => storeStatus = resp.Status;

                var         filmSession = new FilmSession(DicomUID.BasicFilmSession, DicomUID.Generate());
                var         printReq    = new DicomNCreateRequest(filmSession.SOPClassUID, filmSession.SOPInstanceUID);
                DicomStatus printStatus = DicomStatus.Pending;
                printReq.OnResponseReceived += (req, resp) => printStatus = resp.Status;

                var client = new Client.DicomClient("127.0.0.1", port, false, "SCU", "ANY-SCP");
                await client.AddRequestsAsync(echoReq, storeReq, printReq);

                await client.SendAsync();

                Assert.Equal(DicomStatus.Success, echoStatus);
                Assert.Equal(DicomStatus.Success, storeStatus);
                Assert.Equal(DicomStatus.SOPClassNotSupported, printStatus);
            }
        }
Пример #3
0
        public async Task DicomClientSend_ToAcceptedAssociation_ShouldSendRequest()
        {
            var port = Ports.GetNext();

            using (DicomServer.Create <DicomClientTest.MockCEchoProvider>(port))
            {
                var locker = new object();

                var         expected = DicomStatus.Success;
                DicomStatus actual   = null;

                var client = new Dicom.Network.Client.DicomClient("localhost", port, false, "SCU", "ANY-SCP");
                await client.AddRequestAsync(
                    new DicomCEchoRequest
                {
                    OnResponseReceived = (rq, rsp) =>
                    {
                        lock (locker) actual = rsp.Status;
                    }
                }).ConfigureAwait(false);

                await client.SendAsync().ConfigureAwait(false);

                Assert.Equal(expected, actual);
            }
        }
Пример #4
0
        public async Task DicomClientSend_ToRejectedAssociation_ShouldNotSendRequest()
        {
            var port = Ports.GetNext();

            using (DicomServer.Create <DicomClientTest.MockCEchoProvider>(port))
            {
                var         locker = new object();
                DicomStatus status = null;

                var client = new Dicom.Network.Client.DicomClient("localhost", port, false, "SCU", "WRONG-SCP");
                await client.AddRequestAsync(
                    new DicomCEchoRequest
                {
                    OnResponseReceived = (rq, rsp) =>
                    {
                        lock (locker) status = rsp.Status;
                    }
                }).ConfigureAwait(false);

                try
                {
                    await client.SendAsync().ConfigureAwait(false);
                }
                catch
                {
                }

                Assert.Null(status);
            }
        }
Пример #5
0
        /// <summary>
        ///     Blocks until the request is received so calling code doesn't have to deal with asynchrony (see the EventWaitHandle in TrySend).
        ///     Only the timeout is applied no Throtelling, the client is unreleased on return
        /// </summary>
        /// <param name="client"></param>
        /// <param name="token"></param>

        #region SendRequest
        public void SendRequest(DicomClient client, CancellationToken token)
        {
            _listener.OnNotify(this, new NotifyEventArgs(ProgressEventType.Information, "Sending request to " + _dicomConfiguration.RemoteAetTitle + " at " + _dicomConfiguration.RemoteAetUri.Host + ":" + _dicomConfiguration.RemoteAetUri.Port));
            bool completed;

            try
            {
                completed = client.SendAsync(token)
                            .Wait(_dicomConfiguration.TransferTimeOutInMilliseconds + 1000, token);
            }
            catch (Exception ex)
            {
                OnRequestException?.Invoke(ex);
                throw new Exception("Error when attempting to send DICOM request: " + ex.Message, ex);
            }

            if (completed)
            {
                OnRequestSucess?.Invoke();
            }
            else
            {
                OnRequestTimeout?.Invoke();
            }
        }
        public async Task OnCStoreRequestAsync_PreferedTransfersyntax()
        {
            var port = Ports.GetNext();

            using (DicomServer.Create <AsyncDicomCStoreProviderPreferingUncompressedTS>(port, logger: _logger.IncludePrefix("DicomServer")))
            {
                var client = new Client.DicomClient("127.0.0.1", port, false, "SCU", "ANY-SCP")
                {
                    Logger = _logger.IncludePrefix(typeof(DicomClient).Name)
                };

                int numberOfContexts           = 0;
                DicomTransferSyntax accpetedTS = null;
                // create a request with a jpeg-encoded file
                var request = new DicomCStoreRequest(@"./Test Data/CT1_J2KI");
                client.AssociationAccepted += (sender, e) =>
                {
                    numberOfContexts = e.Association.PresentationContexts.Count;
                    accpetedTS       = e.Association.PresentationContexts.First().AcceptedTransferSyntax;
                };
                await client.AddRequestAsync(request).ConfigureAwait(false);

                await client.SendAsync().ConfigureAwait(false);

                Assert.Equal(2, numberOfContexts); // one for the jpeg2k TS and one for the mandatory ImplicitLittleEndian
                Assert.Equal(DicomTransferSyntax.JPEG2000Lossy, accpetedTS);
            }
        }
Пример #7
0
        public async Task OnCFindRequestAsync_ImmediateSuccess_ShouldRespond()
        {
            var port = Ports.GetNext();

            using (DicomServer.Create <ImmediateSuccessAsyncDicomCFindProvider>(port, logger: _logger.IncludePrefix("DicomServer")))
            {
                var client = new Client.DicomClient("127.0.0.1", port, false, "SCU", "ANY-SCP")
                {
                    Logger = _logger.IncludePrefix(typeof(DicomClient).Name)
                };

                DicomCFindResponse response             = null;
                DicomRequest.OnTimeoutEventArgs timeout = null;
                var request = new DicomCFindRequest(DicomQueryRetrieveLevel.Study)
                {
                    OnResponseReceived = (req, res) => response = res,
                    OnTimeout          = (sender, args) => timeout = args
                };

                await client.AddRequestAsync(request).ConfigureAwait(false);

                await client.SendAsync().ConfigureAwait(false);

                Assert.NotNull(response);
                Assert.Equal(DicomStatus.Success, response.Status);
                Assert.Null(timeout);
            }
        }
Пример #8
0
        /// <summary>
        ///    Throttle requests using W(O) = mO(t) + c where W is the wait period, O is the opertaion duration, m and c are positive constants
        ///    Sends requests added to the client is unreleased at the end of this request send.
        /// </summary>
        ///
        #region ThrottleRequest
        public void ThrottleRequest(DicomClient client, CancellationToken cancellationToken)
        {
            var transferTimer = new Stopwatch();

            transferTimer.Start();
            SendRequest(client, cancellationToken);
            transferTimer.Stop();
            //valuein mills
            var delay = _dicomConfiguration.RequestCooldownInMilliseconds;

            if (delay > 0)
            {
                _listener.OnNotify(this, new NotifyEventArgs(ProgressEventType.Information, "Requests sleeping for " + delay / 1000 + "seconds"));
                Task.Delay(delay, cancellationToken).Wait(cancellationToken);
            }
        }
Пример #9
0
        public async Task DicomClientSend_StorePart10File_ShouldSucceed()
        {
            var port = Ports.GetNext();

            using (var server = DicomServer.Create <CStoreScp>(port))
            {
                server.Logger = _logger.IncludePrefix("CStoreScp");

                var file = DicomFile.Open(@".\Test Data\CT-MONO2-16-ankle");

                var client = new Dicom.Network.Client.DicomClient("127.0.0.1", port, false, "SCU", "SCP")
                {
                    Logger = _logger.IncludePrefix("DicomClient")
                };
                await client.AddRequestAsync(new DicomCStoreRequest(file)).ConfigureAwait(false);

                var exception = await Record.ExceptionAsync(async() => await client.SendAsync());

                Assert.Null(exception);
            }
        }
Пример #10
0
        public async Task SendMaxPDU()
        {
            var  port            = Ports.GetNext();
            uint serverPduLength = 400000;
            uint clientPduLength = serverPduLength / 2;

            using (var server = DicomServer.Create <DicomCEchoProvider>(port, null, new DicomServiceOptions {
                MaxPDULength = serverPduLength
            }))
            {
                uint serverPduInAssociationAccepted = 0;
                var  client = new Client.DicomClient("127.0.0.1", port, false, "SCU", "ANY-SCP");
                client.Options = new DicomServiceOptions {
                    MaxPDULength = clientPduLength
                };                                                                           // explicitly choose a different value
                await client.AddRequestAsync(new DicomCEchoRequest());

                client.AssociationAccepted += (sender, e) => serverPduInAssociationAccepted = e.Association.MaximumPDULength;

                await client.SendAsync();

                Assert.Equal(serverPduLength, serverPduInAssociationAccepted);
            }
        }
Пример #11
0
        public override SMIDataChunk DoGetChunk(ICacheFetchRequest cacheRequest, IDataLoadEventListener listener, GracefulCancellationToken cancellationToken)
        {
            listener.OnNotify(this, new NotifyEventArgs(ProgressEventType.Information, $"PACSSource version is {typeof(PACSSource).Assembly.GetName().Version}.  Assembly is {typeof(PACSSource).Assembly} "));
            listener.OnNotify(this, new NotifyEventArgs(ProgressEventType.Information, $"Fo-Dicom version is {typeof(DicomClient).Assembly.GetName().Version}.  Assembly is {typeof(DicomClient).Assembly} "));

            var dicomConfiguration = GetConfiguration();
            var requestSender      = new DicomRequestSender(dicomConfiguration, listener);
            var dateFrom           = Request.Start;
            var dateTo             = Request.End;

            CachingSCP.LocalAet = LocalAETitle;
            CachingSCP.Listener = listener;

            if (PatientIdWhitelistColumnInfo != null && !IgnoreWhiteList)
            {
                GetWhitelist(listener);
            }

            //temp dir
            var cacheDir    = new LoadDirectory(Request.CacheProgress.LoadProgress.LoadMetadata.LocationOfFlatFiles).Cache;
            var cacheLayout = new SMICacheLayout(cacheDir, new SMICachePathResolver(Modality));

            Chunk = new SMIDataChunk(Request)
            {
                FetchDate = dateFrom,
                Modality  = Modality,
                Layout    = cacheLayout
            };

            ConcurrentBag <StudyToFetch> studiesToOrder = new ConcurrentBag <StudyToFetch>();

            CachingSCP.OnEndProcessingCStoreRequest = (storeRequest, storeResponse) =>
            {
                SaveSopInstance(storeRequest, cacheLayout, listener);
                listener.OnNotify(this,
                                  new NotifyEventArgs(ProgressEventType.Debug,
                                                      "Stored sopInstance" + storeRequest.SOPInstanceUID.UID));
            };

            //helps with tyding up resources if we abort or through an exception and neatly avoids ->  Access to disposed closure
            using (var server = (DicomServer <CachingSCP>)DicomServer.Create <CachingSCP>(dicomConfiguration.LocalAetUri.Port))
            {
                DicomClient client = new DicomClient(dicomConfiguration.RemoteAetUri.Host, dicomConfiguration.RemoteAetUri.Port, false, dicomConfiguration.LocalAetTitle, dicomConfiguration.RemoteAetTitle);

                try
                {
                    // Find a list of studies
                    #region Query

                    listener.OnNotify(this,
                                      new NotifyEventArgs(ProgressEventType.Information,
                                                          "Requesting Studies from " + dateFrom + " to " + dateTo));

                    var request = CreateStudyRequestByDateRangeForModality(dateFrom, dateTo, Modality);
                    request.OnResponseReceived += (req, response) =>
                    {
                        if (Filter(_whitelist, response))
                        {
                            studiesToOrder.Add(new StudyToFetch(response.Dataset.GetSingleValue <string>(DicomTag.StudyInstanceUID)));
                        }
                    };
                    requestSender.ThrottleRequest(request, client, cancellationToken.AbortToken);
                    listener.OnNotify(this,
                                      new NotifyEventArgs(ProgressEventType.Debug,
                                                          "Total filtered studies for " + dateFrom + " to " + dateTo + "is " + studiesToOrder.Count));
                    #endregion

                    //go and get them
                    #region Retrieval

                    var transferStopwatch = new Stopwatch();

                    StudyToFetch current;
                    int          consecutiveFailures = 0;

                    //While we have things to fetch
                    while (studiesToOrder.TryTake(out current))
                    {
                        transferStopwatch.Restart();
                        //delay value in mills
                        if (dicomConfiguration.TransferCooldownInMilliseconds != 0)
                        {
                            listener.OnNotify(this,
                                              new NotifyEventArgs(ProgressEventType.Information,
                                                                  "Transfers sleeping for " + dicomConfiguration.TransferCooldownInMilliseconds / 1000 + "seconds"));
                            Task.Delay(dicomConfiguration.TransferCooldownInMilliseconds, cancellationToken.AbortToken).Wait(cancellationToken.AbortToken);
                        }

                        bool done = false;

                        //Build fetch command that Study
                        var cMoveRequest = CreateCMoveByStudyUid(LocalAETitle, current.StudyUid, listener);

                        //Register callbacks
                        cMoveRequest.OnResponseReceived += (requ, response) =>
                        {
                            listener.OnNotify(this,
                                              new NotifyEventArgs(ProgressEventType.Debug,
                                                                  $"Got {response.Status.State} response for {requ}.  Items remaining {response.Remaining}"));

                            switch (response.Status.State)
                            {
                            case DicomState.Pending:
                            case DicomState.Warning:
                                // ignore
                                break;

                            case DicomState.Cancel:
                            case DicomState.Failure:
                                consecutiveFailures++;

                                if (current.RetryCount < MaxRetries)
                                {
                                    // put it back in the bag with a increased retry count
                                    current.RetryCount++;
                                    studiesToOrder.Add(current);
                                }

                                // final state
                                done = true;
                                break;

                            case DicomState.Success:
                                // final state
                                consecutiveFailures = 0;
                                done = true;
                                break;
                            }
                        };

                        //send the command to the server

                        //tell user what we are sending
                        listener.OnNotify(this, new NotifyEventArgs(ProgressEventType.Information, CMoveRequestToString(cMoveRequest, current.RetryCount + 1)));

                        //do not use requestSender.ThrottleRequest(cMoveRequest, cancellationToken);
                        //TODO is there any need to throtttle this request given its lifetime
                        requestSender.ThrottleRequest(cMoveRequest, client, cancellationToken.AbortToken);


                        //enforce a minimum timeout
                        var  swStudyTransfer     = Stopwatch.StartNew();
                        bool hasTransferTimedOut = false;

                        do
                        {
                            Task.Delay(Math.Max(100, dicomConfiguration.TransferPollingInMilliseconds), cancellationToken.AbortToken)
                            .Wait(cancellationToken.AbortToken);

                            hasTransferTimedOut = swStudyTransfer.ElapsedMilliseconds > dicomConfiguration.TransferTimeOutInMilliseconds;
                        }while(!done && !hasTransferTimedOut);

                        // Study has finished being fetched (or timed out)

                        if (hasTransferTimedOut)
                        {
                            listener.OnNotify(this, new NotifyEventArgs(ProgressEventType.Information, "Abandonning fetch of study " + current.StudyUid));
                        }

                        if (consecutiveFailures > 5)
                        {
                            throw new Exception("Too many consecutive failures, giving up");
                        }

                        // 1 failure = study not available, 2 failures = system is having a bad day?
                        if (consecutiveFailures > 1)
                        {
                            //wait 4 minutes then 6 minutes then 8 minutes, eventually server will start responding again?
                            int sleepFor = consecutiveFailures * 2 * 60_000;
                            listener.OnNotify(this, new NotifyEventArgs(ProgressEventType.Warning, $"Sleeping for {sleepFor}ms due to {consecutiveFailures} consecutive failures"));

                            Task.Delay(sleepFor, cancellationToken.AbortToken)
                            .Wait(cancellationToken.AbortToken);
                        }
                    }

                    #endregion
                }
                finally
                {
                    server.Stop();
                }
            }

            return(Chunk);
        }
Пример #12
0
 public Task OnReceiveAssociationAcceptAsync(DicomAssociation association)
 {
     return(DicomClient.OnReceiveAssociationAcceptAsync(association));
 }
Пример #13
0
        /// <summary>
        ///     Blocks until the request is received so calling code doesn't have to deal with asynchrony (see the EventWaitHandle in TrySend).
        ///     Only the timeout is applied no Throtelling
        /// </summary>
        /// <param name="dicomRequest"></param>
        #region SendRequest
        private void SendRequest(DicomRequest dicomRequest, CancellationToken token)
        {
            var client = new DicomClient(_dicomConfiguration.RemoteAetUri.Host, _dicomConfiguration.RemoteAetUri.Port, false, _dicomConfiguration.LocalAetTitle, _dicomConfiguration.RemoteAetTitle);

            SendRequest(dicomRequest, client, token);
        }
Пример #14
0
 public Task OnReceiveAssociationRejectAsync(DicomRejectResult result, DicomRejectSource source, DicomRejectReason reason)
 {
     return(DicomClient.OnReceiveAssociationRejectAsync(result, source, reason));
 }
Пример #15
0
 /// <summary>
 ///    Throttle requests using W(O) = mO(t) + c where W is the wait period, O is the opertaion duration, m and c are positive constants
 ///    The request is added to the client which is unreleased at the end of this request send.
 /// </summary>
 ///
 #region ThrottleRequest
 public void ThrottleRequest(DicomRequest dicomRequest, DicomClient client, CancellationToken cancellationToken)
 {
     client.AddRequestAsync(dicomRequest).Wait(cancellationToken);
     ThrottleRequest(client, cancellationToken);
 }
Пример #16
0
 public Task OnReceiveAssociationReleaseResponseAsync()
 {
     return(DicomClient.OnReceiveAssociationReleaseResponseAsync());
 }
Пример #17
0
        /// <summary>
        ///     Blocks until the request is received so calling code doesn't have to deal with asynchrony (see the EventWaitHandle in TrySend).
        ///     Only the timeout is applied no Throtelling, the client is unreleased on return
        /// </summary>
        /// <param name="dicomRequest"></param>
        /// <param name="client"></param>

        #region SendRequest
        public void SendRequest(DicomRequest dicomRequest, DicomClient client, CancellationToken token)
        {
            client.AddRequestAsync(dicomRequest).Wait(token);
            SendRequest(client, token);
        }
Пример #18
0
 public Task OnConnectionClosedAsync(Exception exception)
 {
     return(DicomClient.OnConnectionClosedAsync(exception));
 }
Пример #19
0
 public Task OnReceiveAbortAsync(DicomAbortSource source, DicomAbortReason reason)
 {
     return(DicomClient.OnReceiveAbortAsync(source, reason));
 }
Пример #20
0
 public static Task <IDicomClientState> TransitionToSendingRequestsState(this DicomClient dicomClient,
                                                                         IInitialisationWithAssociationParameters parameters, DicomClientCancellation cancellation)
 {
     return(TransitionToSendingRequestsState(dicomClient, parameters, parameters.Association, cancellation));
 }
Пример #21
0
 protected override Task OnSendQueueEmptyAsync()
 {
     return(DicomClient.OnSendQueueEmptyAsync());
 }
Пример #22
0
        public static Task <IDicomClientState> TransitionToIdleState(this DicomClient dicomClient, DicomClientCancellation cancellation)
        {
            var idleState = new DicomClientIdleState(dicomClient);

            return(dicomClient.Transition(idleState, cancellation));
        }
Пример #23
0
 public Task OnRequestCompletedAsync(DicomRequest request, DicomResponse response)
 {
     return(DicomClient.OnRequestCompletedAsync(request, response));
 }
Пример #24
0
 public Task <DicomResponse> OnNEventReportRequestAsync(DicomNEventReportRequest request)
 {
     return(DicomClient.OnNEventReportRequestAsync(request));
 }
Пример #25
0
 public Task <DicomResponse> OnCStoreRequestAsync(DicomCStoreRequest request)
 {
     return(DicomClient.OnCStoreRequestAsync(request));
 }
Пример #26
0
 public Task OnRequestTimedOutAsync(DicomRequest request, TimeSpan timeout)
 {
     return(DicomClient.OnRequestTimedOutAsync(request, timeout));
 }
Пример #27
0
        public static Task <IDicomClientState> TransitionToConnectState(this DicomClient dicomClient, DicomClientCancellation cancellation)
        {
            var connectState = new DicomClientConnectState(dicomClient);

            return(dicomClient.Transition(connectState, cancellation));
        }
        public async Task ClientHandleNEventReport_SynchronousEvent()
        {
            var port = Ports.GetNext();

            using (DicomServer.Create <SimpleStorageComitmentProvider>(port))
            {
                DicomStatus status                   = null;
                int         verifiedInstances        = 0;
                DateTime    stampNActionResponse     = DateTime.MinValue;
                DateTime    stampNEventReportRequest = DateTime.MinValue;

                var dicomClient = new Client.DicomClient("127.0.0.1", port, false, "SCU", "ANY-SCP");

                var nActionDicomDataSet = new DicomDataset
                {
                    { DicomTag.TransactionUID, DicomUIDGenerator.GenerateDerivedFromUUID().UID },
                    {
                        DicomTag.ReferencedSOPSequence,
                        new DicomDataset()
                        {
                            { DicomTag.ReferencedSOPClassUID, "1.2.840.10008.5.1.4.1.1.1" },
                            { DicomTag.ReferencedSOPInstanceUID, "1.3.46.670589.30.2273540226.4.54" }
                        },
                        new DicomDataset()
                        {
                            { DicomTag.ReferencedSOPClassUID, "1.2.840.10008.5.1.4.1.1.1" },
                            { DicomTag.ReferencedSOPInstanceUID, "1.3.46.670589.30.2273540226.4.59" }
                        }
                    }
                };

                var nActionRequest = new DicomNActionRequest(DicomUID.StorageCommitmentPushModel,
                                                             DicomUID.StorageCommitmentPushModel, 1)
                {
                    Dataset            = nActionDicomDataSet,
                    OnResponseReceived = (DicomNActionRequest request, DicomNActionResponse response) =>
                    {
                        status = response.Status;
                        stampNActionResponse = DateTime.Now;
                    },
                };

                await dicomClient.AddRequestAsync(nActionRequest);

                dicomClient.OnNEventReportRequest = (eventReq) =>
                {
                    var refSopSequence = eventReq.Dataset.GetSequence(DicomTag.ReferencedSOPSequence);
                    foreach (var item in refSopSequence.Items)
                    {
                        verifiedInstances += 1;
                    }
                    stampNEventReportRequest = DateTime.Now;
                    return(Task.FromResult(new DicomNEventReportResponse(eventReq, DicomStatus.Success)));
                };

                dicomClient.AssociationLingerTimeoutInMs = (int)TimeSpan.FromSeconds(5).TotalMilliseconds;
                await dicomClient.SendAsync().ConfigureAwait(false);

                Assert.Equal(DicomStatus.Success, status);
                Assert.Equal(2, verifiedInstances);
                Assert.True(stampNActionResponse < stampNEventReportRequest);
            }
        }
Пример #29
0
 public static Task <IDicomClientState> TransitionToCompletedState(this DicomClient dicomClient, IInitialisationWithConnectionParameters parameters,
                                                                   DicomClientCancellation cancellation)
 {
     return(TransitionToCompletedState(dicomClient, parameters.Connection, cancellation));
 }
Пример #30
0
 public DicomClientConnection(DicomClient dicomClient, INetworkStream networkStream)
     : base(networkStream, dicomClient.FallbackEncoding, dicomClient.Logger)
 {
     DicomClient   = dicomClient;
     NetworkStream = networkStream;
 }