diff --git a/CustomAnalysisRules.ruleset b/CustomAnalysisRules.ruleset
index af324a764a..342d390ef1 100644
--- a/CustomAnalysisRules.ruleset
+++ b/CustomAnalysisRules.ruleset
@@ -1,5 +1,5 @@
-
+
@@ -16,6 +16,8 @@
+
+
@@ -48,4 +50,4 @@
-
+
\ No newline at end of file
diff --git a/Directory.Build.props b/Directory.Build.props
index baa783685b..174c7a2c62 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -18,7 +18,7 @@
true
https://github.com/microsoft/fhir-server/
$(MSBuildThisFileDirectory)\CodeCoverage.runsettings
- net7.0;net6.0
+ net8.0;net6.0
true
true
diff --git a/Directory.Packages.props b/Directory.Packages.props
index 91375b060f..297d59d0eb 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -1,16 +1,16 @@
- 7.0.29
+ 7.1.5
4.3.0
-
+
-
+
-
+
@@ -18,9 +18,9 @@
-
+
- 7.0.12
+ 8.0.0
@@ -32,7 +32,7 @@
-
+
@@ -61,21 +61,22 @@
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
-
-
-
+
+
+
+
@@ -108,9 +109,9 @@
-
+
-
+
@@ -119,7 +120,7 @@
-
+
-
\ No newline at end of file
+
diff --git a/build/.vsts-PRInternalChecks-azureBuild-pipeline.yml b/build/.vsts-PRInternalChecks-azureBuild-pipeline.yml
index 24bd7d438b..92961612b2 100644
--- a/build/.vsts-PRInternalChecks-azureBuild-pipeline.yml
+++ b/build/.vsts-PRInternalChecks-azureBuild-pipeline.yml
@@ -32,7 +32,7 @@ jobs:
displayName: dotnet build
inputs:
projects: '**/*.sln'
- arguments: --configuration ${{ parameters.BuildConfiguration }} --version-suffix $(build.buildnumber) /warnaserror -f net7.0
+ arguments: --configuration ${{ parameters.BuildConfiguration }} --version-suffix $(build.buildnumber) /warnaserror -f net8.0
- task: AutoApplicability@1
displayName: Run AutoApplicability
continueOnError: True
diff --git a/build/build-variables.yml b/build/build-variables.yml
index f5b4d150f5..7f28b89720 100644
--- a/build/build-variables.yml
+++ b/build/build-variables.yml
@@ -3,7 +3,7 @@
variables:
buildConfiguration: 'Release'
- defaultBuildFramework: 'net7.0'
+ defaultBuildFramework: 'net8.0'
azureSubscriptionEndpoint: 'docker-build'
azureContainerRegistryName: 'healthplatformregistry'
azureContainerRegistry: '$(azureContainerRegistryName).azurecr.io'
diff --git a/build/ci-pipeline.yml b/build/ci-pipeline.yml
index 66b76f9255..de6f125dd8 100644
--- a/build/ci-pipeline.yml
+++ b/build/ci-pipeline.yml
@@ -65,7 +65,7 @@ stages:
majorMinorPatch: $[stageDependencies.UpdateVersion.Semver.outputs['SetVariablesFromGitVersion.majorMinorPatch']]
nuGetVersion: $[stageDependencies.UpdateVersion.Semver.outputs['SetVariablesFromGitVersion.nuGetVersion']]
jobs:
- - job: Windows_dotnet7
+ - job: Windows_dotnet8
pool:
name: '$(DefaultWindowsPool)'
steps:
diff --git a/build/docker/Dockerfile b/build/docker/Dockerfile
index e99e09a7e0..35aa37800b 100644
--- a/build/docker/Dockerfile
+++ b/build/docker/Dockerfile
@@ -1,4 +1,4 @@
-FROM mcr.microsoft.com/dotnet/sdk:7.0.402-cbl-mariner2.0 AS build
+FROM mcr.microsoft.com/dotnet/sdk:8.0.100-1-cbl-mariner2.0 AS build
ARG FHIR_VERSION
ARG ASSEMBLY_VER
@@ -67,9 +67,9 @@ RUN dotnet restore ./src/Microsoft.Health.Fhir.${FHIR_VERSION}.Web/Microsoft.Hea
COPY . .
-RUN dotnet publish /repo/src/Microsoft.Health.Fhir.${FHIR_VERSION}.Web/Microsoft.Health.Fhir.${FHIR_VERSION}.Web.csproj -c Release -o "/build" --no-restore -p:AssemblyVersion="${ASSEMBLY_VER}" -p:FileVersion="${ASSEMBLY_VER}" -p:Version="${ASSEMBLY_VER}" -f net7.0
+RUN dotnet publish /repo/src/Microsoft.Health.Fhir.${FHIR_VERSION}.Web/Microsoft.Health.Fhir.${FHIR_VERSION}.Web.csproj -c Release -o "/build" --no-restore -p:AssemblyVersion="${ASSEMBLY_VER}" -p:FileVersion="${ASSEMBLY_VER}" -p:Version="${ASSEMBLY_VER}" -f net8.0
-FROM mcr.microsoft.com/dotnet/aspnet:7.0.12-cbl-mariner2.0 AS runtime
+FROM mcr.microsoft.com/dotnet/aspnet:8.0.0-cbl-mariner2.0 AS runtime
ARG FHIR_VERSION
diff --git a/build/dotnet6-compat/global.json b/build/dotnet6-compat/global.json
index abde2ccf72..0c1333116f 100644
--- a/build/dotnet6-compat/global.json
+++ b/build/dotnet6-compat/global.json
@@ -1,5 +1,5 @@
{
"sdk": {
- "version": "6.0.415"
+ "version": "6.0.417"
}
}
diff --git a/build/jobs/analyze.yml b/build/jobs/analyze.yml
index cfc7ee368e..5ad0110a60 100644
--- a/build/jobs/analyze.yml
+++ b/build/jobs/analyze.yml
@@ -108,7 +108,7 @@ steps:
inputs:
userProvideBuildInfo: 'msBuildInfo'
msBuildArchitecture: 'DotNetCore'
- msBuildCommandline: 'dotnet build $(Build.SourcesDirectory)/Microsoft.Health.Fhir.sln --configuration $(buildConfiguration) -p:ContinuousIntegrationBuild=true -f net7.0'
+ msBuildCommandline: 'dotnet build $(Build.SourcesDirectory)/Microsoft.Health.Fhir.sln --configuration $(buildConfiguration) -p:ContinuousIntegrationBuild=true -f net8.0'
- task: BinSkim@4
inputs:
diff --git a/build/pr-pipeline.yml b/build/pr-pipeline.yml
index 43dd31a89c..d42658a04e 100644
--- a/build/pr-pipeline.yml
+++ b/build/pr-pipeline.yml
@@ -48,7 +48,7 @@ stages:
majorMinorPatch: $[stageDependencies.UpdateVersion.Semver.outputs['SetVariablesFromGitVersion.majorMinorPatch']]
nuGetVersion: $[stageDependencies.UpdateVersion.Semver.outputs['SetVariablesFromGitVersion.nuGetVersion']]
jobs:
- - job: Windows_dotnet7
+ - job: Windows_dotnet8
pool:
name: '$(DefaultWindowsPool)'
steps:
diff --git a/global.json b/global.json
index 34a2bc8ad8..48e1c84489 100644
--- a/global.json
+++ b/global.json
@@ -1,5 +1,5 @@
{
"sdk": {
- "version": "7.0.402"
+ "version": "8.0.100"
}
}
diff --git a/src/Microsoft.Health.Fhir.Api/Features/ApiNotifications/ApiNotificationMiddleware.cs b/src/Microsoft.Health.Fhir.Api/Features/ApiNotifications/ApiNotificationMiddleware.cs
index cd7a2d2a3c..2fd4f8efba 100644
--- a/src/Microsoft.Health.Fhir.Api/Features/ApiNotifications/ApiNotificationMiddleware.cs
+++ b/src/Microsoft.Health.Fhir.Api/Features/ApiNotifications/ApiNotificationMiddleware.cs
@@ -57,38 +57,36 @@ protected virtual async Task PublishNotificationAsync(HttpContext context, Reque
{
var apiNotification = new ApiResponseNotification();
- using (var timer = _logger.BeginTimedScope(nameof(ApiNotificationMiddleware)) as ActionTimer)
+ using ActionTimer timer = _logger.BeginTimedScope(nameof(ApiNotificationMiddleware));
+ try
{
+ await next(context);
+ }
+ finally
+ {
+ apiNotification.Latency = timer.ElapsedTime;
+
try
{
- await next(context);
- }
- finally
- {
- apiNotification.Latency = timer.ElapsedTime;
+ IFhirRequestContext fhirRequestContext = _fhirRequestContextAccessor.RequestContext;
- try
+ // For now, we will only emit metrics for audited actions (e.g., metadata will not emit metrics).
+ if (fhirRequestContext?.AuditEventType != null)
{
- IFhirRequestContext fhirRequestContext = _fhirRequestContextAccessor.RequestContext;
+ apiNotification.Authentication = fhirRequestContext.Principal?.Identity.AuthenticationType;
+ apiNotification.FhirOperation = fhirRequestContext.AuditEventType;
+ apiNotification.Protocol = context.Request.Scheme;
+ apiNotification.ResourceType = fhirRequestContext.ResourceType;
+ apiNotification.StatusCode = (HttpStatusCode)context.Response.StatusCode;
- // For now, we will only emit metrics for audited actions (e.g., metadata will not emit metrics).
- if (fhirRequestContext?.AuditEventType != null)
- {
- apiNotification.Authentication = fhirRequestContext.Principal?.Identity.AuthenticationType;
- apiNotification.FhirOperation = fhirRequestContext.AuditEventType;
- apiNotification.Protocol = context.Request.Scheme;
- apiNotification.ResourceType = fhirRequestContext.ResourceType;
- apiNotification.StatusCode = (HttpStatusCode)context.Response.StatusCode;
-
- await _mediator.Publish(apiNotification, CancellationToken.None);
- }
- }
- catch (Exception e)
- {
- // Failures in publishing API notifications should not cause the API to return an error.
- _logger.LogCritical(e, "Failure while publishing API notification.");
+ await _mediator.Publish(apiNotification, CancellationToken.None);
}
}
+ catch (Exception e)
+ {
+ // Failures in publishing API notifications should not cause the API to return an error.
+ _logger.LogCritical(e, "Failure while publishing API notification.");
+ }
}
}
}
diff --git a/src/Microsoft.Health.Fhir.Api/Features/Audit/AuditHelper.cs b/src/Microsoft.Health.Fhir.Api/Features/Audit/AuditHelper.cs
index 4a0f2ce931..a2e37db190 100644
--- a/src/Microsoft.Health.Fhir.Api/Features/Audit/AuditHelper.cs
+++ b/src/Microsoft.Health.Fhir.Api/Features/Audit/AuditHelper.cs
@@ -146,9 +146,9 @@ private void Log(AuditAction auditAction, HttpStatusCode? statusCode, HttpContex
/// Return all the values of constants of the specified type
///
/// List of constant values
- private static IList GetAnonymousOperations()
+ private static List GetAnonymousOperations()
{
- IList anonymousOperations = new List();
+ List anonymousOperations = new List();
FieldInfo[] fieldInfos = typeof(FhirAnonymousOperationType).GetFields(BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy);
// Go through the list and only pick out the constants
diff --git a/src/Microsoft.Health.Fhir.Api/Features/Binders/DictionaryExpansionConfigurationProvider.cs b/src/Microsoft.Health.Fhir.Api/Features/Binders/DictionaryExpansionConfigurationProvider.cs
index 72164af0dd..e203040b32 100644
--- a/src/Microsoft.Health.Fhir.Api/Features/Binders/DictionaryExpansionConfigurationProvider.cs
+++ b/src/Microsoft.Health.Fhir.Api/Features/Binders/DictionaryExpansionConfigurationProvider.cs
@@ -70,7 +70,7 @@ public static bool TryParseDictionaryJson(string value, out Dictionary SetContentLocationHeader(th
var url = urlResolver.ResolveOperationResultUrl(operationName, id);
- result.Headers.Add(HeaderNames.ContentLocation, url.ToString());
+ result.Headers[HeaderNames.ContentLocation] = url.ToString();
return result;
}
@@ -31,7 +31,7 @@ public static ResourceActionResult SetContentTypeHeader(this R
EnsureArg.IsNotNull(result, nameof(result));
EnsureArg.IsNotNullOrWhiteSpace(contentTypeValue, nameof(contentTypeValue));
- result.Headers.Add(HeaderNames.ContentType, contentTypeValue);
+ result.Headers[HeaderNames.ContentType] = contentTypeValue;
return result;
}
}
diff --git a/src/Microsoft.Health.Fhir.Api/Features/Throttling/ThrottlingMiddleware.cs b/src/Microsoft.Health.Fhir.Api/Features/Throttling/ThrottlingMiddleware.cs
index 6732d908d1..947f39ff9d 100644
--- a/src/Microsoft.Health.Fhir.Api/Features/Throttling/ThrottlingMiddleware.cs
+++ b/src/Microsoft.Health.Fhir.Api/Features/Throttling/ThrottlingMiddleware.cs
@@ -17,6 +17,7 @@
using Microsoft.Health.Fhir.Api.Configs;
using Microsoft.Health.Fhir.Api.Features.Headers;
using Microsoft.Health.Fhir.Core.Configs;
+using Microsoft.Health.Fhir.Core.Extensions;
using Microsoft.Health.Fhir.Core.Features;
using Microsoft.Health.Fhir.Core.Features.Operations;
@@ -315,7 +316,7 @@ private async Task Return429FromRequestRateExceededException(RequestRateExceeded
public async ValueTask DisposeAsync()
{
- _cancellationTokenSource.Cancel();
+ await _cancellationTokenSource.CancelAsync();
await _samplingLoopTask;
_cancellationTokenSource.Dispose();
_samplingLoopTask.Dispose();
diff --git a/src/Microsoft.Health.Fhir.Api/Registration/FhirServerApplicationBuilderExtensions.cs b/src/Microsoft.Health.Fhir.Api/Registration/FhirServerApplicationBuilderExtensions.cs
index f336bdccfb..da761c230e 100644
--- a/src/Microsoft.Health.Fhir.Api/Registration/FhirServerApplicationBuilderExtensions.cs
+++ b/src/Microsoft.Health.Fhir.Api/Registration/FhirServerApplicationBuilderExtensions.cs
@@ -61,10 +61,7 @@ public PathBaseMiddleware(RequestDelegate next, PathString pathBase)
public async Task Invoke(HttpContext context)
{
- if (context == null)
- {
- throw new ArgumentNullException(nameof(context));
- }
+ ArgumentNullException.ThrowIfNull(context, nameof(context));
var originalPathBase = context.Request.PathBase;
context.Request.PathBase = originalPathBase.Add(_pathBase);
diff --git a/src/Microsoft.Health.Fhir.Azure/AnonymizationConfigurationArtifactProvider.cs b/src/Microsoft.Health.Fhir.Azure/AnonymizationConfigurationArtifactProvider.cs
index 185774c3cb..7a4ddb91c5 100644
--- a/src/Microsoft.Health.Fhir.Azure/AnonymizationConfigurationArtifactProvider.cs
+++ b/src/Microsoft.Health.Fhir.Azure/AnonymizationConfigurationArtifactProvider.cs
@@ -4,6 +4,7 @@
// -------------------------------------------------------------------------------------------------
using System;
+using System.Collections.Generic;
using System.Globalization;
using System.IdentityModel.Tokens.Jwt;
using System.IO;
@@ -39,7 +40,7 @@ public class AnonymizationConfigurationArtifactProvider : IArtifactProvider, IDi
private readonly ILogger _logger;
private readonly IExportClientInitializer _exportClientInitializer;
private readonly ExportJobConfiguration _exportJobConfiguration;
- private IOciArtifactProvider _anonymizationConfigurationCollectionProvider;
+ private OciArtifactProvider _anonymizationConfigurationCollectionProvider;
private IContainerRegistryTokenProvider _containerRegistryTokenProvider;
private BlobServiceClient _blobClient;
@@ -113,26 +114,24 @@ async Task TokenEntryFactory(ICacheEntry entry)
throw new AnonymizationConfigurationFetchException(Resources.AnonymizationConfigurationCollectionTooLarge);
}
- using (var str = new MemoryStream(acrImage.Blobs[i].Content))
+ using var str = new MemoryStream(acrImage.Blobs[i].Content);
+ Dictionary blobsDict = StreamUtility.DecompressFromTarGz(str);
+ if (!blobsDict.TryGetValue(configName, out byte[] value))
{
- var blobsDict = StreamUtility.DecompressFromTarGz(str);
- if (!blobsDict.ContainsKey(configName))
+ continue;
+ }
+ else
+ {
+ configFound = true;
+ if (CheckConfigurationIsTooLarge(value.LongLength))
{
- continue;
+ throw new AnonymizationConfigurationFetchException(Resources.AnonymizationConfigurationTooLarge);
}
- else
+
+ using (var config = new MemoryStream(value))
{
- configFound = true;
- if (CheckConfigurationIsTooLarge(blobsDict[configName].LongLength))
- {
- throw new AnonymizationConfigurationFetchException(Resources.AnonymizationConfigurationTooLarge);
- }
-
- using (var config = new MemoryStream(blobsDict[configName]))
- {
- await config.CopyToAsync(targetStream, cancellationToken);
- break;
- }
+ await config.CopyToAsync(targetStream, cancellationToken);
+ break;
}
}
}
diff --git a/src/Microsoft.Health.Fhir.Azure/IntegrationDataStore/AzureAccessTokenClientInitializerV2.cs b/src/Microsoft.Health.Fhir.Azure/IntegrationDataStore/AzureAccessTokenClientInitializerV2.cs
index 01e34f1c59..ee92f52a03 100644
--- a/src/Microsoft.Health.Fhir.Azure/IntegrationDataStore/AzureAccessTokenClientInitializerV2.cs
+++ b/src/Microsoft.Health.Fhir.Azure/IntegrationDataStore/AzureAccessTokenClientInitializerV2.cs
@@ -87,7 +87,7 @@ public Task GetAuthorizedClientAsync(IntegrationDataStoreConf
}
}
- private static TokenCredential CreateDefaultTokenCredential()
+ private static DefaultAzureCredential CreateDefaultTokenCredential()
{
return new DefaultAzureCredential();
}
diff --git a/src/Microsoft.Health.Fhir.Core.UnitTests/Features/Operations/Export/CancelExportRequestHandlerTests.cs b/src/Microsoft.Health.Fhir.Core.UnitTests/Features/Operations/Export/CancelExportRequestHandlerTests.cs
index 0b5d3a577b..bcc1e40aa4 100644
--- a/src/Microsoft.Health.Fhir.Core.UnitTests/Features/Operations/Export/CancelExportRequestHandlerTests.cs
+++ b/src/Microsoft.Health.Fhir.Core.UnitTests/Features/Operations/Export/CancelExportRequestHandlerTests.cs
@@ -10,7 +10,6 @@
using MediatR;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging.Abstractions;
-using Microsoft.Health.Core.Internal;
using Microsoft.Health.Extensions.DependencyInjection;
using Microsoft.Health.Fhir.Core.Extensions;
using Microsoft.Health.Fhir.Core.Features.Operations;
@@ -70,6 +69,7 @@ public async Task GivenAFhirMediator_WhenCancelingExistingExportJobThatHasAlread
Assert.Null(outcome.JobRecord.CanceledTime);
}
+#if NET8_0_OR_GREATER
[Theory]
[InlineData(OperationStatus.Queued)]
[InlineData(OperationStatus.Running)]
@@ -79,7 +79,8 @@ public async Task GivenAFhirMediator_WhenCancelingExistingExportJobThatHasNotCom
var instant = new DateTimeOffset(2019, 5, 3, 22, 45, 15, TimeSpan.FromMinutes(-60));
- using (Mock.Property(() => ClockResolver.UtcNowFunc, () => instant))
+ Microsoft.Extensions.Time.Testing.FakeTimeProvider timeProvider = new(instant);
+ using (Mock.Property(() => ClockResolver.TimeProvider, timeProvider))
{
outcome = await SetupAndExecuteCancelExportAsync(operationStatus, HttpStatusCode.Accepted);
}
@@ -90,6 +91,7 @@ public async Task GivenAFhirMediator_WhenCancelingExistingExportJobThatHasNotCom
await _fhirOperationDataStore.Received(1).UpdateExportJobAsync(outcome.JobRecord, outcome.ETag, _cancellationToken);
}
+#endif
[Fact]
public async Task GivenAFhirMediator_WhenCancelingExistingExportJobEncountersJobConflictException_ThenItWillBeRetried()
diff --git a/src/Microsoft.Health.Fhir.Core.UnitTests/Features/Operations/Export/ExportJobTaskTests.cs b/src/Microsoft.Health.Fhir.Core.UnitTests/Features/Operations/Export/ExportJobTaskTests.cs
index 156afbbfe8..ac8351455c 100644
--- a/src/Microsoft.Health.Fhir.Core.UnitTests/Features/Operations/Export/ExportJobTaskTests.cs
+++ b/src/Microsoft.Health.Fhir.Core.UnitTests/Features/Operations/Export/ExportJobTaskTests.cs
@@ -17,10 +17,10 @@
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options;
using Microsoft.Health.Core.Features.Context;
-using Microsoft.Health.Core.Internal;
using Microsoft.Health.Extensions.DependencyInjection;
using Microsoft.Health.Fhir.Core.Configs;
using Microsoft.Health.Fhir.Core.Exceptions;
+using Microsoft.Health.Fhir.Core.Extensions;
using Microsoft.Health.Fhir.Core.Features;
using Microsoft.Health.Fhir.Core.Features.Context;
using Microsoft.Health.Fhir.Core.Features.Operations;
@@ -391,6 +391,40 @@ private Expression>>> CreateQueryP
arg.Any(x => x.Item1 == "ct" && x.Item2 == continuationToken);
}
+#if NET8_0_OR_GREATER
+ [Fact]
+ public async Task GivenStorageAccountConnectionDidNotChange_WhenExecuted_ThenJobShouldBeCompleted()
+ {
+ ExportJobConfiguration exportJobConfiguration = new ExportJobConfiguration();
+ exportJobConfiguration.StorageAccountConnection = "connection";
+ exportJobConfiguration.StorageAccountUri = string.Empty;
+
+ var exportJobRecordWithConnection = CreateExportJobRecord(
+ exportJobType: ExportJobType.Patient,
+ storageAccountConnectionHash: Microsoft.Health.Core.Extensions.StringExtensions.ComputeHash(exportJobConfiguration.StorageAccountConnection));
+ SetupExportJobRecordAndOperationDataStore(exportJobRecordWithConnection);
+
+ var exportJobTask = CreateExportJobTask(exportJobConfiguration);
+
+ _searchService.SearchAsync(
+ Arg.Any(),
+ Arg.Any>>(),
+ _cancellationToken,
+ true)
+ .Returns(x => CreateSearchResult());
+
+ DateTimeOffset endTimestamp = DateTimeOffset.UtcNow;
+
+ using (Mock.Property(() => ClockResolver.TimeProvider, new Microsoft.Extensions.Time.Testing.FakeTimeProvider(endTimestamp)))
+ {
+ await exportJobTask.ExecuteAsync(_exportJobRecord, _weakETag, _cancellationToken);
+ }
+
+ Assert.NotNull(_lastExportJobOutcome);
+ Assert.Equal(OperationStatus.Completed, _lastExportJobOutcome.JobRecord.Status);
+ Assert.Equal(endTimestamp, _lastExportJobOutcome.JobRecord.EndTime);
+ }
+
[Fact]
public async Task GivenSearchSucceeds_WhenExecuted_ThenJobStatusShouldBeUpdatedToCompleted()
{
@@ -403,7 +437,7 @@ public async Task GivenSearchSucceeds_WhenExecuted_ThenJobStatusShouldBeUpdatedT
DateTimeOffset endTimestamp = DateTimeOffset.UtcNow;
- using (Mock.Property(() => ClockResolver.UtcNowFunc, () => endTimestamp))
+ using (Mock.Property(() => ClockResolver.TimeProvider, new Microsoft.Extensions.Time.Testing.FakeTimeProvider(endTimestamp)))
{
await _exportJobTask.ExecuteAsync(_exportJobRecord, _weakETag, _cancellationToken);
}
@@ -428,7 +462,7 @@ public async Task GivenSearchFailed_WhenExecuted_ThenJobStatusShouldBeUpdatedToF
DateTimeOffset endTimestamp = DateTimeOffset.UtcNow;
- using (Mock.Property(() => ClockResolver.UtcNowFunc, () => endTimestamp))
+ using (Mock.Property(() => ClockResolver.TimeProvider, new Microsoft.Extensions.Time.Testing.FakeTimeProvider(endTimestamp)))
{
await _exportJobTask.ExecuteAsync(_exportJobRecord, _weakETag, _cancellationToken);
}
@@ -438,6 +472,7 @@ public async Task GivenSearchFailed_WhenExecuted_ThenJobStatusShouldBeUpdatedToF
Assert.Equal(endTimestamp, _lastExportJobOutcome.JobRecord.EndTime);
Assert.False(string.IsNullOrWhiteSpace(_lastExportJobOutcome.JobRecord.FailureDetails.FailureReason));
}
+#endif
[Fact]
public async Task GivenSearchHadIssues_WhenExecuted_ThenIssuesAreRecorded()
@@ -524,39 +559,6 @@ public async Task GivenConnectingToDestinationFails_WhenExecuted_ThenJobStatusSh
Assert.Equal(HttpStatusCode.BadRequest, _lastExportJobOutcome.JobRecord.FailureDetails.FailureStatusCode);
}
- [Fact]
- public async Task GivenStorageAccountConnectionDidNotChange_WhenExecuted_ThenJobShouldBeCompleted()
- {
- ExportJobConfiguration exportJobConfiguration = new ExportJobConfiguration();
- exportJobConfiguration.StorageAccountConnection = "connection";
- exportJobConfiguration.StorageAccountUri = string.Empty;
-
- var exportJobRecordWithConnection = CreateExportJobRecord(
- exportJobType: ExportJobType.Patient,
- storageAccountConnectionHash: Microsoft.Health.Core.Extensions.StringExtensions.ComputeHash(exportJobConfiguration.StorageAccountConnection));
- SetupExportJobRecordAndOperationDataStore(exportJobRecordWithConnection);
-
- var exportJobTask = CreateExportJobTask(exportJobConfiguration);
-
- _searchService.SearchAsync(
- Arg.Any(),
- Arg.Any>>(),
- _cancellationToken,
- true)
- .Returns(x => CreateSearchResult());
-
- DateTimeOffset endTimestamp = DateTimeOffset.UtcNow;
-
- using (Mock.Property(() => ClockResolver.UtcNowFunc, () => endTimestamp))
- {
- await exportJobTask.ExecuteAsync(_exportJobRecord, _weakETag, _cancellationToken);
- }
-
- Assert.NotNull(_lastExportJobOutcome);
- Assert.Equal(OperationStatus.Completed, _lastExportJobOutcome.JobRecord.Status);
- Assert.Equal(endTimestamp, _lastExportJobOutcome.JobRecord.EndTime);
- }
-
[Fact]
public async Task GivenStorageAccountConnectionChanged_WhenExecuted_ThenJobStatusShouldBeUpdatedToFailed()
{
diff --git a/src/Microsoft.Health.Fhir.Core.UnitTests/Features/Search/Registry/SearchParameterStatusManagerTests.cs b/src/Microsoft.Health.Fhir.Core.UnitTests/Features/Search/Registry/SearchParameterStatusManagerTests.cs
index a53f201877..6bdf7a6849 100644
--- a/src/Microsoft.Health.Fhir.Core.UnitTests/Features/Search/Registry/SearchParameterStatusManagerTests.cs
+++ b/src/Microsoft.Health.Fhir.Core.UnitTests/Features/Search/Registry/SearchParameterStatusManagerTests.cs
@@ -11,6 +11,7 @@
using MediatR;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Health.Core;
+using Microsoft.Health.Fhir.Core.Extensions;
using Microsoft.Health.Fhir.Core.Features.Definition;
using Microsoft.Health.Fhir.Core.Features.Search.Parameters;
using Microsoft.Health.Fhir.Core.Features.Search.Registry;
diff --git a/src/Microsoft.Health.Fhir.Core.UnitTests/Microsoft.Health.Fhir.Core.UnitTests.csproj b/src/Microsoft.Health.Fhir.Core.UnitTests/Microsoft.Health.Fhir.Core.UnitTests.csproj
index 4e86ac736a..dec942973d 100644
--- a/src/Microsoft.Health.Fhir.Core.UnitTests/Microsoft.Health.Fhir.Core.UnitTests.csproj
+++ b/src/Microsoft.Health.Fhir.Core.UnitTests/Microsoft.Health.Fhir.Core.UnitTests.csproj
@@ -20,6 +20,9 @@
runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
diff --git a/src/Microsoft.Health.Fhir.Core/Extensions/CancellationTokenSourceExtensions.cs b/src/Microsoft.Health.Fhir.Core/Extensions/CancellationTokenSourceExtensions.cs
new file mode 100644
index 0000000000..844564b7ec
--- /dev/null
+++ b/src/Microsoft.Health.Fhir.Core/Extensions/CancellationTokenSourceExtensions.cs
@@ -0,0 +1,20 @@
+// -------------------------------------------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
+// -------------------------------------------------------------------------------------------------
+
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace Microsoft.Health.Fhir.Core.Extensions;
+
+#if NET6_0
+public static class CancellationTokenSourceExtensions
+{
+ public static Task CancelAsync(this CancellationTokenSource cancellationTokenSource)
+ {
+ cancellationTokenSource.Cancel();
+ return Task.CompletedTask;
+ }
+}
+#endif
diff --git a/src/Microsoft.Health.Fhir.Core/Extensions/Clock.cs b/src/Microsoft.Health.Fhir.Core/Extensions/Clock.cs
new file mode 100644
index 0000000000..c3b53fd111
--- /dev/null
+++ b/src/Microsoft.Health.Fhir.Core/Extensions/Clock.cs
@@ -0,0 +1,27 @@
+// -------------------------------------------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
+// -------------------------------------------------------------------------------------------------
+
+using System;
+
+namespace Microsoft.Health.Fhir.Core.Extensions;
+
+#if NET8_0_OR_GREATER
+
+///
+/// Clock has been removed in Shared Components in favor of .NET8 TimeProvider.
+/// This class provides a wrapper to the TimeProvider to maintain the same interface while we continue to support .net6
+///
+public static class Clock
+{
+ public static DateTimeOffset UtcNow
+ {
+ get
+ {
+ return ClockResolver.TimeProvider.GetUtcNow();
+ }
+ }
+}
+
+#endif
diff --git a/src/Microsoft.Health.Fhir.Core/Extensions/ClockResolver.cs b/src/Microsoft.Health.Fhir.Core/Extensions/ClockResolver.cs
new file mode 100644
index 0000000000..48c12554a4
--- /dev/null
+++ b/src/Microsoft.Health.Fhir.Core/Extensions/ClockResolver.cs
@@ -0,0 +1,17 @@
+// -------------------------------------------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
+// -------------------------------------------------------------------------------------------------
+
+using System;
+
+namespace Microsoft.Health.Fhir.Core.Extensions;
+
+#if NET8_0_OR_GREATER
+
+public static class ClockResolver
+{
+ public static TimeProvider TimeProvider { get; set; } = TimeProvider.System;
+}
+
+#endif
diff --git a/src/Microsoft.Health.Fhir.Core/Extensions/SearchServiceExtensions.cs b/src/Microsoft.Health.Fhir.Core/Extensions/SearchServiceExtensions.cs
index 5eba435a71..d9f5b8c9a2 100644
--- a/src/Microsoft.Health.Fhir.Core/Extensions/SearchServiceExtensions.cs
+++ b/src/Microsoft.Health.Fhir.Core/Extensions/SearchServiceExtensions.cs
@@ -53,7 +53,7 @@ public static class SearchServiceExtensions
Microsoft.Extensions.Logging.ILogger logger = null)
{
// Filters search parameters that can limit the number of results (e.g. _count=1)
- IList> filteredParameters = conditionalParameters
+ List> filteredParameters = conditionalParameters
.Where(x => !_excludedParameters.Contains(x.Item1, StringComparer.OrdinalIgnoreCase))
.ToList();
diff --git a/src/Microsoft.Health.Fhir.Core/Features/Conformance/CapabilityStatementBuilder.cs b/src/Microsoft.Health.Fhir.Core/Features/Conformance/CapabilityStatementBuilder.cs
index b857e4b9c7..a82e3370f3 100644
--- a/src/Microsoft.Health.Fhir.Core/Features/Conformance/CapabilityStatementBuilder.cs
+++ b/src/Microsoft.Health.Fhir.Core/Features/Conformance/CapabilityStatementBuilder.cs
@@ -133,7 +133,7 @@ public ICapabilityStatementBuilder ApplyToResource(string resourceType, Action
{
@@ -177,7 +177,7 @@ public ICapabilityStatementBuilder AddGlobalSearchParameters()
return this;
}
- private ICapabilityStatementBuilder SyncSearchParamsAsync(string resourceType)
+ private CapabilityStatementBuilder SyncSearchParamsAsync(string resourceType)
{
EnsureArg.IsNotNullOrEmpty(resourceType, nameof(resourceType));
EnsureArg.IsTrue(_modelInfoProvider.IsKnownResource(resourceType), nameof(resourceType), x => GenerateTypeErrorMessage(x, resourceType));
@@ -243,7 +243,7 @@ private ICapabilityStatementBuilder SyncSearchParamsAsync(string resourceType)
return this;
}
- private ICapabilityStatementBuilder SyncProfile(string resourceType, bool disableCacheRefresh)
+ private CapabilityStatementBuilder SyncProfile(string resourceType, bool disableCacheRefresh)
{
EnsureArg.IsNotNullOrEmpty(resourceType, nameof(resourceType));
EnsureArg.IsTrue(_modelInfoProvider.IsKnownResource(resourceType), nameof(resourceType), x => GenerateTypeErrorMessage(x, resourceType));
diff --git a/src/Microsoft.Health.Fhir.Core/Features/Conformance/Models/DefaultOptionHashSet.cs b/src/Microsoft.Health.Fhir.Core/Features/Conformance/Models/DefaultOptionHashSet.cs
index 5cf2b4a548..528e33d838 100644
--- a/src/Microsoft.Health.Fhir.Core/Features/Conformance/Models/DefaultOptionHashSet.cs
+++ b/src/Microsoft.Health.Fhir.Core/Features/Conformance/Models/DefaultOptionHashSet.cs
@@ -7,7 +7,6 @@
namespace Microsoft.Health.Fhir.Core.Features.Conformance.Models
{
- [System.Diagnostics.CodeAnalysis.SuppressMessage("Naming", "CA1710:Identifiers should have correct suffix", Justification = "Should be consistent with base type.")]
internal class DefaultOptionHashSet : HashSet, IDefaultOption
{
public DefaultOptionHashSet(T defaultOption)
diff --git a/src/Microsoft.Health.Fhir.Core/Features/Conformance/SystemConformanceProvider.cs b/src/Microsoft.Health.Fhir.Core/Features/Conformance/SystemConformanceProvider.cs
index a2fef4a867..db5b5a0533 100644
--- a/src/Microsoft.Health.Fhir.Core/Features/Conformance/SystemConformanceProvider.cs
+++ b/src/Microsoft.Health.Fhir.Core/Features/Conformance/SystemConformanceProvider.cs
@@ -264,7 +264,7 @@ public async ValueTask DisposeAsync()
if (!_cancellationTokenSource.IsCancellationRequested)
{
- _cancellationTokenSource.Cancel();
+ await _cancellationTokenSource.CancelAsync();
}
if (_rebuilder != null)
diff --git a/src/Microsoft.Health.Fhir.Core/Features/Definition/SearchParameterDefinitionBuilder.cs b/src/Microsoft.Health.Fhir.Core/Features/Definition/SearchParameterDefinitionBuilder.cs
index 4916427848..6f18bded37 100644
--- a/src/Microsoft.Health.Fhir.Core/Features/Definition/SearchParameterDefinitionBuilder.cs
+++ b/src/Microsoft.Health.Fhir.Core/Features/Definition/SearchParameterDefinitionBuilder.cs
@@ -27,7 +27,7 @@ namespace Microsoft.Health.Fhir.Core.Features.Definition
{
internal static class SearchParameterDefinitionBuilder
{
- private static readonly ISet _missingExpressionsInR5 = new HashSet
+ private static readonly HashSet _missingExpressionsInR5 = new HashSet
{
new("http://hl7.org/fhir/SearchParameter/EvidenceVariable-topic"),
new("http://hl7.org/fhir/SearchParameter/ImagingStudy-reason"),
@@ -99,7 +99,7 @@ internal static BundleWrapper ReadEmbeddedSearchParameters(
{
using Stream stream = modelInfoProvider.OpenVersionedFileStream(embeddedResourceName, embeddedResourceNamespace, assembly);
- using TextReader reader = new StreamReader(stream);
+ using var reader = new StreamReader(stream);
var data = reader.ReadToEnd();
var rawResource = new RawResource(data, FhirResourceFormat.Json, true);
diff --git a/src/Microsoft.Health.Fhir.Core/Features/Operations/ConvertData/ContainerRegistryTemplateProvider.cs b/src/Microsoft.Health.Fhir.Core/Features/Operations/ConvertData/ContainerRegistryTemplateProvider.cs
index 3f3c84ec5f..14df25f4da 100644
--- a/src/Microsoft.Health.Fhir.Core/Features/Operations/ConvertData/ContainerRegistryTemplateProvider.cs
+++ b/src/Microsoft.Health.Fhir.Core/Features/Operations/ConvertData/ContainerRegistryTemplateProvider.cs
@@ -26,8 +26,7 @@ public class ContainerRegistryTemplateProvider : IConvertDataTemplateProvider, I
{
private bool _disposed = false;
private readonly IContainerRegistryTokenProvider _containerRegistryTokenProvider;
- private readonly ITemplateCollectionProviderFactory _templateCollectionProviderFactory;
- private readonly ConvertDataConfiguration _convertDataConfig;
+ private readonly TemplateCollectionProviderFactory _templateCollectionProviderFactory;
private readonly MemoryCache _cache;
private readonly MemoryCache _templateProviderCache;
private readonly SemaphoreSlim _templateProviderFactorySemaphore;
@@ -39,19 +38,18 @@ public ContainerRegistryTemplateProvider(
ILogger logger)
{
EnsureArg.IsNotNull(containerRegistryTokenProvider, nameof(containerRegistryTokenProvider));
- EnsureArg.IsNotNull(convertDataConfig, nameof(convertDataConfig));
+ EnsureArg.IsNotNull(convertDataConfig?.Value, nameof(convertDataConfig));
EnsureArg.IsNotNull(logger, nameof(logger));
_containerRegistryTokenProvider = containerRegistryTokenProvider;
- _convertDataConfig = convertDataConfig.Value;
_logger = logger;
// Initialize cache and template collection provider factory
_cache = new MemoryCache(new MemoryCacheOptions
{
- SizeLimit = _convertDataConfig.CacheSizeLimit,
+ SizeLimit = convertDataConfig.Value.CacheSizeLimit,
});
- _templateCollectionProviderFactory = new TemplateCollectionProviderFactory(_cache, Options.Create(_convertDataConfig.TemplateCollectionOptions));
+ _templateCollectionProviderFactory = new TemplateCollectionProviderFactory(_cache, Options.Create(convertDataConfig.Value.TemplateCollectionOptions));
_templateProviderCache = new MemoryCache(new MemoryCacheOptions());
_templateProviderFactorySemaphore = new SemaphoreSlim(1, 1);
@@ -111,22 +109,22 @@ First try to get the template provider from the cache.
// Remove token from cache when authentication failed.
_cache.Remove(GetCacheKey(request.RegistryServer));
- _logger.LogWarning(authEx, "Failed to access container registry.");
+ _logger.LogWarning(authEx, "Failed to access container registry");
throw new ContainerRegistryNotAuthorizedException(string.Format(Core.Resources.ContainerRegistryNotAuthorized, request.RegistryServer), authEx);
}
catch (ImageFetchException fetchEx)
{
- _logger.LogWarning(fetchEx, "Failed to fetch template image.");
+ _logger.LogWarning(fetchEx, "Failed to fetch template image");
throw new FetchTemplateCollectionFailedException(string.Format(Core.Resources.FetchTemplateCollectionFailed, fetchEx.Message), fetchEx);
}
catch (TemplateManagementException templateEx)
{
- _logger.LogWarning(templateEx, "Template collection is invalid.");
+ _logger.LogWarning(templateEx, "Template collection is invalid");
throw new TemplateCollectionErrorException(string.Format(Core.Resources.FetchTemplateCollectionFailed, templateEx.Message), templateEx);
}
catch (Exception unhandledEx)
{
- _logger.LogError(unhandledEx, "Unhandled exception: failed to get template collection.");
+ _logger.LogError(unhandledEx, "Unhandled exception: failed to get template collection");
throw new FetchTemplateCollectionFailedException(string.Format(Core.Resources.FetchTemplateCollectionFailed, unhandledEx.Message), unhandledEx);
}
}
diff --git a/src/Microsoft.Health.Fhir.Core/Features/Operations/ConvertData/DefaultTemplateProvider.cs b/src/Microsoft.Health.Fhir.Core/Features/Operations/ConvertData/DefaultTemplateProvider.cs
index 05b4a8e55f..19dbaab203 100644
--- a/src/Microsoft.Health.Fhir.Core/Features/Operations/ConvertData/DefaultTemplateProvider.cs
+++ b/src/Microsoft.Health.Fhir.Core/Features/Operations/ConvertData/DefaultTemplateProvider.cs
@@ -25,12 +25,12 @@ public class DefaultTemplateProvider : IConvertDataTemplateProvider, IDisposable
private bool _disposed = false;
private readonly ILogger _logger;
private readonly MemoryCache _cache;
- private readonly ITemplateCollectionProviderFactory _templateCollectionProviderFactory;
+ private readonly TemplateCollectionProviderFactory _templateCollectionProviderFactory;
private readonly ConvertDataConfiguration _convertDataConfig;
public DefaultTemplateProvider(
IOptions convertDataConfig,
- ILogger logger)
+ ILogger logger)
{
EnsureArg.IsNotNull(convertDataConfig, nameof(convertDataConfig));
EnsureArg.IsNotNull(logger, nameof(logger));
@@ -44,6 +44,7 @@ public DefaultTemplateProvider(
{
SizeLimit = _convertDataConfig.CacheSizeLimit,
});
+
_templateCollectionProviderFactory = new TemplateCollectionProviderFactory(_cache, Options.Create(_convertDataConfig.TemplateCollectionOptions));
}
@@ -57,7 +58,7 @@ public async Task>> GetTemplateCollectionAsync
{
var accessToken = string.Empty;
- _logger.LogInformation("Using the default template collection for data conversion.");
+ _logger.LogInformation("Using the default template collection for data conversion");
try
{
@@ -66,12 +67,12 @@ public async Task>> GetTemplateCollectionAsync
}
catch (TemplateManagementException templateEx)
{
- _logger.LogWarning(templateEx, "Template collection is invalid.");
+ _logger.LogWarning(templateEx, "Template collection is invalid");
throw new TemplateCollectionErrorException(string.Format(Core.Resources.FetchTemplateCollectionFailed, templateEx.Message), templateEx);
}
catch (Exception unhandledEx)
{
- _logger.LogError(unhandledEx, "Unhandled exception: failed to get template collection.");
+ _logger.LogError(unhandledEx, "Unhandled exception: failed to get template collection");
throw new FetchTemplateCollectionFailedException(string.Format(Core.Resources.FetchTemplateCollectionFailed, unhandledEx.Message), unhandledEx);
}
}
diff --git a/src/Microsoft.Health.Fhir.Core/Features/Operations/Export/CancelExportRequestHandler.cs b/src/Microsoft.Health.Fhir.Core/Features/Operations/Export/CancelExportRequestHandler.cs
index 5e6417062a..dde615e2b5 100644
--- a/src/Microsoft.Health.Fhir.Core/Features/Operations/Export/CancelExportRequestHandler.cs
+++ b/src/Microsoft.Health.Fhir.Core/Features/Operations/Export/CancelExportRequestHandler.cs
@@ -13,6 +13,7 @@
using Microsoft.Health.Core;
using Microsoft.Health.Core.Features.Security.Authorization;
using Microsoft.Health.Fhir.Core.Exceptions;
+using Microsoft.Health.Fhir.Core.Extensions;
using Microsoft.Health.Fhir.Core.Features.Operations.Export.Models;
using Microsoft.Health.Fhir.Core.Features.Security;
using Microsoft.Health.Fhir.Core.Messages.Export;
diff --git a/src/Microsoft.Health.Fhir.Core/Features/Operations/Export/CreateExportRequestHandler.cs b/src/Microsoft.Health.Fhir.Core/Features/Operations/Export/CreateExportRequestHandler.cs
index 77f4c506c6..8bbb210cb3 100644
--- a/src/Microsoft.Health.Fhir.Core/Features/Operations/Export/CreateExportRequestHandler.cs
+++ b/src/Microsoft.Health.Fhir.Core/Features/Operations/Export/CreateExportRequestHandler.cs
@@ -112,7 +112,7 @@ public async Task Handle(CreateExportRequest request, Canc
///
/// The _typeFilter parameter input.
/// A list of
- private static IList ParseFilter(string filterString)
+ private static List ParseFilter(string filterString)
{
var filters = new List();
@@ -121,7 +121,7 @@ private static IList ParseFilter(string filterString)
var filterArray = filterString.Split(",");
foreach (string filter in filterArray)
{
- var parameterIndex = filter.IndexOf("?", StringComparison.Ordinal);
+ var parameterIndex = filter.IndexOf('?', StringComparison.Ordinal);
if (parameterIndex < 0 || parameterIndex == filter.Length - 1)
{
diff --git a/src/Microsoft.Health.Fhir.Core/Features/Operations/Export/ExportFileManager.cs b/src/Microsoft.Health.Fhir.Core/Features/Operations/Export/ExportFileManager.cs
index 6ec7c20f16..57e683aa35 100644
--- a/src/Microsoft.Health.Fhir.Core/Features/Operations/Export/ExportFileManager.cs
+++ b/src/Microsoft.Health.Fhir.Core/Features/Operations/Export/ExportFileManager.cs
@@ -21,7 +21,7 @@ internal class ExportFileManager
{
private readonly ExportJobRecord _exportJobRecord;
private readonly IExportDestinationClient _exportDestinationClient;
- private readonly IDictionary _resourceTypeToFileInfoMapping;
+ private readonly Dictionary _resourceTypeToFileInfoMapping;
private readonly uint _approxMaxFileSizeInBytes;
private bool _isInitialized = false;
private Dictionary _resourceCommited = new Dictionary();
@@ -162,14 +162,13 @@ private ExportFileInfo CreateNewFileAndUpdateMappings(string resourceType, int f
}
// Update internal mapping with new file for the resource type.
- if (_resourceTypeToFileInfoMapping.ContainsKey(resourceType))
+ if (!_resourceTypeToFileInfoMapping.TryAdd(resourceType, newFile))
{
_resourceTypeToFileInfoMapping[resourceType] = newFile;
_resourceCommited[resourceType] = false;
}
else
{
- _resourceTypeToFileInfoMapping.Add(resourceType, newFile);
_resourceCommited.Add(resourceType, false);
}
diff --git a/src/Microsoft.Health.Fhir.Core/Features/Operations/Export/ExportJobTask.cs b/src/Microsoft.Health.Fhir.Core/Features/Operations/Export/ExportJobTask.cs
index 773edaf223..6dc0c046e9 100644
--- a/src/Microsoft.Health.Fhir.Core/Features/Operations/Export/ExportJobTask.cs
+++ b/src/Microsoft.Health.Fhir.Core/Features/Operations/Export/ExportJobTask.cs
@@ -22,6 +22,7 @@
using Microsoft.Health.Extensions.DependencyInjection;
using Microsoft.Health.Fhir.Core.Configs;
using Microsoft.Health.Fhir.Core.Exceptions;
+using Microsoft.Health.Fhir.Core.Extensions;
using Microsoft.Health.Fhir.Core.Features.Context;
using Microsoft.Health.Fhir.Core.Features.Operations.Export.ExportDestinationClient;
using Microsoft.Health.Fhir.Core.Features.Operations.Export.Models;
diff --git a/src/Microsoft.Health.Fhir.Core/Features/Operations/Export/Models/ExportJobRecord.cs b/src/Microsoft.Health.Fhir.Core/Features/Operations/Export/Models/ExportJobRecord.cs
index 18ff1e12f4..21b81dda35 100644
--- a/src/Microsoft.Health.Fhir.Core/Features/Operations/Export/Models/ExportJobRecord.cs
+++ b/src/Microsoft.Health.Fhir.Core/Features/Operations/Export/Models/ExportJobRecord.cs
@@ -7,6 +7,7 @@
using System.Collections.Generic;
using EnsureThat;
using Microsoft.Health.Core;
+using Microsoft.Health.Fhir.Core.Extensions;
using Microsoft.Health.Fhir.Core.Models;
using Microsoft.Health.JobManagement;
using Newtonsoft.Json;
diff --git a/src/Microsoft.Health.Fhir.Core/Features/Operations/Import/ImportErrorStore.cs b/src/Microsoft.Health.Fhir.Core/Features/Operations/Import/ImportErrorStore.cs
index dc8df249bd..48bec833c3 100644
--- a/src/Microsoft.Health.Fhir.Core/Features/Operations/Import/ImportErrorStore.cs
+++ b/src/Microsoft.Health.Fhir.Core/Features/Operations/Import/ImportErrorStore.cs
@@ -41,6 +41,7 @@ public ImportErrorStore(IIntegrationDataStoreClient integrationDataStoreClient,
///
/// New import errors
/// Cancellaltion Token
+ [System.Diagnostics.CodeAnalysis.SuppressMessage("Reliability", "CA2016:Forward the 'CancellationToken' parameter to methods", Justification = ".NET 6/8 compat")]
public async Task UploadErrorsAsync(string[] importErrors, CancellationToken cancellationToken)
{
if (importErrors == null || importErrors.Length == 0)
@@ -67,7 +68,7 @@ public async Task UploadErrorsAsync(string[] importErrors, CancellationToken can
}
catch (Exception ex)
{
- _logger.LogWarning("Failed to upload import error log.", ex);
+ _logger.LogWarning(ex, "Failed to upload import error log.");
throw new RetriableJobException(ex.Message, ex);
}
}
diff --git a/src/Microsoft.Health.Fhir.Core/Features/Operations/Import/ImportResourceLoader.cs b/src/Microsoft.Health.Fhir.Core/Features/Operations/Import/ImportResourceLoader.cs
index be49d170bf..50d4776385 100644
--- a/src/Microsoft.Health.Fhir.Core/Features/Operations/Import/ImportResourceLoader.cs
+++ b/src/Microsoft.Health.Fhir.Core/Features/Operations/Import/ImportResourceLoader.cs
@@ -77,10 +77,7 @@ private async Task LoadResourcesInternalAsync(Channel outputChan
while ((currentBytesRead <= bytesToRead) && !string.IsNullOrEmpty(content = await reader.ReadLineAsync()))
#pragma warning restore CA2016
{
- if (cancellationToken.IsCancellationRequested)
- {
- throw new OperationCanceledException();
- }
+ cancellationToken.ThrowIfCancellationRequested();
if (offset > 0 && skipFirstLine) // skip first line
{
@@ -126,7 +123,7 @@ private async Task LoadResourcesInternalAsync(Channel outputChan
}
}
- private async Task> ParseImportRawContentAsync(string resourceType, IList<(string content, long index, int length)> rawContents, long offset, ImportMode importMode)
+ private async Task> ParseImportRawContentAsync(string resourceType, List<(string content, long index, int length)> rawContents, long offset, ImportMode importMode)
{
return await Task.Run(() =>
{
diff --git a/src/Microsoft.Health.Fhir.Core/Features/Operations/Reindex/CancelReindexRequestHandler.cs b/src/Microsoft.Health.Fhir.Core/Features/Operations/Reindex/CancelReindexRequestHandler.cs
index ad539fd972..66cdd65776 100644
--- a/src/Microsoft.Health.Fhir.Core/Features/Operations/Reindex/CancelReindexRequestHandler.cs
+++ b/src/Microsoft.Health.Fhir.Core/Features/Operations/Reindex/CancelReindexRequestHandler.cs
@@ -12,6 +12,7 @@
using Microsoft.Health.Core;
using Microsoft.Health.Core.Features.Security.Authorization;
using Microsoft.Health.Fhir.Core.Exceptions;
+using Microsoft.Health.Fhir.Core.Extensions;
using Microsoft.Health.Fhir.Core.Features.Operations.Reindex.Models;
using Microsoft.Health.Fhir.Core.Features.Security;
using Microsoft.Health.Fhir.Core.Messages.Reindex;
diff --git a/src/Microsoft.Health.Fhir.Core/Features/Operations/Reindex/Models/ReindexJobRecord.cs b/src/Microsoft.Health.Fhir.Core/Features/Operations/Reindex/Models/ReindexJobRecord.cs
index e470c72d6c..5ecf7b33b9 100644
--- a/src/Microsoft.Health.Fhir.Core/Features/Operations/Reindex/Models/ReindexJobRecord.cs
+++ b/src/Microsoft.Health.Fhir.Core/Features/Operations/Reindex/Models/ReindexJobRecord.cs
@@ -9,6 +9,7 @@
using System.Linq;
using EnsureThat;
using Microsoft.Health.Core;
+using Microsoft.Health.Fhir.Core.Extensions;
using Microsoft.Health.Fhir.Core.Features.Persistence;
using Microsoft.Health.Fhir.Core.Features.Search;
using Microsoft.Health.Fhir.Core.Models;
diff --git a/src/Microsoft.Health.Fhir.Core/Features/Operations/Reindex/ReindexJobTask.cs b/src/Microsoft.Health.Fhir.Core/Features/Operations/Reindex/ReindexJobTask.cs
index 37e7078855..3085cf3a62 100644
--- a/src/Microsoft.Health.Fhir.Core/Features/Operations/Reindex/ReindexJobTask.cs
+++ b/src/Microsoft.Health.Fhir.Core/Features/Operations/Reindex/ReindexJobTask.cs
@@ -19,6 +19,7 @@
using Microsoft.Health.Extensions.DependencyInjection;
using Microsoft.Health.Fhir.Core.Configs;
using Microsoft.Health.Fhir.Core.Exceptions;
+using Microsoft.Health.Fhir.Core.Extensions;
using Microsoft.Health.Fhir.Core.Features.Context;
using Microsoft.Health.Fhir.Core.Features.Definition;
using Microsoft.Health.Fhir.Core.Features.Operations.Reindex.Models;
@@ -197,7 +198,7 @@ private async Task TryPopulateNewJobFields(CancellationToken cancellationT
var resourceList = new HashSet();
// filter list of SearchParameters by the target resource types
- if (_reindexJobRecord.TargetResourceTypes.Any())
+ if (_reindexJobRecord.TargetResourceTypes.Count > 0)
{
foreach (var searchParam in possibleNotYetIndexedParams)
{
@@ -251,7 +252,7 @@ private async Task TryPopulateNewJobFields(CancellationToken cancellationT
}
// if there are not any parameters which are supported but not yet indexed, then we have nothing to do
- if (!notYetIndexedParams.Any() && resourceList.Count == 0)
+ if (notYetIndexedParams.Count == 0 && resourceList.Count == 0)
{
_reindexJobRecord.Error.Add(new OperationOutcomeIssue(
OperationOutcomeConstants.IssueSeverity.Information,
@@ -312,7 +313,7 @@ private async Task HandleException(Exception ex)
_reindexJobRecord.FailureCount++;
- _logger.LogError(ex, "Encountered an unhandled exception. The job failure count increased to {FailureCount}, id: {Id}.", _reindexJobRecord.FailureCount);
+ _logger.LogError(ex, "Encountered an unhandled exception. The job failure count increased to {FailureCount}.", _reindexJobRecord.FailureCount);
if (_reindexJobRecord.FailureCount >= _reindexJobConfiguration.ConsecutiveFailuresThreshold)
{
@@ -332,6 +333,7 @@ private async Task HandleException(Exception ex)
}
}
+ [System.Diagnostics.CodeAnalysis.SuppressMessage("Performance", "CA1849:Call async methods when in an async method", Justification = "tokenSource.CancelAsync(false) doesn't exist.")]
private async Task ProcessJob()
{
var queryTasks = new List>();
@@ -879,6 +881,7 @@ private async Task UpdateParametersAndCompleteJob(CancellationToken cancellation
}
}
+ [System.Diagnostics.CodeAnalysis.SuppressMessage("Performance", "CA1859:Use concrete types when possible for improved performance", Justification = "Collection defined on model")]
private ICollection GetDerivedResourceTypes(IReadOnlyCollection resourceTypes)
{
var completeResourceList = new HashSet(resourceTypes);
diff --git a/src/Microsoft.Health.Fhir.Core/Features/Persistence/ResourceWrapper.cs b/src/Microsoft.Health.Fhir.Core/Features/Persistence/ResourceWrapper.cs
index 5eec7f570c..bbabd83f3a 100644
--- a/src/Microsoft.Health.Fhir.Core/Features/Persistence/ResourceWrapper.cs
+++ b/src/Microsoft.Health.Fhir.Core/Features/Persistence/ResourceWrapper.cs
@@ -7,6 +7,7 @@
using System.Collections.Generic;
using EnsureThat;
using Microsoft.Health.Core;
+using Microsoft.Health.Fhir.Core.Extensions;
using Microsoft.Health.Fhir.Core.Features.Search;
using Microsoft.Health.Fhir.Core.Models;
using Newtonsoft.Json;
diff --git a/src/Microsoft.Health.Fhir.Core/Features/Search/Access/ExpressionAccessControl.cs b/src/Microsoft.Health.Fhir.Core/Features/Search/Access/ExpressionAccessControl.cs
index c848ecb8d0..d7ba5f809a 100644
--- a/src/Microsoft.Health.Fhir.Core/Features/Search/Access/ExpressionAccessControl.cs
+++ b/src/Microsoft.Health.Fhir.Core/Features/Search/Access/ExpressionAccessControl.cs
@@ -66,7 +66,7 @@ public void CheckAndRaiseAccessExceptions(Expression expression)
}
}
- private static bool ResourceTypeAllowedByClinicalScopes(ICollection validResourceTypes, string resourceType)
+ private static bool ResourceTypeAllowedByClinicalScopes(HashSet validResourceTypes, string resourceType)
{
if (validResourceTypes != null && (validResourceTypes.Contains(KnownResourceTypes.All) || validResourceTypes.Contains(resourceType)))
{
diff --git a/src/Microsoft.Health.Fhir.Core/Features/Search/Converters/ResourceReferenceToReferenceSearchValueConverter.cs b/src/Microsoft.Health.Fhir.Core/Features/Search/Converters/ResourceReferenceToReferenceSearchValueConverter.cs
index 3b79061eeb..741ab3d268 100644
--- a/src/Microsoft.Health.Fhir.Core/Features/Search/Converters/ResourceReferenceToReferenceSearchValueConverter.cs
+++ b/src/Microsoft.Health.Fhir.Core/Features/Search/Converters/ResourceReferenceToReferenceSearchValueConverter.cs
@@ -37,7 +37,7 @@ protected override IEnumerable Convert(ITypedElement value)
}
// Contained resources will not be searchable.
- if (reference.StartsWith("#", StringComparison.Ordinal)
+ if (reference.StartsWith('#')
|| reference.StartsWith("urn:", StringComparison.Ordinal))
{
yield break;
diff --git a/src/Microsoft.Health.Fhir.Core/Features/Search/Converters/UriToReferenceSearchValueConverter.cs b/src/Microsoft.Health.Fhir.Core/Features/Search/Converters/UriToReferenceSearchValueConverter.cs
index 455c758148..118810c8d9 100644
--- a/src/Microsoft.Health.Fhir.Core/Features/Search/Converters/UriToReferenceSearchValueConverter.cs
+++ b/src/Microsoft.Health.Fhir.Core/Features/Search/Converters/UriToReferenceSearchValueConverter.cs
@@ -36,7 +36,7 @@ protected override IEnumerable Convert(ITypedElement value)
}
// Contained resources will not be searchable.
- if (uri.StartsWith("#", StringComparison.Ordinal)
+ if (uri.StartsWith('#')
|| uri.StartsWith("urn:", StringComparison.Ordinal))
{
yield break;
diff --git a/src/Microsoft.Health.Fhir.Core/Features/Search/Expressions/IncludeExpression.cs b/src/Microsoft.Health.Fhir.Core/Features/Search/Expressions/IncludeExpression.cs
index d3dd5abc57..c333de2e4b 100644
--- a/src/Microsoft.Health.Fhir.Core/Features/Search/Expressions/IncludeExpression.cs
+++ b/src/Microsoft.Health.Fhir.Core/Features/Search/Expressions/IncludeExpression.cs
@@ -170,7 +170,7 @@ private IReadOnlyCollection GetRequiredResources()
}
}
- private IReadOnlyCollection GetProducedResources()
+ private List GetProducedResources()
{
var producedResources = new List();
diff --git a/src/Microsoft.Health.Fhir.Core/Features/Search/Expressions/Parsers/ExpressionParser.cs b/src/Microsoft.Health.Fhir.Core/Features/Search/Expressions/Parsers/ExpressionParser.cs
index de285b2e49..730e3255ca 100644
--- a/src/Microsoft.Health.Fhir.Core/Features/Search/Expressions/Parsers/ExpressionParser.cs
+++ b/src/Microsoft.Health.Fhir.Core/Features/Search/Expressions/Parsers/ExpressionParser.cs
@@ -221,7 +221,7 @@ private Expression ParseImpl(string[] resourceTypes, ReadOnlySpan key, str
return ParseSearchValueExpression(searchParameter, modifier.ToString(), value);
}
- private Expression ParseChainedExpression(string[] resourceTypes, SearchParameterInfo searchParameter, string[] targetResourceTypes, ReadOnlySpan remainingKey, string value, bool reversed)
+ private ChainedExpression ParseChainedExpression(string[] resourceTypes, SearchParameterInfo searchParameter, string[] targetResourceTypes, ReadOnlySpan remainingKey, string value, bool reversed)
{
// We have more paths after this so this is a chained expression.
// Since this is chained expression, the expression must be a reference type.
diff --git a/src/Microsoft.Health.Fhir.Core/Features/Search/Expressions/Parsers/SearchValueExpressionBuilderHelper.cs b/src/Microsoft.Health.Fhir.Core/Features/Search/Expressions/Parsers/SearchValueExpressionBuilderHelper.cs
index 124dd8406a..fe666ee6cc 100644
--- a/src/Microsoft.Health.Fhir.Core/Features/Search/Expressions/Parsers/SearchValueExpressionBuilderHelper.cs
+++ b/src/Microsoft.Health.Fhir.Core/Features/Search/Expressions/Parsers/SearchValueExpressionBuilderHelper.cs
@@ -9,6 +9,7 @@
using EnsureThat;
using Microsoft.Health.Core;
using Microsoft.Health.Core.Extensions;
+using Microsoft.Health.Fhir.Core.Extensions;
using Microsoft.Health.Fhir.Core.Features.Search.SearchValues;
using Microsoft.Health.Fhir.ValueSets;
diff --git a/src/Microsoft.Health.Fhir.Core/Features/Search/Filters/MissingDataFilterCriteria.cs b/src/Microsoft.Health.Fhir.Core/Features/Search/Filters/MissingDataFilterCriteria.cs
index ece2a32f34..ed4d6f5d1b 100644
--- a/src/Microsoft.Health.Fhir.Core/Features/Search/Filters/MissingDataFilterCriteria.cs
+++ b/src/Microsoft.Health.Fhir.Core/Features/Search/Filters/MissingDataFilterCriteria.cs
@@ -26,7 +26,7 @@ namespace Microsoft.Health.Fhir.Core.Features.Search.Filters
///
public sealed class MissingDataFilterCriteria : IFilterCriteria
{
- private static readonly IDictionary _requiredStatusElementsByResourceType = new Dictionary()
+ private static readonly Dictionary _requiredStatusElementsByResourceType = new()
{
{ "AllergyIntolerance", "clinicalStatus" },
{ "Condition", "clinicalStatus" },
@@ -51,7 +51,7 @@ private MissingDataFilterCriteria(bool isCriteriaEnabled, bool isSmartRequest)
_isSmartRequest = isSmartRequest;
}
- public static MissingDataFilterCriteria Default => new MissingDataFilterCriteria(isCriteriaEnabled: false, isSmartRequest: false);
+ public static MissingDataFilterCriteria Default => new(isCriteriaEnabled: false, isSmartRequest: false);
public SearchResult Apply(SearchResult searchResult)
{
@@ -62,8 +62,8 @@ public SearchResult Apply(SearchResult searchResult)
return searchResult;
}
- List finalResults = new List();
- List searchIssues = new List();
+ var finalResults = new List();
+ var searchIssues = new List();
foreach (SearchResultEntry resultEntry in searchResult.Results)
{
@@ -156,7 +156,7 @@ private static bool ContainStatusElement(ResourceWrapper resourceWrapper, string
private static bool ContainsXmlStatusElement(ResourceWrapper resourceWrapper, string requiredStatusElementName)
{
- XDocument doc = XDocument.Parse(resourceWrapper.RawResource.Data);
+ var doc = XDocument.Parse(resourceWrapper.RawResource.Data);
List elementsByName = doc.Root.Elements().Where(x => string.Equals(x.Name.LocalName, requiredStatusElementName, StringComparison.OrdinalIgnoreCase)).ToList();
@@ -179,7 +179,7 @@ private static bool ContainsXmlStatusElement(ResourceWrapper resourceWrapper, st
private static bool ContainsJsonStatusElement(ResourceWrapper resourceWrapper, string requiredStatusElementName)
{
- JObject jsonResource = JObject.Parse(resourceWrapper.RawResource.Data);
+ var jsonResource = JObject.Parse(resourceWrapper.RawResource.Data);
if (!jsonResource.ContainsKey(requiredStatusElementName))
{
return false;
diff --git a/src/Microsoft.Health.Fhir.Core/Features/Search/Registry/FilebasedSearchParameterStatusDataStore.cs b/src/Microsoft.Health.Fhir.Core/Features/Search/Registry/FilebasedSearchParameterStatusDataStore.cs
index cc8a059671..30e68ff4db 100644
--- a/src/Microsoft.Health.Fhir.Core/Features/Search/Registry/FilebasedSearchParameterStatusDataStore.cs
+++ b/src/Microsoft.Health.Fhir.Core/Features/Search/Registry/FilebasedSearchParameterStatusDataStore.cs
@@ -11,6 +11,7 @@
using EnsureThat;
using Microsoft.Health.Core;
using Microsoft.Health.Fhir.Core.Data;
+using Microsoft.Health.Fhir.Core.Extensions;
using Microsoft.Health.Fhir.Core.Features.Definition;
using Microsoft.Health.Fhir.Core.Models;
using Newtonsoft.Json;
@@ -39,8 +40,8 @@ public async Task> GetSearchP
{
if (_statusResults == null)
{
- using Stream stream = _modelInfoProvider.OpenVersionedFileStream("unsupported-search-parameters.json");
- using TextReader reader = new StreamReader(stream);
+ await using Stream stream = _modelInfoProvider.OpenVersionedFileStream("unsupported-search-parameters.json");
+ using var reader = new StreamReader(stream);
#pragma warning disable CA2016
var content = await reader.ReadToEndAsync();
#pragma warning restore CA2016
diff --git a/src/Microsoft.Health.Fhir.Core/Features/Search/Registry/SearchParameterStatusManager.cs b/src/Microsoft.Health.Fhir.Core/Features/Search/Registry/SearchParameterStatusManager.cs
index 4f9b473acf..44f407689f 100644
--- a/src/Microsoft.Health.Fhir.Core/Features/Search/Registry/SearchParameterStatusManager.cs
+++ b/src/Microsoft.Health.Fhir.Core/Features/Search/Registry/SearchParameterStatusManager.cs
@@ -12,6 +12,7 @@
using MediatR;
using Microsoft.Extensions.Logging;
using Microsoft.Health.Core;
+using Microsoft.Health.Fhir.Core.Extensions;
using Microsoft.Health.Fhir.Core.Features.Definition;
using Microsoft.Health.Fhir.Core.Features.Search.Parameters;
using Microsoft.Health.Fhir.Core.Messages.Search;
diff --git a/src/Microsoft.Health.Fhir.Core/Features/Search/SearchService.cs b/src/Microsoft.Health.Fhir.Core/Features/Search/SearchService.cs
index 5903179883..8446d3310b 100644
--- a/src/Microsoft.Health.Fhir.Core/Features/Search/SearchService.cs
+++ b/src/Microsoft.Health.Fhir.Core/Features/Search/SearchService.cs
@@ -12,6 +12,7 @@
using EnsureThat;
using Microsoft.Health.Core;
using Microsoft.Health.Fhir.Core.Exceptions;
+using Microsoft.Health.Fhir.Core.Extensions;
using Microsoft.Health.Fhir.Core.Features.Persistence;
using Microsoft.Health.Fhir.Core.Models;
diff --git a/src/Microsoft.Health.Fhir.Core/Features/Search/StringExtensions.cs b/src/Microsoft.Health.Fhir.Core/Features/Search/StringExtensions.cs
index c92ff1733e..ea99f2d738 100644
--- a/src/Microsoft.Health.Fhir.Core/Features/Search/StringExtensions.cs
+++ b/src/Microsoft.Health.Fhir.Core/Features/Search/StringExtensions.cs
@@ -150,11 +150,11 @@ public static string UnescapeSearchParameterValue(this string s)
return s;
}
- private static IReadOnlyList Split(string s, char separator)
+ private static List Split(string s, char separator)
{
EnsureArg.IsNotNull(s, nameof(s));
- List results = new List();
+ var results = new List();
bool isEscaping = false;
diff --git a/src/Microsoft.Health.Fhir.Core/Features/Search/TypedElementSearchIndexer.cs b/src/Microsoft.Health.Fhir.Core/Features/Search/TypedElementSearchIndexer.cs
index 8bb9a7c8c6..0ac194cc46 100644
--- a/src/Microsoft.Health.Fhir.Core/Features/Search/TypedElementSearchIndexer.cs
+++ b/src/Microsoft.Health.Fhir.Core/Features/Search/TypedElementSearchIndexer.cs
@@ -189,7 +189,7 @@ private IEnumerable ProcessNonCompositeSearchParameter(SearchP
}
}
- private IReadOnlyList ExtractSearchValues(
+ private List ExtractSearchValues(
string searchParameterDefinitionUrl,
SearchParamType? searchParameterType,
IReadOnlyList allowedReferenceResourceTypes,
diff --git a/src/Microsoft.Health.Fhir.Core/Features/Validation/Narratives/NarrativeHtmlSanitizer.cs b/src/Microsoft.Health.Fhir.Core/Features/Validation/Narratives/NarrativeHtmlSanitizer.cs
index ac234a1039..e86efc1318 100644
--- a/src/Microsoft.Health.Fhir.Core/Features/Validation/Narratives/NarrativeHtmlSanitizer.cs
+++ b/src/Microsoft.Health.Fhir.Core/Features/Validation/Narratives/NarrativeHtmlSanitizer.cs
@@ -22,7 +22,7 @@ public class NarrativeHtmlSanitizer : INarrativeHtmlSanitizer
{
private readonly ILogger _logger;
- private static readonly ISet AllowedElements = new HashSet(StringComparer.OrdinalIgnoreCase)
+ private static readonly HashSet AllowedElements = new(StringComparer.OrdinalIgnoreCase)
{
// https://www.hl7.org/fhir/narrative-definitions.html#Narrative.div
"a",
@@ -75,7 +75,7 @@ public class NarrativeHtmlSanitizer : INarrativeHtmlSanitizer
"var",
};
- private static readonly ISet AllowedAttributes = new HashSet(StringComparer.OrdinalIgnoreCase)
+ private static readonly HashSet AllowedAttributes = new(StringComparer.OrdinalIgnoreCase)
{
// https://www.hl7.org/fhir/narrative-definitions.html#Narrative.div
"abbr",
@@ -140,7 +140,7 @@ public class NarrativeHtmlSanitizer : INarrativeHtmlSanitizer
};
// Obvious invalid structural parsing errors to report
- private static readonly ISet RaiseErrorTypes = new HashSet
+ private static readonly HashSet RaiseErrorTypes = new HashSet
{
HtmlParseError.AmbiguousOpenTag,
HtmlParseError.BogusComment,
diff --git a/src/Microsoft.Health.Fhir.CosmosDb.UnitTests/Features/Storage/CosmosFhirDataStoreTests.cs b/src/Microsoft.Health.Fhir.CosmosDb.UnitTests/Features/Storage/CosmosFhirDataStoreTests.cs
index 8458f0f55b..4da108a6e6 100644
--- a/src/Microsoft.Health.Fhir.CosmosDb.UnitTests/Features/Storage/CosmosFhirDataStoreTests.cs
+++ b/src/Microsoft.Health.Fhir.CosmosDb.UnitTests/Features/Storage/CosmosFhirDataStoreTests.cs
@@ -19,7 +19,6 @@
using Microsoft.Extensions.Options;
using Microsoft.Health.Abstractions.Exceptions;
using Microsoft.Health.Core.Features.Context;
-using Microsoft.Health.Core.Internal;
using Microsoft.Health.Extensions.DependencyInjection;
using Microsoft.Health.Fhir.Core.Configs;
using Microsoft.Health.Fhir.Core.Extensions;
@@ -119,6 +118,7 @@ public async Task GivenAQuery_WhenFetchingSubsequentPagesYieldsA429_ReturnsExist
Assert.Equal("token", continuationToken);
}
+#if NET8_0_OR_GREATER
[Fact]
public async Task GivenAQuery_WhenFetchingSubsequentPagesTimesOut_ReturnsExistingResults()
{
@@ -134,7 +134,7 @@ public async Task GivenAQuery_WhenFetchingSubsequentPagesTimesOut_ReturnsExistin
_cosmosDataStoreConfiguration.SearchEnumerationTimeoutInSeconds = 0;
// lock the time
- using (Mock.Property(() => ClockResolver.UtcNowFunc, () => time))
+ using (Mock.Property(() => ClockResolver.TimeProvider, new Microsoft.Extensions.Time.Testing.FakeTimeProvider(time)))
{
(IReadOnlyList results, string continuationToken) =
await _dataStore.ExecuteDocumentQueryAsync(
@@ -145,6 +145,7 @@ await _dataStore.ExecuteDocumentQueryAsync(
Assert.Equal("token", continuationToken);
}
}
+#endif
[Fact]
public async Task GivenAQueryWhereItemCountCanBeExceeded_WhenExecuted_FetchesSubsequentPages()
diff --git a/src/Microsoft.Health.Fhir.CosmosDb.UnitTests/Features/Storage/Registry/CosmosDbSearchParameterStatusInitializerTests.cs b/src/Microsoft.Health.Fhir.CosmosDb.UnitTests/Features/Storage/Registry/CosmosDbSearchParameterStatusInitializerTests.cs
index cac99a769f..df694110f7 100644
--- a/src/Microsoft.Health.Fhir.CosmosDb.UnitTests/Features/Storage/Registry/CosmosDbSearchParameterStatusInitializerTests.cs
+++ b/src/Microsoft.Health.Fhir.CosmosDb.UnitTests/Features/Storage/Registry/CosmosDbSearchParameterStatusInitializerTests.cs
@@ -9,6 +9,7 @@
using System.Threading.Tasks;
using Microsoft.Azure.Cosmos;
using Microsoft.Health.Core;
+using Microsoft.Health.Fhir.Core.Extensions;
using Microsoft.Health.Fhir.Core.Features.Search.Registry;
using Microsoft.Health.Fhir.CosmosDb.Configs;
using Microsoft.Health.Fhir.CosmosDb.Features.Queries;
diff --git a/src/Microsoft.Health.Fhir.CosmosDb.UnitTests/Features/Storage/Search/ResourceWrapperTests.cs b/src/Microsoft.Health.Fhir.CosmosDb.UnitTests/Features/Storage/Search/ResourceWrapperTests.cs
index b44ecc4d10..d7e31ba025 100644
--- a/src/Microsoft.Health.Fhir.CosmosDb.UnitTests/Features/Storage/Search/ResourceWrapperTests.cs
+++ b/src/Microsoft.Health.Fhir.CosmosDb.UnitTests/Features/Storage/Search/ResourceWrapperTests.cs
@@ -9,7 +9,6 @@
using System.Net.Http;
using Hl7.Fhir.Model;
using Hl7.Fhir.Serialization;
-using Microsoft.Health.Core.Internal;
using Microsoft.Health.Fhir.Core.Extensions;
using Microsoft.Health.Fhir.Core.Features.Persistence;
using Microsoft.Health.Fhir.Core.Models;
@@ -65,6 +64,7 @@ public void GivenAResourceWrapper_WhenConvertingToAHistoryObject_ThenTheCorrectP
Assert.Equal("version1", historyRecord.Version);
}
+#if NET8_0_OR_GREATER
[Fact]
public void GivenAResource_WhenCreatingAResourceWrapper_ThenMetaPropertiesAreCorrect()
{
@@ -74,7 +74,7 @@ public void GivenAResource_WhenCreatingAResourceWrapper_ThenMetaPropertiesAreCor
observation.Meta.Profile = new List { "test" };
var lastModified = new DateTimeOffset(2017, 1, 1, 1, 1, 1, TimeSpan.Zero);
- using (Mock.Property(() => ClockResolver.UtcNowFunc, () => lastModified))
+ using (Mock.Property(() => ClockResolver.TimeProvider, new Microsoft.Extensions.Time.Testing.FakeTimeProvider(lastModified)))
{
ResourceElement typedElement = observation.ToResourceElement();
@@ -88,5 +88,6 @@ public void GivenAResource_WhenCreatingAResourceWrapper_ThenMetaPropertiesAreCor
Assert.Equal("test", poco.Meta.Profile.First());
}
}
+#endif
}
}
diff --git a/src/Microsoft.Health.Fhir.CosmosDb.UnitTests/Microsoft.Health.Fhir.CosmosDb.UnitTests.csproj b/src/Microsoft.Health.Fhir.CosmosDb.UnitTests/Microsoft.Health.Fhir.CosmosDb.UnitTests.csproj
index 36c08d6ab3..e2af38051a 100644
--- a/src/Microsoft.Health.Fhir.CosmosDb.UnitTests/Microsoft.Health.Fhir.CosmosDb.UnitTests.csproj
+++ b/src/Microsoft.Health.Fhir.CosmosDb.UnitTests/Microsoft.Health.Fhir.CosmosDb.UnitTests.csproj
@@ -6,6 +6,9 @@
+
+
+
diff --git a/src/Microsoft.Health.Fhir.CosmosDb/Features/Operations/Reindex/ReindexJobCosmosThrottleController.cs b/src/Microsoft.Health.Fhir.CosmosDb/Features/Operations/Reindex/ReindexJobCosmosThrottleController.cs
index fca670e9ae..cae209b843 100644
--- a/src/Microsoft.Health.Fhir.CosmosDb/Features/Operations/Reindex/ReindexJobCosmosThrottleController.cs
+++ b/src/Microsoft.Health.Fhir.CosmosDb/Features/Operations/Reindex/ReindexJobCosmosThrottleController.cs
@@ -10,6 +10,7 @@
using Microsoft.Extensions.Primitives;
using Microsoft.Health.Core;
using Microsoft.Health.Core.Features.Context;
+using Microsoft.Health.Fhir.Core.Extensions;
using Microsoft.Health.Fhir.Core.Features.Context;
using Microsoft.Health.Fhir.Core.Features.Operations;
using Microsoft.Health.Fhir.Core.Features.Operations.Reindex;
diff --git a/src/Microsoft.Health.Fhir.CosmosDb/Features/Storage/CosmosDbCollectionPhysicalPartitionInfo.cs b/src/Microsoft.Health.Fhir.CosmosDb/Features/Storage/CosmosDbCollectionPhysicalPartitionInfo.cs
index ff54542b2a..2c7d315501 100644
--- a/src/Microsoft.Health.Fhir.CosmosDb/Features/Storage/CosmosDbCollectionPhysicalPartitionInfo.cs
+++ b/src/Microsoft.Health.Fhir.CosmosDb/Features/Storage/CosmosDbCollectionPhysicalPartitionInfo.cs
@@ -17,6 +17,7 @@
using Microsoft.Extensions.Options;
using Microsoft.Health.Abstractions.Exceptions;
using Microsoft.Health.Extensions.DependencyInjection;
+using Microsoft.Health.Fhir.Core.Extensions;
using Microsoft.Health.Fhir.CosmosDb.Configs;
namespace Microsoft.Health.Fhir.CosmosDb.Features.Storage
@@ -70,7 +71,7 @@ private async Task BackgroundLoop(CancellationToken cancellationToken)
if (newPartitionCount != PhysicalPartitionCount)
{
- _logger.LogInformation("Physical partition count changed from {OldPhysicalPartitionCount} to {NewPhysicalPartitionCount}.", PhysicalPartitionCount, newPartitionCount);
+ _logger.LogInformation("Physical partition count changed from {OldPhysicalPartitionCount} to {NewPhysicalPartitionCount}", PhysicalPartitionCount, newPartitionCount);
}
PhysicalPartitionCount = newPartitionCount;
@@ -81,7 +82,7 @@ private async Task BackgroundLoop(CancellationToken cancellationToken)
}
catch (Exception e)
{
- _logger.LogError("Unable to get physical partition count.", e);
+ _logger.LogError(e, "Unable to get physical partition count");
}
}
}
@@ -162,7 +163,7 @@ public async ValueTask DisposeAsync()
{
try
{
- _backgroundLoopCancellationTokenSource.Cancel();
+ await _backgroundLoopCancellationTokenSource.CancelAsync();
await _backgroundLoopTask;
_backgroundLoopCancellationTokenSource.Dispose();
_backgroundLoopTask.Dispose();
diff --git a/src/Microsoft.Health.Fhir.CosmosDb/Features/Storage/CosmosDbDistributedLock.cs b/src/Microsoft.Health.Fhir.CosmosDb/Features/Storage/CosmosDbDistributedLock.cs
index 1509ccc908..99433011ab 100644
--- a/src/Microsoft.Health.Fhir.CosmosDb/Features/Storage/CosmosDbDistributedLock.cs
+++ b/src/Microsoft.Health.Fhir.CosmosDb/Features/Storage/CosmosDbDistributedLock.cs
@@ -12,6 +12,7 @@
using Microsoft.Extensions.Logging;
using Microsoft.Health.Abstractions.Exceptions;
using Microsoft.Health.Extensions.DependencyInjection;
+using Microsoft.Health.Fhir.Core.Extensions;
using Newtonsoft.Json;
namespace Microsoft.Health.Fhir.CosmosDb.Features.Storage
@@ -140,7 +141,8 @@ public async Task ReleaseLock()
try
{
- _keepAliveCancellationSource.Cancel();
+ await _keepAliveCancellationSource.CancelAsync();
+
try
{
await _keepAliveTask;
diff --git a/src/Microsoft.Health.Fhir.Shared.Api.UnitTests/Features/ActionResults/FhirResultTests.cs b/src/Microsoft.Health.Fhir.Shared.Api.UnitTests/Features/ActionResults/FhirResultTests.cs
index 2eb406b831..ca353bd728 100644
--- a/src/Microsoft.Health.Fhir.Shared.Api.UnitTests/Features/ActionResults/FhirResultTests.cs
+++ b/src/Microsoft.Health.Fhir.Shared.Api.UnitTests/Features/ActionResults/FhirResultTests.cs
@@ -90,9 +90,9 @@ public void GivenAFhirResult_WhenHeadersThatAlreadyExistsInResponseArePassed_The
ServiceProvider provider = collection.BuildServiceProvider();
context.HttpContext.RequestServices = provider;
- result.Headers.Add("testKey1", "3");
- result.Headers.Add("testKey2", "2");
- context.HttpContext.Response.Headers.Add("testKey2", "1");
+ result.Headers["testKey1"] = "3";
+ result.Headers["testKey2"] = "2";
+ context.HttpContext.Response.Headers["testKey2"] = "1";
result.ExecuteResultAsync(context);
diff --git a/src/Microsoft.Health.Fhir.Shared.Api.UnitTests/Features/Filters/FhirRequestContextRouteDataPopulatingFilterAttributeTests.cs b/src/Microsoft.Health.Fhir.Shared.Api.UnitTests/Features/Filters/FhirRequestContextRouteDataPopulatingFilterAttributeTests.cs
index 662af60b7f..45c5d2c73e 100644
--- a/src/Microsoft.Health.Fhir.Shared.Api.UnitTests/Features/Filters/FhirRequestContextRouteDataPopulatingFilterAttributeTests.cs
+++ b/src/Microsoft.Health.Fhir.Shared.Api.UnitTests/Features/Filters/FhirRequestContextRouteDataPopulatingFilterAttributeTests.cs
@@ -123,9 +123,7 @@ public void GivenANonResourceActionResult_WhenExecutedAnAction_ThenResourceTypeS
[Fact]
public void GivenPartialIndexHeader_WhenSearchReqeust_ThenFhirContextPropertySet()
{
- _httpContext.Request.Headers.Add(
- KnownHeaders.PartiallyIndexedParamsHeaderName,
- new Microsoft.Extensions.Primitives.StringValues(new string[] { "true" }));
+ _httpContext.Request.Headers[KnownHeaders.PartiallyIndexedParamsHeaderName] = new Microsoft.Extensions.Primitives.StringValues(new string[] { "true" });
_filterAttribute.OnActionExecuting(_actionExecutingContext);
diff --git a/src/Microsoft.Health.Fhir.Shared.Api.UnitTests/Features/Filters/ValidateBulkImportRequestFilterAttributeTests.cs b/src/Microsoft.Health.Fhir.Shared.Api.UnitTests/Features/Filters/ValidateBulkImportRequestFilterAttributeTests.cs
index 33938c55ca..59e53b33e7 100644
--- a/src/Microsoft.Health.Fhir.Shared.Api.UnitTests/Features/Filters/ValidateBulkImportRequestFilterAttributeTests.cs
+++ b/src/Microsoft.Health.Fhir.Shared.Api.UnitTests/Features/Filters/ValidateBulkImportRequestFilterAttributeTests.cs
@@ -43,8 +43,8 @@ public void GiveARequestWithInvalidPreferHeader_WhenGettingABulkImportOperationR
{
var context = CreateContext();
context.HttpContext.Request.Method = "GET";
- context.HttpContext.Request.Headers.Add(PreferHeaderName, preferHeader);
- context.HttpContext.Request.Headers.Add(HeaderNames.ContentType, CorrectContentTypeHeaderValue);
+ context.HttpContext.Request.Headers[PreferHeaderName] = preferHeader;
+ context.HttpContext.Request.Headers[HeaderNames.ContentType] = CorrectContentTypeHeaderValue;
Assert.Throws(() => _filter.OnActionExecuting(context));
}
@@ -57,8 +57,8 @@ public void GiveARequestWithInvalidPreferHeader_WhenCreatingABulkImportRequest_T
{
var context = CreateContext();
context.HttpContext.Request.Method = "POST";
- context.HttpContext.Request.Headers.Add(PreferHeaderName, preferHeader);
- context.HttpContext.Request.Headers.Add(HeaderNames.ContentType, CorrectContentTypeHeaderValue);
+ context.HttpContext.Request.Headers[PreferHeaderName] = preferHeader;
+ context.HttpContext.Request.Headers[HeaderNames.ContentType] = CorrectContentTypeHeaderValue;
Assert.Throws(() => _filter.OnActionExecuting(context));
}
@@ -71,8 +71,8 @@ public void GiveARequestWithInvalidPreferHeader_WhenCancelABulkImportRequest_The
{
var context = CreateContext();
context.HttpContext.Request.Method = "DELETE";
- context.HttpContext.Request.Headers.Add(PreferHeaderName, preferHeader);
- context.HttpContext.Request.Headers.Add(HeaderNames.ContentType, CorrectContentTypeHeaderValue);
+ context.HttpContext.Request.Headers[PreferHeaderName] = preferHeader;
+ context.HttpContext.Request.Headers[HeaderNames.ContentType] = CorrectContentTypeHeaderValue;
Assert.Throws(() => _filter.OnActionExecuting(context));
}
@@ -82,7 +82,7 @@ public void GivenARequestWithNoPreferHeader_WhenGettingABulkImportOperationReque
{
var context = CreateContext();
context.HttpContext.Request.Method = "GET";
- context.HttpContext.Request.Headers.Add(HeaderNames.ContentType, CorrectContentTypeHeaderValue);
+ context.HttpContext.Request.Headers[HeaderNames.ContentType] = CorrectContentTypeHeaderValue;
Assert.Throws(() => _filter.OnActionExecuting(context));
}
@@ -92,7 +92,7 @@ public void GivenARequestWithNoPreferHeader_WhenCreatingABulkImportRequest_ThenA
{
var context = CreateContext();
context.HttpContext.Request.Method = "POST";
- context.HttpContext.Request.Headers.Add(HeaderNames.ContentType, CorrectContentTypeHeaderValue);
+ context.HttpContext.Request.Headers[HeaderNames.ContentType] = CorrectContentTypeHeaderValue;
Assert.Throws(() => _filter.OnActionExecuting(context));
}
@@ -102,7 +102,7 @@ public void GivenARequestWithNoPreferHeader_WhenCancelABulkImportRequest_ThenARe
{
var context = CreateContext();
context.HttpContext.Request.Method = "DELETE";
- context.HttpContext.Request.Headers.Add(HeaderNames.ContentType, CorrectContentTypeHeaderValue);
+ context.HttpContext.Request.Headers[HeaderNames.ContentType] = CorrectContentTypeHeaderValue;
Assert.Throws(() => _filter.OnActionExecuting(context));
}
@@ -119,8 +119,8 @@ public void GiveARequestWithInvalidContentTypeHeader_WhenCreatingABulkImportRequ
{
var context = CreateContext();
context.HttpContext.Request.Method = "POST";
- context.HttpContext.Request.Headers.Add(PreferHeaderName, CorrectPreferHeaderValue);
- context.HttpContext.Request.Headers.Add(HeaderNames.ContentType, contentTypeHeader);
+ context.HttpContext.Request.Headers[PreferHeaderName] = CorrectPreferHeaderValue;
+ context.HttpContext.Request.Headers[HeaderNames.ContentType] = contentTypeHeader;
Assert.Throws(() => _filter.OnActionExecuting(context));
}
@@ -130,7 +130,7 @@ public void GivenARequestWithNoContentTypeHeader_WhenCreatingABulkImportRequest_
{
var context = CreateContext();
context.HttpContext.Request.Method = "POST";
- context.HttpContext.Request.Headers.Add(PreferHeaderName, CorrectPreferHeaderValue);
+ context.HttpContext.Request.Headers[PreferHeaderName] = CorrectPreferHeaderValue;
Assert.Throws(() => _filter.OnActionExecuting(context));
}
@@ -140,7 +140,7 @@ public void GivenARequestWithNoContentTypeHeader_WhenGetABulkImportRequest_ThenT
{
var context = CreateContext();
context.HttpContext.Request.Method = "GET";
- context.HttpContext.Request.Headers.Add(PreferHeaderName, CorrectPreferHeaderValue);
+ context.HttpContext.Request.Headers[PreferHeaderName] = CorrectPreferHeaderValue;
_filter.OnActionExecuting(context);
}
@@ -150,7 +150,7 @@ public void GivenARequestWithNoContentTypeHeader_WhenCancelABulkImportRequest_Th
{
var context = CreateContext();
context.HttpContext.Request.Method = "DELETE";
- context.HttpContext.Request.Headers.Add(PreferHeaderName, CorrectPreferHeaderValue);
+ context.HttpContext.Request.Headers[PreferHeaderName] = CorrectPreferHeaderValue;
_filter.OnActionExecuting(context);
}
@@ -160,8 +160,8 @@ public void GivenARequestWithCorrectHeader_WhenCreatingABulkImportRequest_ThenTh
{
var context = CreateContext();
context.HttpContext.Request.Method = "POST";
- context.HttpContext.Request.Headers.Add(PreferHeaderName, CorrectPreferHeaderValue);
- context.HttpContext.Request.Headers.Add(HeaderNames.ContentType, CorrectContentTypeHeaderValue);
+ context.HttpContext.Request.Headers[PreferHeaderName] = CorrectPreferHeaderValue;
+ context.HttpContext.Request.Headers[HeaderNames.ContentType] = CorrectContentTypeHeaderValue;
_filter.OnActionExecuting(context);
}
diff --git a/src/Microsoft.Health.Fhir.Shared.Api.UnitTests/Features/Filters/ValidateContentTypeFilterAttributeTests.cs b/src/Microsoft.Health.Fhir.Shared.Api.UnitTests/Features/Filters/ValidateContentTypeFilterAttributeTests.cs
index fe84ff4d7f..2e2dde8674 100644
--- a/src/Microsoft.Health.Fhir.Shared.Api.UnitTests/Features/Filters/ValidateContentTypeFilterAttributeTests.cs
+++ b/src/Microsoft.Health.Fhir.Shared.Api.UnitTests/Features/Filters/ValidateContentTypeFilterAttributeTests.cs
@@ -75,7 +75,7 @@ public async Task GivenARequestWithAValidFormatQueryStringAndAnEmptyAcceptHeader
var actionExecutedDelegate = CreateActionExecutedDelegate(context);
context.HttpContext.Request.QueryString = new QueryString($"?_format=json");
- context.HttpContext.Request.Headers.Add("Accept", string.Empty);
+ context.HttpContext.Request.Headers["Accept"] = string.Empty;
await filter.OnActionExecutionAsync(context, actionExecutedDelegate);
}
@@ -92,7 +92,7 @@ public async Task GivenARequestWithAValidFormatQueryStringAndAValidAcceptHeader_
var actionExecutedDelegate = CreateActionExecutedDelegate(context);
context.HttpContext.Request.QueryString = new QueryString($"?_format={requestFormat}");
- context.HttpContext.Request.Headers.Add("Accept", "application/json");
+ context.HttpContext.Request.Headers["Accept"] = "application/json";
await filter.OnActionExecutionAsync(context, actionExecutedDelegate);
}
@@ -129,8 +129,8 @@ public async Task GivenARequestWithAValidFormatQueryStringAndAnInvalidContentTyp
context.HttpContext.Request.QueryString = new QueryString($"?_format={requestFormat}");
context.HttpContext.Request.Method = HttpMethod.Post.ToString();
- context.HttpContext.Request.Headers.Add("Content-Type", contentTypeHeader);
- context.HttpContext.Request.Headers.Add("Accept", contentTypeHeader);
+ context.HttpContext.Request.Headers["Content-Type"] = contentTypeHeader;
+ context.HttpContext.Request.Headers["Accept"] = contentTypeHeader;
await Assert.ThrowsAsync(async () => await filter.OnActionExecutionAsync(context, actionExecutedDelegate));
}
@@ -153,7 +153,7 @@ public async Task GivenARequestWithAnInvalidFormatQueryStringAndAnInvalidContent
context.HttpContext.Request.QueryString = new QueryString($"?_format={requestFormat}");
context.HttpContext.Request.Method = HttpMethod.Post.ToString();
- context.HttpContext.Request.Headers.Add("Content-Type", "application/fhir+xml");
+ context.HttpContext.Request.Headers["Content-Type"] = "application/fhir+xml";
await Assert.ThrowsAsync(async () => await filter.OnActionExecutionAsync(context, actionExecutedDelegate));
}
@@ -171,7 +171,7 @@ public async Task GivenARequestWithAValidAcceptHeader_WhenValidatingTheContentTy
var context = CreateContext(Guid.NewGuid().ToString());
var actionExecutedDelegate = CreateActionExecutedDelegate(context);
- context.HttpContext.Request.Headers.Add("Accept", acceptHeader);
+ context.HttpContext.Request.Headers["Accept"] = acceptHeader;
await filter.OnActionExecutionAsync(context, actionExecutedDelegate);
}
@@ -189,7 +189,7 @@ public async Task GivenARequestWithAnInvalidAcceptHeader_WhenValidatingTheConten
var context = CreateContext(Guid.NewGuid().ToString());
var actionExecutedDelegate = CreateActionExecutedDelegate(context);
- context.HttpContext.Request.Headers.Add("Accept", acceptHeader);
+ context.HttpContext.Request.Headers["Accept"] = acceptHeader;
await filter.OnActionExecutionAsync(context, actionExecutedDelegate);
}
@@ -206,7 +206,7 @@ public async Task GivenARequestWithAnInvalidApplicationAcceptHeader_WhenValidati
var context = CreateContext(Guid.NewGuid().ToString());
var actionExecutedDelegate = CreateActionExecutedDelegate(context);
- context.HttpContext.Request.Headers.Add("Accept", acceptHeader);
+ context.HttpContext.Request.Headers["Accept"] = acceptHeader;
await Assert.ThrowsAsync(async () => await filter.OnActionExecutionAsync(context, actionExecutedDelegate));
}
@@ -229,10 +229,10 @@ public async Task GivenARequestWithAnInvalidAcceptHeaderAndAnInvalidContentTypeH
var context = CreateContext(Guid.NewGuid().ToString());
var actionExecutedDelegate = CreateActionExecutedDelegate(context);
- context.HttpContext.Request.Headers.Add("Accept", acceptHeader);
+ context.HttpContext.Request.Headers["Accept"] = acceptHeader;
context.HttpContext.Request.Method = HttpMethod.Post.ToString();
- context.HttpContext.Request.Headers.Add("Content-Type", contentTypeHeader);
+ context.HttpContext.Request.Headers["Content-Type"] = contentTypeHeader;
// The fact that the Accept header is invalid is ignored, but an exception related to the invalid Content Type header is still thrown.
await Assert.ThrowsAsync(async () => await filter.OnActionExecutionAsync(context, actionExecutedDelegate));
@@ -253,10 +253,10 @@ public async Task GivenARequestWithAnInvalidApplicationAcceptHeaderAndAnInvalidC
var context = CreateContext(Guid.NewGuid().ToString());
var actionExecutedDelegate = CreateActionExecutedDelegate(context);
- context.HttpContext.Request.Headers.Add("Accept", acceptHeader);
+ context.HttpContext.Request.Headers["Accept"] = acceptHeader;
context.HttpContext.Request.Method = HttpMethod.Post.ToString();
- context.HttpContext.Request.Headers.Add("Content-Type", contentTypeHeader);
+ context.HttpContext.Request.Headers["Content-Type"] = contentTypeHeader;
// The Accept header is invalid and has the format "application/", so an exception for that is thrown.
await Assert.ThrowsAsync(async () => await filter.OnActionExecutionAsync(context, actionExecutedDelegate));
@@ -274,7 +274,7 @@ public async Task GivenARequestWithNoAcceptHeaderAndAnInvalidContentTypeHeader_W
var actionExecutedDelegate = CreateActionExecutedDelegate(context);
context.HttpContext.Request.Method = HttpMethod.Post.ToString();
- context.HttpContext.Request.Headers.Add("Content-Type", contentTypeHeader);
+ context.HttpContext.Request.Headers["Content-Type"] = contentTypeHeader;
await Assert.ThrowsAsync(async () => await filter.OnActionExecutionAsync(context, actionExecutedDelegate));
}
@@ -291,8 +291,8 @@ public async Task GivenARequestWithAValidAcceptHeaderAndAValidContentTypeHeader_
var actionExecutedDelegate = CreateActionExecutedDelegate(context);
context.HttpContext.Request.Method = HttpMethod.Post.ToString();
- context.HttpContext.Request.Headers.Add("Content-Type", contentTypeHeader);
- context.HttpContext.Request.Headers.Add("Accept", contentTypeHeader);
+ context.HttpContext.Request.Headers["Content-Type"] = contentTypeHeader;
+ context.HttpContext.Request.Headers["Accept"] = contentTypeHeader;
await filter.OnActionExecutionAsync(context, actionExecutedDelegate);
}
@@ -309,10 +309,10 @@ public async Task GivenARequestWithAValidAcceptHeaderAndAnInvalidContentTypeHead
var context = CreateContext(Guid.NewGuid().ToString());
var actionExecutedDelegate = CreateActionExecutedDelegate(context);
- context.HttpContext.Request.Headers.Add("Accept", "application/json");
+ context.HttpContext.Request.Headers["Accept"] = "application/json";
context.HttpContext.Request.Method = HttpMethod.Post.ToString();
- context.HttpContext.Request.Headers.Add("Content-Type", contentTypeHeader);
+ context.HttpContext.Request.Headers["Content-Type"] = contentTypeHeader;
await Assert.ThrowsAsync(async () => await filter.OnActionExecutionAsync(context, actionExecutedDelegate));
}
@@ -344,7 +344,7 @@ public async Task GivenACapabilityStatementWithMultipleFormats_WhenValidatingThe
var actionExecutedDelegate = CreateActionExecutedDelegate(context);
context.HttpContext.Request.QueryString = new QueryString($"?_format={formatQuerystring}");
- context.HttpContext.Request.Headers.Add("Accept", formats[1]);
+ context.HttpContext.Request.Headers["Accept"] = formats[1];
await filter.OnActionExecutionAsync(context, actionExecutedDelegate);
@@ -370,7 +370,7 @@ public async Task GivenARequestWithAValidAcceptHeaderAndFormatOverride_WhenSetti
var context = CreateContext(Guid.NewGuid().ToString());
var actionExecutedDelegate = CreateActionExecutedDelegate(context);
- context.HttpContext.Request.Headers.Add("Accept", acceptHeader);
+ context.HttpContext.Request.Headers["Accept"] = acceptHeader;
context.HttpContext.Request.Query = new QueryCollection(new Dictionary
{
{ KnownQueryParameterNames.Format, "xml" },
diff --git a/src/Microsoft.Health.Fhir.Shared.Api.UnitTests/Features/Filters/ValidateExportRequestFilterAttributeTests.cs b/src/Microsoft.Health.Fhir.Shared.Api.UnitTests/Features/Filters/ValidateExportRequestFilterAttributeTests.cs
index e53a4333eb..eda913ef64 100644
--- a/src/Microsoft.Health.Fhir.Shared.Api.UnitTests/Features/Filters/ValidateExportRequestFilterAttributeTests.cs
+++ b/src/Microsoft.Health.Fhir.Shared.Api.UnitTests/Features/Filters/ValidateExportRequestFilterAttributeTests.cs
@@ -48,7 +48,7 @@ public void GivenARequestWithInvalidAcceptHeader_WhenGettingAnExportOperationReq
{
var context = CreateContext();
- context.HttpContext.Request.Headers.Add(HeaderNames.Accept, acceptHeader);
+ context.HttpContext.Request.Headers[HeaderNames.Accept] = acceptHeader;
Assert.Throws(() => _filter.OnActionExecuting(context));
}
@@ -58,7 +58,7 @@ public void GivenARequestWithNoAcceptHeader_WhenGettingAnExportOperationRequest_
{
var context = CreateContext();
- context.HttpContext.Request.Headers.Add(PreferHeaderName, CorrectPreferHeaderValue);
+ context.HttpContext.Request.Headers[PreferHeaderName] = CorrectPreferHeaderValue;
Assert.Throws(() => _filter.OnActionExecuting(context));
}
@@ -71,7 +71,7 @@ public void GiveARequestWithInvalidPreferHeader_WhenGettingAnExportOperationRequ
{
var context = CreateContext();
- context.HttpContext.Request.Headers.Add(PreferHeaderName, preferHeader);
+ context.HttpContext.Request.Headers[PreferHeaderName] = preferHeader;
Assert.Throws(() => _filter.OnActionExecuting(context));
}
@@ -81,7 +81,7 @@ public void GivenARequestWithNoPreferHeader_WhenGettingAnExportOperationRequest_
{
var context = CreateContext();
- context.HttpContext.Request.Headers.Add(HeaderNames.Accept, CorrectAcceptHeaderValue);
+ context.HttpContext.Request.Headers[HeaderNames.Accept] = CorrectAcceptHeaderValue;
Assert.Throws(() => _filter.OnActionExecuting(context));
}
@@ -93,8 +93,8 @@ public void GivenARequestWithNoPreferHeader_WhenGettingAnExportOperationRequest_
public void GivenARequestWithCorrectHeadersAndUnsupportedQueryParam_WhenGettingAnExportOperationRequest_ThenARequestNotValidExceptionShouldBeThrown(string queryParamName)
{
var context = CreateContext();
- context.HttpContext.Request.Headers.Add(HeaderNames.Accept, CorrectAcceptHeaderValue);
- context.HttpContext.Request.Headers.Add(PreferHeaderName, CorrectPreferHeaderValue);
+ context.HttpContext.Request.Headers[HeaderNames.Accept] = CorrectAcceptHeaderValue;
+ context.HttpContext.Request.Headers[PreferHeaderName] = CorrectPreferHeaderValue;
var queryParams = new Dictionary()
{
@@ -111,8 +111,8 @@ public void GivenARequestWithCorrectHeadersAndUnsupportedQueryParam_WhenGettingA
public void GivenARequestWithAnonymizedExportQueryParam_WhenGettingAnDefaultExportOperationRequest_ThenTheResultIsSuccessful(params string[] queryParamNames)
{
var context = CreateContext();
- context.HttpContext.Request.Headers.Add(HeaderNames.Accept, CorrectAcceptHeaderValue);
- context.HttpContext.Request.Headers.Add(PreferHeaderName, CorrectPreferHeaderValue);
+ context.HttpContext.Request.Headers[HeaderNames.Accept] = CorrectAcceptHeaderValue;
+ context.HttpContext.Request.Headers[PreferHeaderName] = CorrectPreferHeaderValue;
var queryParams = new Dictionary();
foreach (string queryParamName in queryParamNames)
@@ -133,8 +133,8 @@ public void GivenARequestWithAnonymizedExportQueryParam_WhenGettingAnDefaultExpo
public void GivenARequestWithCorrectHeaderAndSupportedQueryParam_WhenGettingAnExportOperationRequest_ThenTheResultIsSuccessful(params string[] queryParamNames)
{
var context = CreateContext();
- context.HttpContext.Request.Headers.Add(HeaderNames.Accept, CorrectAcceptHeaderValue);
- context.HttpContext.Request.Headers.Add(PreferHeaderName, CorrectPreferHeaderValue);
+ context.HttpContext.Request.Headers[HeaderNames.Accept] = CorrectAcceptHeaderValue;
+ context.HttpContext.Request.Headers[PreferHeaderName] = CorrectPreferHeaderValue;
var queryParams = new Dictionary();
foreach (string queryParamName in queryParamNames)
@@ -154,8 +154,8 @@ public void GivenARequestWithCorrectHeaderAndSupportedQueryParam_WhenGettingAnEx
public void GivenARequestWithCorrectHeaderAndSupportedOutputFormatQueryParam_WhenGettingAnExportOperationRequest_ThenTheResultIsSuccessful(string outputFormat)
{
var context = CreateContext();
- context.HttpContext.Request.Headers.Add(HeaderNames.Accept, CorrectAcceptHeaderValue);
- context.HttpContext.Request.Headers.Add(PreferHeaderName, CorrectPreferHeaderValue);
+ context.HttpContext.Request.Headers[HeaderNames.Accept] = CorrectAcceptHeaderValue;
+ context.HttpContext.Request.Headers[PreferHeaderName] = CorrectPreferHeaderValue;
var queryParams = new Dictionary();
queryParams.Add(KnownQueryParameterNames.OutputFormat, outputFormat);
@@ -169,8 +169,8 @@ public void GivenARequestWithCorrectHeaderAndSupportedOutputFormatQueryParam_Whe
public void GivenARequestWithCorrectHeaderAndUnsupportedOutputFormatQueryParam_WhenGettingAnExportOperationRequest_ThenARequestNotValidExceptionShouldBeThrown()
{
var context = CreateContext();
- context.HttpContext.Request.Headers.Add(HeaderNames.Accept, CorrectAcceptHeaderValue);
- context.HttpContext.Request.Headers.Add(PreferHeaderName, CorrectPreferHeaderValue);
+ context.HttpContext.Request.Headers[HeaderNames.Accept] = CorrectAcceptHeaderValue;
+ context.HttpContext.Request.Headers[PreferHeaderName] = CorrectPreferHeaderValue;
var queryParams = new Dictionary();
queryParams.Add(KnownQueryParameterNames.OutputFormat, "invalid");
@@ -184,8 +184,8 @@ public void GivenARequestWithCorrectHeaderAndUnsupportedOutputFormatQueryParam_W
public void GivenARequestWithCorrectHeaderAndNoQueryParams_WhenGettingAnExportOperationRequest_ThenTheResultIsSuccessful()
{
var context = CreateContext();
- context.HttpContext.Request.Headers.Add(HeaderNames.Accept, CorrectAcceptHeaderValue);
- context.HttpContext.Request.Headers.Add(PreferHeaderName, CorrectPreferHeaderValue);
+ context.HttpContext.Request.Headers[HeaderNames.Accept] = CorrectAcceptHeaderValue;
+ context.HttpContext.Request.Headers[PreferHeaderName] = CorrectPreferHeaderValue;
_filter.OnActionExecuting(context);
}
diff --git a/src/Microsoft.Health.Fhir.Shared.Api.UnitTests/Features/Headers/FhirResultExtensionsTests.cs b/src/Microsoft.Health.Fhir.Shared.Api.UnitTests/Features/Headers/FhirResultExtensionsTests.cs
index caeb8484a6..14138e3077 100644
--- a/src/Microsoft.Health.Fhir.Shared.Api.UnitTests/Features/Headers/FhirResultExtensionsTests.cs
+++ b/src/Microsoft.Health.Fhir.Shared.Api.UnitTests/Features/Headers/FhirResultExtensionsTests.cs
@@ -93,9 +93,11 @@ public void WhenAddingTwoHeaders_ThenFhirResultHasAtLeastTwoHeaders()
[Fact]
public void WhenAddingSameHeaderTwice_ThenOnlyOneHeaderIsPresent()
{
- Assert.Throws(() => FhirResult.Create(_mockResource)
+ var result = FhirResult.Create(_mockResource)
.SetLastModifiedHeader()
- .SetLastModifiedHeader());
+ .SetLastModifiedHeader();
+
+ Assert.Single(result.Headers);
}
[Fact]
diff --git a/src/Microsoft.Health.Fhir.Shared.Api.UnitTests/Features/Security/RequestHandlerCheckAccessTests.cs b/src/Microsoft.Health.Fhir.Shared.Api.UnitTests/Features/Security/RequestHandlerCheckAccessTests.cs
index c182587f5a..23dfcf1412 100644
--- a/src/Microsoft.Health.Fhir.Shared.Api.UnitTests/Features/Security/RequestHandlerCheckAccessTests.cs
+++ b/src/Microsoft.Health.Fhir.Shared.Api.UnitTests/Features/Security/RequestHandlerCheckAccessTests.cs
@@ -7,6 +7,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
+using System.Runtime.CompilerServices;
using System.Runtime.Serialization;
using System.Threading;
using System.Threading.Tasks;
@@ -107,7 +108,7 @@ static IEnumerable GetFieldsIncludingFromBaseTypes(Type t)
static object CreateObject(Type type)
{
- return FormatterServices.GetSafeUninitializedObject(type);
+ return RuntimeHelpers.GetUninitializedObject(type);
}
}
}
diff --git a/src/Microsoft.Health.Fhir.Shared.Api/Controllers/BulkDeleteController.cs b/src/Microsoft.Health.Fhir.Shared.Api/Controllers/BulkDeleteController.cs
index 0c7f7d88aa..88b94327b8 100644
--- a/src/Microsoft.Health.Fhir.Shared.Api/Controllers/BulkDeleteController.cs
+++ b/src/Microsoft.Health.Fhir.Shared.Api/Controllers/BulkDeleteController.cs
@@ -76,7 +76,7 @@ public async Task GetBulkDeleteStatusById(long idParameter)
var actionResult = JobResult.FromResults(result.Results, result.Issues, result.HttpStatusCode);
if (result.HttpStatusCode == System.Net.HttpStatusCode.Accepted)
{
- actionResult.Headers.Add(KnownHeaders.Progress, Resources.InProgress);
+ actionResult.Headers[KnownHeaders.Progress] = Resources.InProgress;
}
return actionResult;
diff --git a/src/Microsoft.Health.Fhir.Shared.Api/Controllers/EverythingController.cs b/src/Microsoft.Health.Fhir.Shared.Api/Controllers/EverythingController.cs
index 7ca2214e34..3e8bfcc179 100644
--- a/src/Microsoft.Health.Fhir.Shared.Api/Controllers/EverythingController.cs
+++ b/src/Microsoft.Health.Fhir.Shared.Api/Controllers/EverythingController.cs
@@ -82,7 +82,7 @@ public async Task PatientEverythingById(
return FhirResult.Create(result.Bundle);
}
- private IReadOnlyList> ReadUnsupportedParameters()
+ private List> ReadUnsupportedParameters()
{
IReadOnlyList> parameters = Request.Query
.SelectMany(query => query.Value, (query, value) => Tuple.Create(query.Key, value))
diff --git a/src/Microsoft.Health.Fhir.Shared.Api/Controllers/FhirController.cs b/src/Microsoft.Health.Fhir.Shared.Api/Controllers/FhirController.cs
index 6453762017..5f18b6dab9 100644
--- a/src/Microsoft.Health.Fhir.Shared.Api/Controllers/FhirController.cs
+++ b/src/Microsoft.Health.Fhir.Shared.Api/Controllers/FhirController.cs
@@ -242,7 +242,7 @@ public async Task ConditionalUpdate([FromBody] Resource resource)
return ToSaveOutcomeResult(saveOutcome);
}
- private IActionResult ToSaveOutcomeResult(SaveOutcome saveOutcome)
+ private FhirResult ToSaveOutcomeResult(SaveOutcome saveOutcome)
{
switch (saveOutcome.Outcome)
{
@@ -444,7 +444,7 @@ public async Task ConditionalDelete(string typeParameter, [FromQu
if (maxDeleteCount.HasValue)
{
- Response.Headers.Add(KnownHeaders.ItemsDeleted, (response?.ResourcesDeleted ?? 0).ToString(CultureInfo.InvariantCulture));
+ Response.Headers[KnownHeaders.ItemsDeleted] = (response?.ResourcesDeleted ?? 0).ToString(CultureInfo.InvariantCulture);
}
return FhirResult.NoContent().SetETagHeader(response?.WeakETag);
diff --git a/src/Microsoft.Health.Fhir.Shared.Api/Features/Filters/OperationOutcomeExceptionFilterAttribute.cs b/src/Microsoft.Health.Fhir.Shared.Api/Features/Filters/OperationOutcomeExceptionFilterAttribute.cs
index 966f7e27d7..40a74d52f1 100644
--- a/src/Microsoft.Health.Fhir.Shared.Api/Features/Filters/OperationOutcomeExceptionFilterAttribute.cs
+++ b/src/Microsoft.Health.Fhir.Shared.Api/Features/Filters/OperationOutcomeExceptionFilterAttribute.cs
@@ -82,7 +82,7 @@ public override void OnActionExecuted(ActionExecutedContext context)
operationOutcomeResult.StatusCode = HttpStatusCode.Gone;
if (!string.IsNullOrEmpty(resourceGoneException.DeletedResource?.VersionId))
{
- operationOutcomeResult.Headers.Add(HeaderNames.ETag, WeakETag.FromVersionId(resourceGoneException.DeletedResource.VersionId).ToString());
+ operationOutcomeResult.Headers[HeaderNames.ETag] = WeakETag.FromVersionId(resourceGoneException.DeletedResource.VersionId).ToString();
}
break;
@@ -167,7 +167,7 @@ public override void OnActionExecuted(ActionExecutedContext context)
if (!string.IsNullOrEmpty(everythingOperationException.ContentLocationHeaderValue))
{
- operationOutcomeResult.Headers.Add(HeaderNames.ContentLocation, everythingOperationException.ContentLocationHeaderValue);
+ operationOutcomeResult.Headers[HeaderNames.ContentLocation] = everythingOperationException.ContentLocationHeaderValue;
}
break;
diff --git a/src/Microsoft.Health.Fhir.Shared.Api/Features/Formatters/FormatterExtensions.cs b/src/Microsoft.Health.Fhir.Shared.Api/Features/Formatters/FormatterExtensions.cs
index 110c78bde7..c6e6280141 100644
--- a/src/Microsoft.Health.Fhir.Shared.Api/Features/Formatters/FormatterExtensions.cs
+++ b/src/Microsoft.Health.Fhir.Shared.Api/Features/Formatters/FormatterExtensions.cs
@@ -15,7 +15,7 @@ namespace Microsoft.Health.Fhir.Api.Features.Formatters
{
public static class FormatterExtensions
{
- private static readonly IDictionary ResourceFormatContentType = new Dictionary
+ private static readonly Dictionary ResourceFormatContentType = new Dictionary
{
{ ResourceFormat.Json, KnownContentTypes.JsonContentType },
{ ResourceFormat.Xml, KnownContentTypes.XmlContentType },
diff --git a/src/Microsoft.Health.Fhir.Shared.Api/Features/Formatters/HtmlOutputFormatter.cs b/src/Microsoft.Health.Fhir.Shared.Api/Features/Formatters/HtmlOutputFormatter.cs
index ff63dba370..ef7fc191db 100644
--- a/src/Microsoft.Health.Fhir.Shared.Api/Features/Formatters/HtmlOutputFormatter.cs
+++ b/src/Microsoft.Health.Fhir.Shared.Api/Features/Formatters/HtmlOutputFormatter.cs
@@ -6,6 +6,7 @@
using System;
using System.Buffers;
using System.IO;
+using System.Linq;
using System.Text;
using EnsureThat;
using Hl7.Fhir.Model;
@@ -99,7 +100,11 @@ public override async Task WriteResponseBodyAsync(OutputFormatterWriteContext co
jsonTextWriter.ArrayPool = _charPool;
jsonTextWriter.Formatting = Formatting.Indented;
- await _fhirJsonSerializer.SerializeAsync(resourceInstance, jsonTextWriter, context.HttpContext.GetSummaryTypeOrDefault(), context.HttpContext.GetElementsOrDefault());
+ await _fhirJsonSerializer.SerializeAsync(
+ resourceInstance,
+ jsonTextWriter,
+ context.HttpContext.GetSummaryTypeOrDefault(),
+ context.HttpContext.GetElementsOrDefault().ToArray());
}
var viewDictionary = new ViewDataDictionary(new EmptyModelMetadataProvider(), new ModelStateDictionary())
diff --git a/src/Microsoft.Health.Fhir.Shared.Api/Features/Formatters/HttpContextExtensions.cs b/src/Microsoft.Health.Fhir.Shared.Api/Features/Formatters/HttpContextExtensions.cs
index 4e3871f3aa..597dc85b95 100644
--- a/src/Microsoft.Health.Fhir.Shared.Api/Features/Formatters/HttpContextExtensions.cs
+++ b/src/Microsoft.Health.Fhir.Shared.Api/Features/Formatters/HttpContextExtensions.cs
@@ -4,12 +4,14 @@
// -------------------------------------------------------------------------------------------------
using System;
+using System.Collections.Generic;
using System.Linq;
using System.Net;
using Hl7.Fhir.Rest;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.Health.Fhir.Core.Features;
+using Microsoft.Health.Fhir.Core.Features.Search;
namespace Microsoft.Health.Fhir.Api.Features.Formatters
{
@@ -39,14 +41,14 @@ public static SummaryType GetSummaryTypeOrDefault(this HttpContext context)
return SummaryType.False;
}
- public static string[] GetElementsOrDefault(this HttpContext context)
+ public static IReadOnlyList GetElementsOrDefault(this HttpContext context)
{
var query = context.Request.Query[KnownQueryParameterNames.Elements].FirstOrDefault();
if (!string.IsNullOrWhiteSpace(query) &&
(context.Response.StatusCode == (int)HttpStatusCode.OK || context.Response.StatusCode == (int)HttpStatusCode.Created))
{
- var elements = query.Split(new char[1] { ',' });
+ IReadOnlyList elements = query.SplitByOrSeparator();
return elements;
}
@@ -72,7 +74,7 @@ public static bool GetPrettyOrDefault(this HttpContext context)
public static void AllowSynchronousIO(this HttpContext context)
{
- var bodyControlFeature = context.Features.Get();
+ IHttpBodyControlFeature bodyControlFeature = context.Features.Get();
if (bodyControlFeature != null)
{
bodyControlFeature.AllowSynchronousIO = true;
diff --git a/src/Microsoft.Health.Fhir.Shared.Api/Features/Headers/FhirResultExtensions.cs b/src/Microsoft.Health.Fhir.Shared.Api/Features/Headers/FhirResultExtensions.cs
index d8dd8cd28a..c0b012eda1 100644
--- a/src/Microsoft.Health.Fhir.Shared.Api/Features/Headers/FhirResultExtensions.cs
+++ b/src/Microsoft.Health.Fhir.Shared.Api/Features/Headers/FhirResultExtensions.cs
@@ -3,6 +3,7 @@
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// -------------------------------------------------------------------------------------------------
+using System;
using System.Globalization;
using Microsoft.Health.Fhir.Api.Features.ActionResults;
using Microsoft.Health.Fhir.Core.Features.Persistence;
@@ -24,7 +25,7 @@ public static FhirResult SetLocationHeader(this FhirResult fhirResult, IUrlResol
if (url.IsAbsoluteUri)
{
- fhirResult.Headers.Add(HeaderNames.Location, url.AbsoluteUri);
+ fhirResult.Headers[HeaderNames.Location] = url.AbsoluteUri;
}
}
@@ -46,7 +47,7 @@ public static FhirResult SetETagHeader(this FhirResult fhirResult, WeakETag weak
{
if (weakETag != null)
{
- fhirResult.Headers.Add(HeaderNames.ETag, weakETag.ToString());
+ fhirResult.Headers[HeaderNames.ETag] = weakETag.ToString();
}
return fhirResult;
@@ -56,10 +57,11 @@ public static FhirResult SetLastModifiedHeader(this FhirResult fhirResult)
{
IResourceElement resource = fhirResult.Result;
- var lastUpdated = resource?.LastUpdated;
+ DateTimeOffset? lastUpdated = resource?.LastUpdated;
+
if (lastUpdated != null)
{
- fhirResult.Headers.Add(HeaderNames.LastModified, lastUpdated.Value.ToString("r", CultureInfo.InvariantCulture));
+ fhirResult.Headers[HeaderNames.LastModified] = lastUpdated.Value.ToString("r", CultureInfo.InvariantCulture);
}
return fhirResult;
diff --git a/src/Microsoft.Health.Fhir.Shared.Api/Features/Operations/ParametersExtensions.cs b/src/Microsoft.Health.Fhir.Shared.Api/Features/Operations/ParametersExtensions.cs
index bc60e2460c..0d7a23078c 100644
--- a/src/Microsoft.Health.Fhir.Shared.Api/Features/Operations/ParametersExtensions.cs
+++ b/src/Microsoft.Health.Fhir.Shared.Api/Features/Operations/ParametersExtensions.cs
@@ -33,14 +33,14 @@ public static bool TryGetStringValue(this Parameters.ParameterComponent paramCom
public static bool TryGetBooleanValue(this Parameters.ParameterComponent paramComponent, out bool boolValue)
{
- Element booleanElement = paramComponent?.Value;
+ DataType booleanElement = paramComponent?.Value;
return bool.TryParse(booleanElement?.ToString(), out boolValue);
}
public static bool TryGetUriValue(this Parameters.ParameterComponent paramComponent, out Uri uriValue)
{
- Element uriElement = paramComponent?.Value;
+ DataType uriElement = paramComponent?.Value;
return Uri.TryCreate(uriElement?.ToString(), UriKind.RelativeOrAbsolute, out uriValue);
}
diff --git a/src/Microsoft.Health.Fhir.Shared.Api/Features/Resources/Bundle/BundleHandler.cs b/src/Microsoft.Health.Fhir.Shared.Api/Features/Resources/Bundle/BundleHandler.cs
index 594d6a72dd..d94e4fa43b 100644
--- a/src/Microsoft.Health.Fhir.Shared.Api/Features/Resources/Bundle/BundleHandler.cs
+++ b/src/Microsoft.Health.Fhir.Shared.Api/Features/Resources/Bundle/BundleHandler.cs
@@ -523,7 +523,7 @@ private async Task GenerateRequest(EntryComponent entry, int order, Cancellation
if (requestMethod == HTTPVerb.POST
|| requestMethod == HTTPVerb.PUT)
{
- httpContext.Request.Headers.Add(HeaderNames.ContentType, new StringValues(KnownContentTypes.JsonContentType));
+ httpContext.Request.Headers[HeaderNames.ContentType] = new StringValues(KnownContentTypes.JsonContentType);
if (entry.Resource != null)
{
@@ -540,7 +540,7 @@ private async Task GenerateRequest(EntryComponent entry, int order, Cancellation
string.Equals(KnownResourceTypes.Parameters, entry.Resource?.TypeName, StringComparison.Ordinal) &&
entry.Resource is Parameters parametersResource)
{
- httpContext.Request.Headers.Add(HeaderNames.ContentType, new StringValues(KnownContentTypes.JsonContentType));
+ httpContext.Request.Headers[HeaderNames.ContentType] = new StringValues(KnownContentTypes.JsonContentType);
var memoryStream = new MemoryStream(await _fhirJsonSerializer.SerializeToBytesAsync(parametersResource));
memoryStream.Seek(0, SeekOrigin.Begin);
httpContext.Request.Body = memoryStream;
@@ -552,7 +552,7 @@ private async Task GenerateRequest(EntryComponent entry, int order, Cancellation
string.Equals(KnownResourceTypes.Binary, entry.Resource?.TypeName, StringComparison.Ordinal) &&
entry.Resource is Binary binaryResource && string.Equals(KnownMediaTypeHeaderValues.ApplicationJsonPatch.ToString(), binaryResource.ContentType, StringComparison.OrdinalIgnoreCase))
{
- httpContext.Request.Headers.Add(HeaderNames.ContentType, new StringValues(binaryResource.ContentType));
+ httpContext.Request.Headers[HeaderNames.ContentType] = new StringValues(binaryResource.ContentType);
var memoryStream = new MemoryStream(binaryResource.Data);
memoryStream.Seek(0, SeekOrigin.Begin);
httpContext.Request.Body = memoryStream;
@@ -575,7 +575,7 @@ private static void AddHeaderIfNeeded(string headerKey, string headerValue, Http
{
if (!string.IsNullOrWhiteSpace(headerValue))
{
- httpContext.Request.Headers.Add(headerKey, new StringValues(headerValue));
+ httpContext.Request.Headers[headerKey] = new StringValues(headerValue);
}
}
@@ -773,7 +773,7 @@ private void SetupContexts(RouteContext request, HttpContext httpContext)
}
}
- private void PopulateReferenceIdDictionary(IEnumerable bundleEntries, IDictionary idDictionary)
+ private void PopulateReferenceIdDictionary(IEnumerable bundleEntries, Dictionary idDictionary)
{
foreach (EntryComponent entry in bundleEntries)
{
diff --git a/src/Microsoft.Health.Fhir.Shared.Api/Features/Resources/Bundle/BundleHandlerParallelOperations.cs b/src/Microsoft.Health.Fhir.Shared.Api/Features/Resources/Bundle/BundleHandlerParallelOperations.cs
index f0081a9839..eba0a55b1d 100644
--- a/src/Microsoft.Health.Fhir.Shared.Api/Features/Resources/Bundle/BundleHandlerParallelOperations.cs
+++ b/src/Microsoft.Health.Fhir.Shared.Api/Features/Resources/Bundle/BundleHandlerParallelOperations.cs
@@ -22,6 +22,7 @@
using Microsoft.Health.Core.Features.Context;
using Microsoft.Health.Fhir.Api.Features.Bundle;
using Microsoft.Health.Fhir.Api.Features.Routing;
+using Microsoft.Health.Fhir.Core.Extensions;
using Microsoft.Health.Fhir.Core.Features.Context;
using Microsoft.Health.Fhir.Core.Features.Persistence;
using Microsoft.Health.Fhir.Core.Features.Persistence.Orchestration;
@@ -132,7 +133,7 @@ private async Task ExecuteRequestsInParallelAsync(
// In case of a FhirTransactionFailedException, the entire Bundle Operation should be canceled.
bundleOperation.Cancel($"Failed transaction. Resource at position {resourceExecutionContext.Index}. Status Code: {ex.ResponseStatusCode}. Message: {ex.Message}");
- requestCancellationToken.Cancel();
+ await requestCancellationToken.CancelAsync();
throw;
}
diff --git a/src/Microsoft.Health.Fhir.Shared.Api/Features/Resources/ProvenanceHeaderBehavior.cs b/src/Microsoft.Health.Fhir.Shared.Api/Features/Resources/ProvenanceHeaderBehavior.cs
index 30dd29ae7e..3a18ff8376 100644
--- a/src/Microsoft.Health.Fhir.Shared.Api/Features/Resources/ProvenanceHeaderBehavior.cs
+++ b/src/Microsoft.Health.Fhir.Shared.Api/Features/Resources/ProvenanceHeaderBehavior.cs
@@ -86,7 +86,7 @@ private async Task GenericHandle(RequestHandlerDelegate<
private Provenance GetProvenanceFromHeader()
{
- if (!_httpContextAccessor.HttpContext.Request.Headers.ContainsKey(KnownHeaders.ProvenanceHeader))
+ if (!_httpContextAccessor.HttpContext.Request.Headers.TryGetValue(KnownHeaders.ProvenanceHeader, out Microsoft.Extensions.Primitives.StringValues value))
{
return null;
}
@@ -94,7 +94,7 @@ private Provenance GetProvenanceFromHeader()
Provenance provenance;
try
{
- provenance = _fhirJsonParser.Parse(_httpContextAccessor.HttpContext.Request.Headers[KnownHeaders.ProvenanceHeader]);
+ provenance = _fhirJsonParser.Parse(value);
}
catch
{
diff --git a/src/Microsoft.Health.Fhir.Shared.Core.UnitTests/Features/Resources/ResourceHandlerTests.cs b/src/Microsoft.Health.Fhir.Shared.Core.UnitTests/Features/Resources/ResourceHandlerTests.cs
index 9f588589fd..7daf3abaf4 100644
--- a/src/Microsoft.Health.Fhir.Shared.Core.UnitTests/Features/Resources/ResourceHandlerTests.cs
+++ b/src/Microsoft.Health.Fhir.Shared.Core.UnitTests/Features/Resources/ResourceHandlerTests.cs
@@ -16,7 +16,6 @@
using Microsoft.Extensions.Logging;
using Microsoft.Health.Core.Features.Context;
using Microsoft.Health.Core.Features.Security.Authorization;
-using Microsoft.Health.Core.Internal;
using Microsoft.Health.Extensions.DependencyInjection;
using Microsoft.Health.Fhir.Core.Exceptions;
using Microsoft.Health.Fhir.Core.Extensions;
@@ -182,6 +181,7 @@ public async Task GivenAFhirMediator_WhenCreatingAResourceAndResourceIdProviderH
Assert.Equal("id2", deserializedResource.Id);
}
+#if NET8_0_OR_GREATER
[Fact]
public async Task GivenAFhirMediator_WhenSavingAResource_ThenLastUpdatedShouldBeSet()
{
@@ -189,7 +189,7 @@ public async Task GivenAFhirMediator_WhenSavingAResource_ThenLastUpdatedShouldBe
DateTime baseDate = DateTimeOffset.Now.Date;
var instant = new DateTimeOffset(baseDate.AddTicks((6 * TimeSpan.TicksPerMillisecond) + (long)(0.7 * TimeSpan.TicksPerMillisecond)), TimeSpan.Zero);
- using (Mock.Property(() => ClockResolver.UtcNowFunc, () => instant))
+ using (Mock.Property(() => ClockResolver.TimeProvider, new Microsoft.Extensions.Time.Testing.FakeTimeProvider(instant)))
{
_fhirDataStore.UpsertAsync(Arg.Any(), Arg.Any())
.Returns(x => new UpsertOutcome(x.ArgAt(0).Wrapper, SaveOutcomeType.Created));
@@ -200,6 +200,7 @@ public async Task GivenAFhirMediator_WhenSavingAResource_ThenLastUpdatedShouldBe
Assert.Equal(new DateTimeOffset(baseDate.AddMilliseconds(6), TimeSpan.Zero), deserializedResource.LastUpdated);
}
}
+#endif
[Fact]
public async Task GivenAFhirMediator_WhenSavingAResource_ThenVersionShouldBeSet()
diff --git a/src/Microsoft.Health.Fhir.Shared.Core.UnitTests/Features/Search/BundleFactoryTests.cs b/src/Microsoft.Health.Fhir.Shared.Core.UnitTests/Features/Search/BundleFactoryTests.cs
index bd9a5546b9..bd1ddaa23c 100644
--- a/src/Microsoft.Health.Fhir.Shared.Core.UnitTests/Features/Search/BundleFactoryTests.cs
+++ b/src/Microsoft.Health.Fhir.Shared.Core.UnitTests/Features/Search/BundleFactoryTests.cs
@@ -11,7 +11,6 @@
using Hl7.Fhir.Serialization;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Health.Core.Features.Context;
-using Microsoft.Health.Core.Internal;
using Microsoft.Health.Fhir.Core.Extensions;
using Microsoft.Health.Fhir.Core.Features.Context;
using Microsoft.Health.Fhir.Core.Features.Persistence;
@@ -60,6 +59,7 @@ public BundleFactoryTests()
_fhirRequestContextAccessor.RequestContext.Returns(fhirRequestContext);
}
+#if NET8_0_OR_GREATER
[Fact]
public void GivenAnEmptySearchResult_WhenCreateSearchBundle_ThenCorrectBundleShouldBeReturned()
{
@@ -67,7 +67,7 @@ public void GivenAnEmptySearchResult_WhenCreateSearchBundle_ThenCorrectBundleSho
ResourceElement actual = null;
- using (Mock.Property(() => ClockResolver.UtcNowFunc, () => _dateTime))
+ using (Mock.Property(() => ClockResolver.TimeProvider, new Microsoft.Extensions.Time.Testing.FakeTimeProvider(_dateTime)))
{
actual = _bundleFactory.CreateSearchBundle(new SearchResult(new SearchResultEntry[0], null, null, _unsupportedSearchParameters));
}
@@ -100,7 +100,7 @@ public void GivenASearchResult_WhenCreateSearchBundle_ThenCorrectBundleShouldBeR
ResourceElement actual = null;
- using (Mock.Property(() => ClockResolver.UtcNowFunc, () => _dateTime))
+ using (Mock.Property(() => ClockResolver.TimeProvider, new Microsoft.Extensions.Time.Testing.FakeTimeProvider(_dateTime)))
{
actual = _bundleFactory.CreateSearchBundle(searchResult);
}
@@ -139,6 +139,7 @@ async Task ValidateEntry(Observation expected, Bundle.EntryComponent actualEntry
}
}
}
+#endif
private ResourceWrapper CreateResourceWrapper(ResourceElement resourceElement, HttpMethod httpMethod)
{
diff --git a/src/Microsoft.Health.Fhir.Shared.Core.UnitTests/Features/Search/Expressions/Parsers/SearchValueExpressionBuilderTests.cs b/src/Microsoft.Health.Fhir.Shared.Core.UnitTests/Features/Search/Expressions/Parsers/SearchValueExpressionBuilderTests.cs
index e4b2a5391e..62ebccd21c 100644
--- a/src/Microsoft.Health.Fhir.Shared.Core.UnitTests/Features/Search/Expressions/Parsers/SearchValueExpressionBuilderTests.cs
+++ b/src/Microsoft.Health.Fhir.Shared.Core.UnitTests/Features/Search/Expressions/Parsers/SearchValueExpressionBuilderTests.cs
@@ -7,7 +7,6 @@
using System.Collections.Generic;
using System.Linq;
using Hl7.Fhir.Model;
-using Microsoft.Health.Core.Internal;
using Microsoft.Health.Fhir.Core.Extensions;
using Microsoft.Health.Fhir.Core.Features.Definition;
using Microsoft.Health.Fhir.Core.Features.Search;
@@ -367,6 +366,7 @@ public void GivenADateWithComparatorOfSingleBinaryOperator_WhenBuilt_ThenCorrect
expectStartTimeValue ? dateTimeSearchValue.Start : dateTimeSearchValue.End));
}
+#if NET8_0_OR_GREATER
[Theory]
[InlineData("2016", "2015-11-25T12:00:00.0000000+00:00", "2017-02-06T11:59:59.9999999+00:00")]
[InlineData("2016-02", "2015-11-25T21:36:00.0000000+00:00", "2016-05-07T02:23:59.9999999+00:00")]
@@ -380,7 +380,7 @@ public void GivenADateWithComparatorOfSingleBinaryOperator_WhenBuilt_ThenCorrect
[InlineData("2220-02-01T10:00-07:00", "2240-04-17T16:18:05.9999999+00:00", "2199-11-16T17:42:54.0000000+00:00")]
public void GivenADateWithApComparator_WhenBuilt_ThenCorrectExpressionShouldBeCreated(string dateTimeInput, string expectedStartValue, string expectedEndValue)
{
- using (Mock.Property(() => ClockResolver.UtcNowFunc, () => DateTimeOffset.Parse("2018-01-01T00:00Z")))
+ using (Mock.Property(() => ClockResolver.TimeProvider, new Microsoft.Extensions.Time.Testing.FakeTimeProvider(DateTimeOffset.Parse("2018-01-01T00:00Z"))))
{
var partialDateTime = PartialDateTime.Parse(dateTimeInput);
var dateTimeSearchValue = new DateTimeSearchValue(partialDateTime);
@@ -396,6 +396,7 @@ public void GivenADateWithApComparator_WhenBuilt_ThenCorrectExpressionShouldBeCr
e1 => ValidateDateTimeBinaryOperatorExpression(e1, FieldName.DateTimeEnd, BinaryOperator.LessThanOrEqual, DateTimeOffset.Parse(expectedEndValue))));
}
}
+#endif
[Theory]
[MemberData(nameof(GetAllModifiersExceptMissing))]
diff --git a/src/Microsoft.Health.Fhir.Shared.Core/Features/Operations/MemberMatch/MemberMatchService.cs b/src/Microsoft.Health.Fhir.Shared.Core/Features/Operations/MemberMatch/MemberMatchService.cs
index d8861f3120..1b508188b8 100644
--- a/src/Microsoft.Health.Fhir.Shared.Core/Features/Operations/MemberMatch/MemberMatchService.cs
+++ b/src/Microsoft.Health.Fhir.Shared.Core/Features/Operations/MemberMatch/MemberMatchService.cs
@@ -124,14 +124,14 @@ private ResourceElement CreatePatientWithIdentity(ResourceElement patient, Searc
return result;
}
- private Expression CreateSearchExpression(ResourceElement coverage, ResourceElement patient)
+ private MultiaryExpression CreateSearchExpression(ResourceElement coverage, ResourceElement patient)
{
- var coverageValues = _searchIndexer.Extract(coverage);
- var patientValues = _searchIndexer.Extract(patient);
+ IReadOnlyCollection coverageValues = _searchIndexer.Extract(coverage);
+ IReadOnlyCollection patientValues = _searchIndexer.Extract(patient);
var expressions = new List();
var reverseChainExpressions = new List();
expressions.Add(Expression.SearchParameter(_resourceTypeSearchParameter, Expression.StringEquals(FieldName.TokenCode, null, KnownResourceTypes.Patient, false)));
- foreach (var patientValue in patientValues)
+ foreach (SearchIndexEntry patientValue in patientValues)
{
if (IgnoreInSearch(patientValue))
{
@@ -175,7 +175,7 @@ private Expression CreateSearchExpression(ResourceElement coverage, ResourceElem
reverseChainedExpression = Expression.And(reverseChainExpressions);
}
- var expression = Expression.Chained(new[] { KnownResourceTypes.Coverage }, _coverageBeneficiaryParameter, new[] { KnownResourceTypes.Patient }, true, reverseChainedExpression);
+ ChainedExpression expression = Expression.Chained(new[] { KnownResourceTypes.Coverage }, _coverageBeneficiaryParameter, new[] { KnownResourceTypes.Patient }, true, reverseChainedExpression);
expressions.Add(expression);
}
diff --git a/src/Microsoft.Health.Fhir.Shared.Web/DevelopmentIdentityProviderRegistrationExtensions.cs b/src/Microsoft.Health.Fhir.Shared.Web/DevelopmentIdentityProviderRegistrationExtensions.cs
index a4dbcd5378..a242a85177 100644
--- a/src/Microsoft.Health.Fhir.Shared.Web/DevelopmentIdentityProviderRegistrationExtensions.cs
+++ b/src/Microsoft.Health.Fhir.Shared.Web/DevelopmentIdentityProviderRegistrationExtensions.cs
@@ -163,7 +163,7 @@ public static IConfigurationBuilder AddDevelopmentAuthEnvironmentIfConfigured(th
return configurationBuilder.Add(new DevelopmentAuthEnvironmentConfigurationSource(testEnvironmentFilePath, existingConfiguration));
}
- private static IReadOnlyCollection GenerateSmartClinicalScopes()
+ private static List GenerateSmartClinicalScopes()
{
ModelExtensions.SetModelInfoProvider();
var resourceTypes = ModelInfoProvider.Instance.GetResourceTypeNames();
@@ -192,7 +192,7 @@ private static IReadOnlyCollection GenerateSmartClinicalScopes()
return scopes;
}
- private static IEnumerable CreateFhirUserClaims(string userId, string host)
+ private static ClientClaim[] CreateFhirUserClaims(string userId, string host)
{
string userType = null;
@@ -209,11 +209,11 @@ private static IEnumerable CreateFhirUserClaims(string userId, stri
userType = "System";
}
- return new ClientClaim[]
- {
+ return
+ [
new ClientClaim("appid", userId),
new ClientClaim("fhirUser", $"{host}{userType}/" + userId),
- };
+ ];
}
private sealed class DevelopmentAuthEnvironmentConfigurationSource : IConfigurationSource
diff --git a/src/Microsoft.Health.Fhir.Shared.Web/Startup.cs b/src/Microsoft.Health.Fhir.Shared.Web/Startup.cs
index 341e87dfd6..eb6e73cc46 100644
--- a/src/Microsoft.Health.Fhir.Shared.Web/Startup.cs
+++ b/src/Microsoft.Health.Fhir.Shared.Web/Startup.cs
@@ -189,7 +189,7 @@ public virtual void Configure(IApplicationBuilder app)
string instanceKey = KnownHeaders.InstanceId;
if (!context.Response.Headers.ContainsKey(instanceKey))
{
- context.Response.Headers.Add(instanceKey, new StringValues(instanceId));
+ context.Response.Headers[instanceKey] = new StringValues(instanceId);
}
}
@@ -234,6 +234,8 @@ private static void AddAuthenticationLibrary(IServiceCollection services, Securi
{
options.Authority = securityConfiguration.Authentication.Authority;
options.Audience = securityConfiguration.Authentication.Audience;
+ options.TokenValidationParameters.RoleClaimType = securityConfiguration.Authorization.RolesClaim;
+ options.MapInboundClaims = false;
options.RequireHttpsMetadata = true;
options.Challenge = $"Bearer authorization_uri=\"{securityConfiguration.Authentication.Authority}\", resource_id=\"{securityConfiguration.Authentication.Audience}\", realm=\"{securityConfiguration.Authentication.Audience}\"";
});
diff --git a/src/Microsoft.Health.Fhir.SqlServer/Features/Operations/Import/ImportOrchestratorJob.cs b/src/Microsoft.Health.Fhir.SqlServer/Features/Operations/Import/ImportOrchestratorJob.cs
index b61809b56d..5963401d54 100644
--- a/src/Microsoft.Health.Fhir.SqlServer/Features/Operations/Import/ImportOrchestratorJob.cs
+++ b/src/Microsoft.Health.Fhir.SqlServer/Features/Operations/Import/ImportOrchestratorJob.cs
@@ -22,6 +22,7 @@
using Microsoft.Health.Core.Features.Audit;
using Microsoft.Health.Core.Features.Context;
using Microsoft.Health.Fhir.Core.Configs;
+using Microsoft.Health.Fhir.Core.Extensions;
using Microsoft.Health.Fhir.Core.Features.Audit;
using Microsoft.Health.Fhir.Core.Features.Context;
using Microsoft.Health.Fhir.Core.Features.Operations;
@@ -105,10 +106,7 @@ public async Task ExecuteAsync(JobInfo jobInfo, IProgress progre
try
{
- if (cancellationToken.IsCancellationRequested)
- {
- throw new OperationCanceledException();
- }
+ cancellationToken.ThrowIfCancellationRequested();
if (currentResult.Progress == ImportOrchestratorJobProgress.Initialized)
{
diff --git a/src/Microsoft.Health.Fhir.SqlServer/Features/Operations/Import/ImportProcessingJob.cs b/src/Microsoft.Health.Fhir.SqlServer/Features/Operations/Import/ImportProcessingJob.cs
index 4098c6bcff..54e4f4408e 100644
--- a/src/Microsoft.Health.Fhir.SqlServer/Features/Operations/Import/ImportProcessingJob.cs
+++ b/src/Microsoft.Health.Fhir.SqlServer/Features/Operations/Import/ImportProcessingJob.cs
@@ -69,10 +69,7 @@ public async Task ExecuteAsync(JobInfo jobInfo, IProgress progre
try
{
- if (cancellationToken.IsCancellationRequested)
- {
- throw new OperationCanceledException();
- }
+ cancellationToken.ThrowIfCancellationRequested();
// Initialize error store
IImportErrorStore importErrorStore = await _importErrorStoreFactory.InitializeAsync(GetErrorFileName(definition.ResourceType, jobInfo.GroupId, jobInfo.Id), cancellationToken);
diff --git a/src/Microsoft.Health.Fhir.SqlServer/Features/Operations/Import/SqlImporter.cs b/src/Microsoft.Health.Fhir.SqlServer/Features/Operations/Import/SqlImporter.cs
index 6990c08a45..1d55684ae8 100644
--- a/src/Microsoft.Health.Fhir.SqlServer/Features/Operations/Import/SqlImporter.cs
+++ b/src/Microsoft.Health.Fhir.SqlServer/Features/Operations/Import/SqlImporter.cs
@@ -60,10 +60,7 @@ public async Task Import(Channel input
var resourceBuffer = new List();
await foreach (ImportResource resource in inputChannel.Reader.ReadAllAsync(cancellationToken))
{
- if (cancellationToken.IsCancellationRequested)
- {
- throw new OperationCanceledException();
- }
+ cancellationToken.ThrowIfCancellationRequested();
currentIndex = resource.Index;
diff --git a/src/Microsoft.Health.Fhir.SqlServer/Features/Search/CustomQueries.cs b/src/Microsoft.Health.Fhir.SqlServer/Features/Search/CustomQueries.cs
index 0aba28935b..f410214127 100644
--- a/src/Microsoft.Health.Fhir.SqlServer/Features/Search/CustomQueries.cs
+++ b/src/Microsoft.Health.Fhir.SqlServer/Features/Search/CustomQueries.cs
@@ -8,6 +8,7 @@
using System.Data;
using Microsoft.Extensions.Logging;
using Microsoft.Health.Core;
+using Microsoft.Health.Fhir.Core.Extensions;
namespace Microsoft.Health.Fhir.SqlServer.Features.Search
{
@@ -22,7 +23,7 @@ internal static class CustomQueries
public static string CheckQueryHash(IDbConnection connection, string hash, ILogger logger)
{
- var now = Clock.UtcNow;
+ DateTimeOffset now = Clock.UtcNow;
if (now > _lastUpdatedQueryCache.AddSeconds(WaitTime))
{
lock (lockObject)
diff --git a/src/Microsoft.Health.Fhir.SqlServer/Features/Search/Expressions/Visitors/IncludeRewriter.cs b/src/Microsoft.Health.Fhir.SqlServer/Features/Search/Expressions/Visitors/IncludeRewriter.cs
index 1f4bbdb093..e4469f52f3 100644
--- a/src/Microsoft.Health.Fhir.SqlServer/Features/Search/Expressions/Visitors/IncludeRewriter.cs
+++ b/src/Microsoft.Health.Fhir.SqlServer/Features/Search/Expressions/Visitors/IncludeRewriter.cs
@@ -121,8 +121,10 @@ public IncludeIterateExpressionDependencyGraph(IEnumerable> OutgoingEdges { get; private set; }
+ [System.Diagnostics.CodeAnalysis.SuppressMessage("Performance", "CA1859:Use concrete types when possible for improved performance", Justification = "This is a public signature.")]
public IDictionary IncomingEdgesCount { get; private set; }
public IEnumerable NodesWithoutIncomingEdges
diff --git a/src/Microsoft.Health.Fhir.SqlServer/Features/Search/Expressions/Visitors/SqlRootExpressionRewriter.cs b/src/Microsoft.Health.Fhir.SqlServer/Features/Search/Expressions/Visitors/SqlRootExpressionRewriter.cs
index 299bb00145..ea38a1cf7c 100644
--- a/src/Microsoft.Health.Fhir.SqlServer/Features/Search/Expressions/Visitors/SqlRootExpressionRewriter.cs
+++ b/src/Microsoft.Health.Fhir.SqlServer/Features/Search/Expressions/Visitors/SqlRootExpressionRewriter.cs
@@ -81,7 +81,7 @@ public override Expression VisitMultiary(MultiaryExpression expression, int cont
public override Expression VisitChained(ChainedExpression expression, int context) => ConvertNonMultiary(expression);
- private Expression ConvertNonMultiary(Expression expression)
+ private SqlRootExpression ConvertNonMultiary(Expression expression)
{
if (TryGetSearchParamTableExpressionQueryGenerator(expression, out var generator, out var kind))
{
diff --git a/src/Microsoft.Health.Fhir.SqlServer/Features/Search/HashingSqlQueryParameterManager.cs b/src/Microsoft.Health.Fhir.SqlServer/Features/Search/HashingSqlQueryParameterManager.cs
index e19f2b20c6..b09a8ce80d 100644
--- a/src/Microsoft.Health.Fhir.SqlServer/Features/Search/HashingSqlQueryParameterManager.cs
+++ b/src/Microsoft.Health.Fhir.SqlServer/Features/Search/HashingSqlQueryParameterManager.cs
@@ -195,7 +195,11 @@ private static void WriteAndAdvance(Span buffer, ref int currentIndex,
Debug.Assert(buffer.Length >= elementLength, "Initial buffer size is not large enough for the datatypes we are trying to write to it");
}
+#if NET8_0_OR_GREATER
+ MemoryMarshal.Write(buffer[currentIndex..], in element);
+#else
MemoryMarshal.Write(buffer[currentIndex..], ref element);
+#endif
currentIndex += elementLength;
}
diff --git a/src/Microsoft.Health.Fhir.SqlServer/Features/Search/SqlCommandSimplifier.cs b/src/Microsoft.Health.Fhir.SqlServer/Features/Search/SqlCommandSimplifier.cs
index 897439317b..deead819d2 100644
--- a/src/Microsoft.Health.Fhir.SqlServer/Features/Search/SqlCommandSimplifier.cs
+++ b/src/Microsoft.Health.Fhir.SqlServer/Features/Search/SqlCommandSimplifier.cs
@@ -51,12 +51,13 @@ private static string RemoveRedundantComparisons(string commandText, SqlParamete
foreach (Match match in operatorMatches)
{
var groups = match.Groups;
- if (!fieldToParameterComparisons.ContainsKey(groups[1].Value))
+ if (!fieldToParameterComparisons.TryGetValue(groups[1].Value, out List<(string, Match)> value))
{
- fieldToParameterComparisons.Add(groups[1].Value, new List<(string, Match)>());
+ value = new List<(string, Match)>();
+ fieldToParameterComparisons.Add(groups[1].Value, value);
}
- fieldToParameterComparisons[groups[1].Value].Add((groups[2].Value, match));
+ value.Add((groups[2].Value, match));
}
foreach (string field in fieldToParameterComparisons.Keys)
diff --git a/src/Microsoft.Health.Fhir.SqlServer/Features/Storage/SqlServerFhirDataStore.cs b/src/Microsoft.Health.Fhir.SqlServer/Features/Storage/SqlServerFhirDataStore.cs
index af328bb13e..75027013c6 100644
--- a/src/Microsoft.Health.Fhir.SqlServer/Features/Storage/SqlServerFhirDataStore.cs
+++ b/src/Microsoft.Health.Fhir.SqlServer/Features/Storage/SqlServerFhirDataStore.cs
@@ -574,7 +574,7 @@ private string GetJsonValue(string json, string propName, bool isExisting)
}
startIndex = startIndex + propName.Length + 4;
- var endIndex = json.IndexOf("\"", startIndex, StringComparison.Ordinal);
+ var endIndex = json.IndexOf('"', startIndex);
if (endIndex == -1)
{
_logger.LogWarning($"Cannot parse {propName} value from {(isExisting ? "existing" : "input")} {json}");
diff --git a/src/Microsoft.Health.Fhir.SqlServer/Features/Watchdogs/DefragWatchdog.cs b/src/Microsoft.Health.Fhir.SqlServer/Features/Watchdogs/DefragWatchdog.cs
index 865b4d7cb3..dceaed120b 100644
--- a/src/Microsoft.Health.Fhir.SqlServer/Features/Watchdogs/DefragWatchdog.cs
+++ b/src/Microsoft.Health.Fhir.SqlServer/Features/Watchdogs/DefragWatchdog.cs
@@ -23,6 +23,7 @@ public sealed class DefragWatchdog : Watchdog
private int _heartbeatPeriodSec;
private int _heartbeatTimeoutSec;
private CancellationToken _cancellationToken;
+ private static readonly string[] Definitions = { "Defrag" };
private readonly ISqlRetryService _sqlRetryService;
private readonly SqlQueueClient _sqlQueueClient;
@@ -208,7 +209,7 @@ private async Task InitDefragAsync(long groupId, CancellationToken cancella
(long groupId, long jobId, long version) id = (-1, -1, -1);
try
{
- var jobs = await _sqlQueueClient.EnqueueAsync(QueueType, new[] { "Defrag" }, null, true, false, cancellationToken);
+ var jobs = await _sqlQueueClient.EnqueueAsync(QueueType, Definitions, null, true, false, cancellationToken);
if (jobs.Count > 0)
{
diff --git a/src/Microsoft.Health.Fhir.Store.Utils/BatchExtensions.cs b/src/Microsoft.Health.Fhir.Store.Utils/BatchExtensions.cs
index 39d9b1c05c..d4153ddb62 100644
--- a/src/Microsoft.Health.Fhir.Store.Utils/BatchExtensions.cs
+++ b/src/Microsoft.Health.Fhir.Store.Utils/BatchExtensions.cs
@@ -103,7 +103,7 @@ public static void ExecuteInParallelBatches(IEnumerable objects, int threa
}
}
- private static void AddToQueueWithTrapping(BlockingCollection>> queue, int batchId, IList batchList, CancelRequest cancel, ICollection workers, int maxWorkers, Action workerAction)
+ private static void AddToQueueWithTrapping(BlockingCollection>> queue, int batchId, IList batchList, CancelRequest cancel, List workers, int maxWorkers, Action workerAction)
{
try
{
diff --git a/src/Microsoft.Health.TaskManagement/JobHosting.cs b/src/Microsoft.Health.TaskManagement/JobHosting.cs
index 3d1e948881..497db7fcff 100644
--- a/src/Microsoft.Health.TaskManagement/JobHosting.cs
+++ b/src/Microsoft.Health.TaskManagement/JobHosting.cs
@@ -123,7 +123,11 @@ private async Task ExecuteJobAsync(JobInfo jobInfo, bool useHeavyHeartbeats)
if (jobInfo.CancelRequested)
{
// For cancelled job, try to execute it for potential cleanup.
+#if NET6_0
jobCancellationToken.Cancel();
+#else
+ await jobCancellationToken.CancelAsync();
+#endif
}
var progress = new Progress((result) => { jobInfo.Result = result; });
@@ -237,7 +241,11 @@ private static async Task PutJobHeartbeatAsync(IQueueClient queueClient, JobInfo
var cancel = await queueClient.PutJobHeartbeatAsync(jobInfo, cancellationTokenSource.Token);
if (cancel)
{
+#if NET6_0
cancellationTokenSource.Cancel();
+#else
+ await cancellationTokenSource.CancelAsync();
+#endif
}
}
catch
diff --git a/test/Microsoft.Health.Fhir.R4.Tests.Integration/Microsoft.Health.Fhir.R4.Tests.Integration.csproj b/test/Microsoft.Health.Fhir.R4.Tests.Integration/Microsoft.Health.Fhir.R4.Tests.Integration.csproj
index 181cb61fe0..6bb17786d9 100644
--- a/test/Microsoft.Health.Fhir.R4.Tests.Integration/Microsoft.Health.Fhir.R4.Tests.Integration.csproj
+++ b/test/Microsoft.Health.Fhir.R4.Tests.Integration/Microsoft.Health.Fhir.R4.Tests.Integration.csproj
@@ -14,6 +14,9 @@
+
+
+
diff --git a/test/Microsoft.Health.Fhir.R4B.Tests.Integration/Microsoft.Health.Fhir.R4B.Tests.Integration.csproj b/test/Microsoft.Health.Fhir.R4B.Tests.Integration/Microsoft.Health.Fhir.R4B.Tests.Integration.csproj
index 5420f6aa62..4aff50f58a 100644
--- a/test/Microsoft.Health.Fhir.R4B.Tests.Integration/Microsoft.Health.Fhir.R4B.Tests.Integration.csproj
+++ b/test/Microsoft.Health.Fhir.R4B.Tests.Integration/Microsoft.Health.Fhir.R4B.Tests.Integration.csproj
@@ -14,6 +14,9 @@
+
+
+
diff --git a/test/Microsoft.Health.Fhir.R5.Tests.Integration/Microsoft.Health.Fhir.R5.Tests.Integration.csproj b/test/Microsoft.Health.Fhir.R5.Tests.Integration/Microsoft.Health.Fhir.R5.Tests.Integration.csproj
index 36f01188b1..b355731b34 100644
--- a/test/Microsoft.Health.Fhir.R5.Tests.Integration/Microsoft.Health.Fhir.R5.Tests.Integration.csproj
+++ b/test/Microsoft.Health.Fhir.R5.Tests.Integration/Microsoft.Health.Fhir.R5.Tests.Integration.csproj
@@ -14,6 +14,9 @@
+
+
+
diff --git a/test/Microsoft.Health.Fhir.Shared.Tests.Integration/Persistence/FhirStorageTests.cs b/test/Microsoft.Health.Fhir.Shared.Tests.Integration/Persistence/FhirStorageTests.cs
index 217b8f6b2a..c5cdb2c436 100644
--- a/test/Microsoft.Health.Fhir.Shared.Tests.Integration/Persistence/FhirStorageTests.cs
+++ b/test/Microsoft.Health.Fhir.Shared.Tests.Integration/Persistence/FhirStorageTests.cs
@@ -16,7 +16,6 @@
using MediatR;
using Microsoft.Health.Abstractions.Exceptions;
using Microsoft.Health.Abstractions.Features.Transactions;
-using Microsoft.Health.Core.Internal;
using Microsoft.Health.Fhir.Core;
using Microsoft.Health.Fhir.Core.Exceptions;
using Microsoft.Health.Fhir.Core.Extensions;
@@ -217,11 +216,12 @@ public async Task GivenASavedResource_WhenUpsertIsAnUpdate_ThenTheExistingResour
}
}
+#if NET8_0_OR_GREATER
[Fact]
public async Task GivenAResource_WhenUpserting_ThenTheNewResourceHasMetaSet()
{
var instant = new DateTimeOffset(DateTimeOffset.Now.Date, TimeSpan.Zero);
- using (Mock.Property(() => ClockResolver.UtcNowFunc, () => instant))
+ using (Mock.Property(() => ClockResolver.TimeProvider, new Microsoft.Extensions.Time.Testing.FakeTimeProvider(instant)))
{
var versionId = Guid.NewGuid().ToString();
var resource = Samples.GetJsonSample("Weight").UpdateVersion(versionId);
@@ -243,6 +243,7 @@ public async Task GivenAResource_WhenUpserting_ThenTheNewResourceHasMetaSet()
Assert.NotEqual(versionId, deserialized.VersionId);
}
}
+#endif
[Fact(Skip = "Not valid for merge")]
public async Task GivenASavedResource_WhenUpserting_ThenRawResourceVersionIsSetOrMetaSetIsSetToFalse()
diff --git a/tools/Importer/Importer.cs b/tools/Importer/Importer.cs
index efde905d03..f1858e3e30 100644
--- a/tools/Importer/Importer.cs
+++ b/tools/Importer/Importer.cs
@@ -110,7 +110,7 @@ internal static void Run()
Console.WriteLine($"{globalPrefix}.Readers=[{readers}/{ReadThreads}].Writers=[{writers}].EndPointCalls=[{epCalls}].Waits=[{waits}]: total reads={totalReads} total writes={totalWrites} secs={(int)swWrites.Elapsed.TotalSeconds} read-speed={(int)(totalReads / swReads.Elapsed.TotalSeconds)} lines/sec write-speed={(int)(totalWrites / swWrites.Elapsed.TotalSeconds)} res/sec");
}
- private static IEnumerable GetLinesInBlobRange(IList blobs, string logPrefix)
+ private static List GetLinesInBlobRange(IList blobs, string logPrefix)
{
Interlocked.Increment(ref readers);
swReads.Start(); // just in case it was stopped by decrement logic below
@@ -268,7 +268,7 @@ private static (string resourceType, string resourceId) ParseJson(string jsonStr
{
var idStart = jsonString.IndexOf("\"id\":\"", StringComparison.OrdinalIgnoreCase) + 6;
var idShort = jsonString.Substring(idStart, 50);
- var idEnd = idShort.IndexOf("\"", StringComparison.OrdinalIgnoreCase);
+ var idEnd = idShort.IndexOf('"', StringComparison.OrdinalIgnoreCase);
var resourceId = idShort.Substring(0, idEnd);
if (string.IsNullOrEmpty(resourceId))
{
@@ -277,7 +277,7 @@ private static (string resourceType, string resourceId) ParseJson(string jsonStr
var rtStart = jsonString.IndexOf("\"resourceType\":\"", StringComparison.OrdinalIgnoreCase) + 16;
var rtShort = jsonString.Substring(rtStart, 50);
- var rtEnd = rtShort.IndexOf("\"", StringComparison.OrdinalIgnoreCase);
+ var rtEnd = rtShort.IndexOf('"', StringComparison.OrdinalIgnoreCase);
var resourceType = rtShort.Substring(0, rtEnd);
if (string.IsNullOrEmpty(resourceType))
{
diff --git a/tools/IndexRebuilder/IndexRebuilder.cs b/tools/IndexRebuilder/IndexRebuilder.cs
index 3a78781414..4cc68f7a6b 100644
--- a/tools/IndexRebuilder/IndexRebuilder.cs
+++ b/tools/IndexRebuilder/IndexRebuilder.cs
@@ -76,7 +76,7 @@ private CancelRequest RunCommands(IList<(string Table, IList SqlCommands
return cancelInt;
}
- private IList<(string Table, IList SqlCommands)> GetCommandsForRebuildIndexes(bool rebuildClustered) // Item1 is Table name, Items - list of SQL commands in the order they have to be executed
+ private List<(string Table, IList SqlCommands)> GetCommandsForRebuildIndexes(bool rebuildClustered) // Item1 is Table name, Items - list of SQL commands in the order they have to be executed
{
var resultsDic = new Dictionary>();
var tablesWithPreservedOrder = new List();
diff --git a/tools/Microsoft.Health.Fhir.R4.ResourceParser/Code/MinimalSearchParameterDefinitionBuilder.cs b/tools/Microsoft.Health.Fhir.R4.ResourceParser/Code/MinimalSearchParameterDefinitionBuilder.cs
index 0e808883c6..ab2210557b 100644
--- a/tools/Microsoft.Health.Fhir.R4.ResourceParser/Code/MinimalSearchParameterDefinitionBuilder.cs
+++ b/tools/Microsoft.Health.Fhir.R4.ResourceParser/Code/MinimalSearchParameterDefinitionBuilder.cs
@@ -22,7 +22,7 @@ namespace Microsoft.Health.Fhir.R4.ResourceParser.Code
{
public static class MinimalSearchParameterDefinitionBuilder
{
- private static readonly ISet _missingExpressionsInR5 = new HashSet
+ private static readonly HashSet _missingExpressionsInR5 = new()
{
new("http://hl7.org/fhir/SearchParameter/EvidenceVariable-topic"),
new("http://hl7.org/fhir/SearchParameter/ImagingStudy-reason"),
diff --git a/tools/Microsoft.Health.Fhir.R4.ResourceParser/ResourceWrapperParser.cs b/tools/Microsoft.Health.Fhir.R4.ResourceParser/ResourceWrapperParser.cs
index ee0fe751a5..38ca6d27cd 100644
--- a/tools/Microsoft.Health.Fhir.R4.ResourceParser/ResourceWrapperParser.cs
+++ b/tools/Microsoft.Health.Fhir.R4.ResourceParser/ResourceWrapperParser.cs
@@ -89,7 +89,7 @@ public string SerializeToString(ResourceWrapper wrapper)
return _fhirJsonSerializer.SerializeToString(_fhirJsonParser.Parse(wrapper.RawResource.ToITypedElement(_modelInfoProvider)));
}
- private static IEnumerable MakeConverters(RequestContextAccessor requestContextAccessor, ICodeSystemResolver codeSystemResolver)
+ private static List MakeConverters(RequestContextAccessor requestContextAccessor, ICodeSystemResolver codeSystemResolver)
{
var fhirTypedElementConverters = new List();
var referenceSearchValueParser = new ReferenceSearchValueParser(requestContextAccessor);
diff --git a/tools/RegisterAndMonitorImport/RegisterAndMonitorImport.cs b/tools/RegisterAndMonitorImport/RegisterAndMonitorImport.cs
index e940dd1360..258c1e7ad8 100644
--- a/tools/RegisterAndMonitorImport/RegisterAndMonitorImport.cs
+++ b/tools/RegisterAndMonitorImport/RegisterAndMonitorImport.cs
@@ -358,7 +358,7 @@ private static ImportResponse TryParseJson(string value)
else
{
value = value.Trim();
- if (value.StartsWith("{", StringComparison.Ordinal) && value.EndsWith("}", StringComparison.Ordinal))
+ if (value.StartsWith('{') && value.EndsWith('}'))
{
try
{