Skip to content

Commit 6097983

Browse files
authored
Update fo-dicom to 5.0.3 (#164)
* Update fo-dicom to 5.0.3 and handle breaking changes * Make validation on DICOM to JSON serialization configurable Signed-off-by: Victor Chang <[email protected]>
1 parent 49f56f2 commit 6097983

21 files changed

+167
-67
lines changed

doc/dependency_decisions.yml

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -804,6 +804,13 @@
804804
:versions:
805805
- 17.3.1
806806
:when: 2022-09-01 23:06:18.619013325 Z
807+
- - :approve
808+
- Microsoft.Toolkit.HighPerformance
809+
- :who: mocsharp
810+
:why: MIT (https://github.com/CommunityToolkit/WindowsCommunityToolkit/raw/main/License.md)
811+
:versions:
812+
- 7.1.2
813+
:when: 2022-09-20 00:42:18.619013325 Z
807814
- - :approve
808815
- Microsoft.Win32.Primitives
809816
- :who: mocsharp
@@ -1866,7 +1873,7 @@
18661873
- :who: mocsharp
18671874
:why: Microsoft Public License (https://github.com/fo-dicom/fo-dicom/raw/development/License.txt)
18681875
:versions:
1869-
- 5.0.2
1876+
- 5.0.3
18701877
:when: 2022-08-16 23:07:29.574869349 Z
18711878
- - :approve
18721879
- runtime.any.System.Collections
@@ -2400,4 +2407,3 @@
24002407
:versions:
24012408
- 4.0.1
24022409
:when: 2022-08-16 23:10:21.184627612 Z
2403-

docker-compose/docker-compose.dev.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,8 @@ services:
3939
- ./.run/minio/data:/data
4040
- ./.run/minio/config:/root/.minio
4141
ports:
42-
- "9000:9000"
42+
- 9000:9000
43+
- 9001:9001
4344
environment:
4445
MINIO_ROOT_USER: minioadmin
4546
MINIO_ROOT_PASSWORD: minioadmin

docs/compliance/third-party-licenses.md

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6045,6 +6045,41 @@ SOFTWARE.
60456045
</details>
60466046

60476047

6048+
<details>
6049+
<summary>Microsoft.Toolkit.HighPerformance 7.1.2</summary>
6050+
6051+
## Microsoft.Toolkit.HighPerformance
6052+
6053+
- Version: 7.1.2
6054+
- Authors: Microsoft
6055+
- Owners: Microsoft.Toolkit,dotnetfoundation
6056+
- Project URL: https://dot.net/
6057+
- Source: [NuGet](https://www.nuget.org/packages/Microsoft.Toolkit.HighPerformance/7.1.2)
6058+
- License: [MIT]( https://github.com/CommunityToolkit/WindowsCommunityToolkit/raw/main/License.md)
6059+
6060+
6061+
```
6062+
# Windows Community Toolkit
6063+
6064+
Copyright © .NET Foundation and Contributors
6065+
6066+
All rights reserved.
6067+
6068+
## MIT License (MIT)
6069+
6070+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”),
6071+
to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
6072+
and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6073+
6074+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6075+
6076+
THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
6077+
FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
6078+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
6079+
IN THE SOFTWARE.
6080+
```
6081+
6082+
</details>
60486083
<details>
60496084
<summary>Microsoft.Win32.Primitives 4.3.0</summary>
60506085

@@ -26864,14 +26899,14 @@ SOFTWARE.
2686426899

2686526900

2686626901
<details>
26867-
<summary>fo-dicom 5.0.2</summary>
26902+
<summary>fo-dicom 5.0.3</summary>
2686826903

2686926904
## fo-dicom
2687026905

26871-
- Version: 5.0.2
26906+
- Version: 5.0.3
2687226907
- Authors: fo-dicom contributors
2687326908
- Project URL: https://github.com/fo-dicom/fo-dicom
26874-
- Source: [NuGet](https://www.nuget.org/packages/fo-dicom/5.0.2)
26909+
- Source: [NuGet](https://www.nuget.org/packages/fo-dicom/5.0.3)
2687526910
- License: [Microsoft Public License](https://github.com/fo-dicom/fo-dicom/raw/development/License.txt)
2687626911

2687726912

@@ -39929,4 +39964,4 @@ The above copyright notice and this permission notice (including the next paragr
3992939964
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL _____ BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
3993039965
```
3993139966

39932-
</details>
39967+
</details>

src/Common/Monai.Deploy.InformaticsGateway.Common.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828

2929
<ItemGroup>
3030
<PackageReference Include="Ardalis.GuardClauses" Version="4.0.1" />
31-
<PackageReference Include="fo-dicom" Version="5.0.2" />
31+
<PackageReference Include="fo-dicom" Version="5.0.3" />
3232
<PackageReference Include="GitVersion.MsBuild" Version="5.10.3">
3333
<PrivateAssets>All</PrivateAssets>
3434
</PackageReference>

src/Configuration/DicomConfiguration.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,5 +41,11 @@ public class DicomConfiguration
4141
/// </summary>
4242
[ConfigurationKeyName("writeDicomJson")]
4343
public DicomJsonOptions WriteDicomJson { get; set; } = DicomJsonOptions.IgnoreOthers;
44+
45+
/// <summary>
46+
/// Gets or sets whether to automatically validate the DICOM values when serializing to JSON.
47+
/// Defaults to False.
48+
/// </summary>
49+
public bool ValidateDicomOnSerialization { get; set; } = false;
4450
}
4551
}

src/DicomWebClient/CLI/Monai.Deploy.InformaticsGateway.DicomWeb.Client.CLI.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535

3636
<ItemGroup>
3737
<PackageReference Include="ConsoleAppFramework" Version="4.2.2" />
38-
<PackageReference Include="fo-dicom" Version="5.0.2" />
38+
<PackageReference Include="fo-dicom" Version="5.0.3" />
3939
<PackageReference Include="Microsoft.Extensions.Http" Version="6.0.0" />
4040
</ItemGroup>
4141
</Project>

src/DicomWebClient/Monai.Deploy.InformaticsGateway.DicomWeb.Client.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@
4343

4444
<ItemGroup>
4545
<PackageReference Include="Ardalis.GuardClauses" Version="4.0.1" />
46-
<PackageReference Include="fo-dicom" Version="5.0.2" />
46+
<PackageReference Include="fo-dicom" Version="5.0.3" />
4747
<PackageReference Include="GitVersion.MsBuild" Version="5.10.3">
4848
<PrivateAssets>All</PrivateAssets>
4949
</PackageReference>

src/InformaticsGateway/Common/DicomExtensions.cs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,12 +52,15 @@ public static DicomTransferSyntax[] ToDicomTransferSyntaxArray(this IEnumerable<
5252
return dicomTransferSyntaxes.ToArray();
5353
}
5454

55-
public static string ToJson(this DicomFile dicomFile, DicomJsonOptions dicomJsonOptions)
55+
public static string ToJson(this DicomFile dicomFile, DicomJsonOptions dicomJsonOptions, bool validateDicom)
5656
{
5757
Guard.Against.Null(dicomFile, nameof(dicomFile));
5858

5959
var options = new JsonSerializerOptions();
60-
options.Converters.Add(new DicomJsonConverter(writeTagsAsKeywords: false, autoValidate: true));
60+
options.Converters.Add(new DicomJsonConverter(
61+
writeTagsAsKeywords: false,
62+
autoValidate: validateDicom,
63+
numberSerializationMode: validateDicom ? NumberSerializationMode.AsNumber : NumberSerializationMode.PreferablyAsNumber));
6164
options.WriteIndented = false;
6265

6366
if (dicomJsonOptions == DicomJsonOptions.Complete)

src/InformaticsGateway/Monai.Deploy.InformaticsGateway.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
<ItemGroup>
3535
<PackageReference Include="Ardalis.GuardClauses" Version="4.0.1" />
3636
<PackageReference Include="DotNext.Threading" Version="4.7.1" />
37-
<PackageReference Include="fo-dicom" Version="5.0.2" />
37+
<PackageReference Include="fo-dicom" Version="5.0.3" />
3838
<PackageReference Include="Karambolo.Extensions.Logging.File" Version="3.3.1" />
3939
<PackageReference Include="HL7-dotnetcore" Version="2.29.0" />
4040
<PackageReference Include="GitVersion.MsBuild" Version="5.10.3">

src/InformaticsGateway/Services/Connectors/DataRetrievalService.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -509,7 +509,7 @@ private async Task RetrieveInstances(string transactionId, IDicomWebClient dicom
509509
}
510510

511511
var dicomFileStorageMetadata = SaveFile(transactionId, file, uids);
512-
await dicomFileStorageMetadata.SetDataStreams(file, file.ToJson(_options.Value.Dicom.WriteDicomJson)).ConfigureAwait(false);
512+
await dicomFileStorageMetadata.SetDataStreams(file, file.ToJson(_options.Value.Dicom.WriteDicomJson, _options.Value.Dicom.ValidateDicomOnSerialization)).ConfigureAwait(false);
513513
retrievedInstance.Add(uids.Identifier, dicomFileStorageMetadata);
514514
count++;
515515
}
@@ -539,7 +539,7 @@ private async Task SaveFiles(string transactionId, IAsyncEnumerable<DicomFile> f
539539
}
540540

541541
var dicomFileStorageMetadata = SaveFile(transactionId, file, uids);
542-
await dicomFileStorageMetadata.SetDataStreams(file, file.ToJson(_options.Value.Dicom.WriteDicomJson)).ConfigureAwait(false);
542+
await dicomFileStorageMetadata.SetDataStreams(file, file.ToJson(_options.Value.Dicom.WriteDicomJson, _options.Value.Dicom.ValidateDicomOnSerialization)).ConfigureAwait(false);
543543
retrievedInstance.Add(uids.Identifier, dicomFileStorageMetadata);
544544
}
545545
}

src/InformaticsGateway/Services/DicomWeb/IStreamsWriter.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ private async Task SaveInstance(Stream stream, string studyInstanceUid, string w
165165
dicomInfo.SetWorkflows(workflowName);
166166
}
167167

168-
await dicomInfo.SetDataStreams(dicomFile, dicomFile.ToJson(_configuration.Value.Dicom.WriteDicomJson)).ConfigureAwait(false);
168+
await dicomInfo.SetDataStreams(dicomFile, dicomFile.ToJson(_configuration.Value.Dicom.WriteDicomJson, _configuration.Value.Dicom.ValidateDicomOnSerialization)).ConfigureAwait(false);
169169
_uploadQueue.Queue(dicomInfo);
170170

171171
// for DICOMweb, use correlation ID as the grouping key

src/InformaticsGateway/Services/Export/ScuExportService.cs

Lines changed: 29 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,6 @@ private async Task HandleDesination(ExportRequestDataMessage exportRequestData,
7878
Guard.Against.Null(exportRequestData, nameof(exportRequestData));
7979

8080
var manualResetEvent = new ManualResetEvent(false);
81-
IDicomClient client = null;
8281
DestinationApplicationEntity destination = null;
8382
try
8483
{
@@ -93,38 +92,38 @@ private async Task HandleDesination(ExportRequestDataMessage exportRequestData,
9392

9493
try
9594
{
96-
client = DicomClientFactory.Create(
97-
destination.HostIp,
98-
destination.Port,
99-
false,
100-
_configuration.Value.Dicom.Scu.AeTitle,
101-
destination.AeTitle);
102-
103-
client.AssociationAccepted += (sender, args) => _logger.AssociationAccepted();
104-
client.AssociationRejected += (sender, args) => _logger.AssociationRejected();
105-
client.AssociationReleased += (sender, args) => _logger.AssociationReleased();
106-
client.ServiceOptions.LogDataPDUs = _configuration.Value.Dicom.Scu.LogDataPdus;
107-
client.ServiceOptions.LogDimseDatasets = _configuration.Value.Dicom.Scu.LogDimseDatasets;
108-
109-
client.NegotiateAsyncOps();
110-
if (GenerateRequests(exportRequestData, client, manualResetEvent))
111-
{
112-
await Policy
113-
.Handle<Exception>()
114-
.WaitAndRetryAsync(
115-
_configuration.Value.Export.Retries.RetryDelays,
116-
(exception, timeSpan, retryCount, context) =>
117-
{
118-
_logger.DimseExportErrorWithRetry(timeSpan, retryCount, exception);
119-
})
120-
.ExecuteAsync(async () =>
95+
await Policy
96+
.Handle<Exception>()
97+
.WaitAndRetryAsync(
98+
_configuration.Value.Export.Retries.RetryDelays,
99+
(exception, timeSpan, retryCount, context) =>
100+
{
101+
_logger.DimseExportErrorWithRetry(timeSpan, retryCount, exception);
102+
})
103+
.ExecuteAsync(async () =>
104+
{
105+
var client = DicomClientFactory.Create(
106+
destination.HostIp,
107+
destination.Port,
108+
false,
109+
_configuration.Value.Dicom.Scu.AeTitle,
110+
destination.AeTitle);
111+
112+
client.AssociationAccepted += (sender, args) => _logger.AssociationAccepted();
113+
client.AssociationRejected += (sender, args) => _logger.AssociationRejected();
114+
client.AssociationReleased += (sender, args) => _logger.AssociationReleased();
115+
client.ServiceOptions.LogDataPDUs = _configuration.Value.Dicom.Scu.LogDataPdus;
116+
client.ServiceOptions.LogDimseDatasets = _configuration.Value.Dicom.Scu.LogDimseDatasets;
117+
118+
client.NegotiateAsyncOps();
119+
if (await GenerateRequestsAsync(exportRequestData, client, manualResetEvent))
121120
{
122121
_logger.DimseExporting(destination.AeTitle, destination.HostIp, destination.Port);
123122
await client.SendAsync(cancellationToken).ConfigureAwait(false);
124123
manualResetEvent.WaitOne();
125124
_logger.DimseExportComplete(destination.AeTitle);
126-
}).ConfigureAwait(false);
127-
}
125+
}
126+
}).ConfigureAwait(false);
128127
}
129128
catch (Exception ex)
130129
{
@@ -151,7 +150,7 @@ private DestinationApplicationEntity LookupDestination(string destinationName)
151150
return destination;
152151
}
153152

154-
private bool GenerateRequests(
153+
private async Task<bool> GenerateRequestsAsync(
155154
ExportRequestDataMessage exportRequestData,
156155
IDicomClient client,
157156
ManualResetEvent manualResetEvent)
@@ -177,7 +176,7 @@ private bool GenerateRequests(
177176
manualResetEvent.Set();
178177
};
179178

180-
client.AddRequestAsync(request).ConfigureAwait(false);
179+
await client.AddRequestAsync(request).ConfigureAwait(false);
181180
return true;
182181
}
183182
catch (Exception exception)

src/InformaticsGateway/Services/Scp/ApplicationEntityHandler.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ internal class ApplicationEntityHandler : IDisposable, IApplicationEntityHandler
4141

4242
private MonaiApplicationEntity _configuration;
4343
private DicomJsonOptions _dicomJsonOptions;
44+
private bool _validateDicomValueOnJsonSerialization;
4445
private bool _disposedValue;
4546

4647
public ApplicationEntityHandler(
@@ -55,12 +56,13 @@ public ApplicationEntityHandler(
5556
_uploadQueue = _serviceScope.ServiceProvider.GetService<IObjectUploadQueue>() ?? throw new ServiceNotFoundException(nameof(IObjectUploadQueue));
5657
}
5758

58-
public void Configure(MonaiApplicationEntity monaiApplicationEntity, DicomJsonOptions dicomJsonOptions)
59+
public void Configure(MonaiApplicationEntity monaiApplicationEntity, DicomJsonOptions dicomJsonOptions, bool validateDicomValuesOnJsonSerialization)
5960
{
6061
Guard.Against.Null(monaiApplicationEntity, nameof(monaiApplicationEntity));
6162

6263
_configuration = monaiApplicationEntity;
6364
_dicomJsonOptions = dicomJsonOptions;
65+
_validateDicomValueOnJsonSerialization = validateDicomValuesOnJsonSerialization;
6466
}
6567

6668
public async Task HandleInstanceAsync(DicomCStoreRequest request, string calledAeTitle, string callingAeTitle, Guid associationId, StudySerieSopUids uids)
@@ -93,7 +95,7 @@ public async Task HandleInstanceAsync(DicomCStoreRequest request, string calledA
9395
dicomInfo.SetWorkflows(_configuration.Workflows.ToArray());
9496
}
9597

96-
await dicomInfo.SetDataStreams(request.File, request.File.ToJson(_dicomJsonOptions)).ConfigureAwait(false);
98+
await dicomInfo.SetDataStreams(request.File, request.File.ToJson(_dicomJsonOptions, _validateDicomValueOnJsonSerialization)).ConfigureAwait(false);
9799
_uploadQueue.Queue(dicomInfo);
98100

99101
var dicomTag = FellowOakDicom.DicomTag.Parse(_configuration.Grouping);

src/InformaticsGateway/Services/Scp/ApplicationEntityManager.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ private void AddNewAeTitle(MonaiApplicationEntity entity)
143143
{
144144
var scope = _serviceScopeFactory.CreateScope();
145145
var handler = scope.ServiceProvider.GetService<IApplicationEntityHandler>() ?? throw new ServiceNotFoundException(nameof(IApplicationEntityHandler));
146-
handler.Configure(entity, Configuration.Value.Dicom.WriteDicomJson);
146+
handler.Configure(entity, Configuration.Value.Dicom.WriteDicomJson, Configuration.Value.Dicom.ValidateDicomOnSerialization);
147147

148148
if (!_aeTitles.TryAdd(entity.AeTitle, handler))
149149
{

src/InformaticsGateway/Services/Scp/IApplicationEntityHandler.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ namespace Monai.Deploy.InformaticsGateway.Services.Scp
2525
{
2626
internal interface IApplicationEntityHandler
2727
{
28-
void Configure(MonaiApplicationEntity monaiApplicationEntity, DicomJsonOptions dicomJsonOptions);
28+
void Configure(MonaiApplicationEntity monaiApplicationEntity, DicomJsonOptions dicomJsonOptions, bool validateDicomValuesOnJsonSerialization);
2929

3030
Task HandleInstanceAsync(DicomCStoreRequest request, string calledAeTitle, string callingAeTitle, Guid associationId, StudySerieSopUids uids);
3131
}

src/InformaticsGateway/Services/Scp/ScpServiceInternal.cs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,6 @@
2121
using System.Threading;
2222
using System.Threading.Tasks;
2323
using FellowOakDicom;
24-
using FellowOakDicom.Imaging.Codec;
25-
using FellowOakDicom.Log;
2624
using FellowOakDicom.Network;
2725
using Monai.Deploy.InformaticsGateway.Api;
2826
using Monai.Deploy.InformaticsGateway.Common;
@@ -44,8 +42,8 @@ internal class ScpServiceInternal :
4442
private IDisposable _loggerScope;
4543
private Guid _associationId;
4644

47-
public ScpServiceInternal(INetworkStream stream, Encoding fallbackEncoding, FellowOakDicom.Log.ILogger log, ILogManager logManager, INetworkManager network, ITranscoderManager transcoder)
48-
: base(stream, fallbackEncoding, log, logManager, network, transcoder)
45+
public ScpServiceInternal(INetworkStream stream, Encoding fallbackEncoding, FellowOakDicom.Log.ILogger log, DicomServiceDependencies dicomServiceDependencies)
46+
: base(stream, fallbackEncoding, log, dicomServiceDependencies)
4947
{
5048
}
5149

0 commit comments

Comments
 (0)