Skip to content

Commit

Permalink
Updated FhirClient (#167)
Browse files Browse the repository at this point in the history
* removed hl7 fhir client and leveraging health team client

* changed to local.appsettings.json

* removed FhirOperationException

* removed r4 common test proj and made other updates

* updated nuget package sources

* moved ServiceCollectionExtensions to Microsoft.Health.Extensions.Fhir project

* removed unnecessary package references

* added service collection extension and updated fhirservice validtor

* updated BearerTokenAuthMessageHandler

* updating inputs on  .net core sdk task

* updated r4 params to base constructor

* removed updates to ResourceIdentityServiceFactory

* updated ResolveResourceIdentityService

* refactored repo to service, implemeneted retry and timeout policies on httpclient, updated fhirexceptionprocessor

* added fhirclient validation

* fix fhirclientvalidator tests

* Updated AddFhirClient and corresponding tests

* removed identifierextensions and updated validation

* added ToSearchQueryParameter to SearchExtensions

* added null check for logger in addfhirclient

Co-authored-by: Mackenzie Dolishny <[email protected]>
  • Loading branch information
kenziedolish and Mackenzie Dolishny authored Feb 16, 2022
1 parent 82f3b26 commit 726cf7d
Show file tree
Hide file tree
Showing 43 changed files with 735 additions and 550 deletions.
2 changes: 2 additions & 0 deletions build/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ steps:
displayName: 'Use .NET Core sdk 6.0.x'
inputs:
version: 6.0.x
selectOrConfig: configs
nugetConfigPath: nuget.config

- script: dotnet build --configuration $(buildConfiguration) --version-suffix $(build.buildNumber) /warnaserror
displayName: 'dotnet build $(buildConfiguration)'
Expand Down
18 changes: 18 additions & 0 deletions nuget.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<config>
<add key="repositoryPath" value="packages" />
</config>
<packageSources>
<!-- When <clear /> is present, previously defined sources are ignored -->
<clear />
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
<add key="Microsoft Health OSS" value="https://microsofthealthoss.pkgs.visualstudio.com/FhirServer/_packaging/Public/nuget/v3/index.json" />
</packageSources>
<activePackageSource>
<add key="All" value="(Aggregate source)" />
</activePackageSource>
<disabledPackageSources>
<add key="Microsoft Visual Studio Offline Packages" value="true" />
</disabledPackageSources>
</configuration>
14 changes: 8 additions & 6 deletions src/console/MeasurementCollectionToFhir/ProcessorStartup.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
using EnsureThat;
using Hl7.Fhir.Model;
using Hl7.Fhir.Rest;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
Expand All @@ -10,6 +9,7 @@
using Microsoft.Health.Common;
using Microsoft.Health.Extensions.Fhir;
using Microsoft.Health.Extensions.Fhir.Config;
using Microsoft.Health.Extensions.Fhir.Service;
using Microsoft.Health.Fhir.Ingest.Config;
using Microsoft.Health.Fhir.Ingest.Host;
using Microsoft.Health.Fhir.Ingest.Service;
Expand Down Expand Up @@ -38,13 +38,15 @@ public void ConfigureServices(IServiceCollection services)
services.Configure<ResourceIdentityOptions>(Configuration.GetSection("ResourceIdentity"));
services.Configure<FhirClientFactoryOptions>(Configuration.GetSection("FhirClient"));

services.TryAddSingleton<IFactory<FhirClient>, FhirClientFactory>();
services.TryAddSingleton(sp => sp.GetRequiredService<IFactory<FhirClient>>().Create());
services.TryAddSingleton<IFhirTemplateProcessor<ILookupTemplate<IFhirTemplate>, Observation>, R4FhirLookupTemplateProcessor>();
services.AddFhirClient(Configuration);
services.TryAddSingleton(ResolveResourceIdentityService);
services.TryAddSingleton<IFhirService, FhirService>();

services.TryAddSingleton<IFhirTemplateProcessor<ILookupTemplate<IFhirTemplate>, Observation>, R4FhirLookupTemplateProcessor>();
services.TryAddSingleton<IMemoryCache>(sp => new MemoryCache(Options.Create(new MemoryCacheOptions { SizeLimit = 5000 })));
services.TryAddSingleton<FhirImportService, R4FhirImportService>();

services.TryAddSingleton<ResourceManagementService>();
services.TryAddSingleton<MeasurementFhirImportOptions>();
services.TryAddSingleton<MeasurementFhirImportService>();
services.TryAddSingleton(ResolveMeasurementImportProvider);
Expand All @@ -65,9 +67,9 @@ private static IResourceIdentityService ResolveResourceIdentityService(IServiceP
{
EnsureArg.IsNotNull(serviceProvider, nameof(serviceProvider));

var fhirClient = serviceProvider.GetRequiredService<FhirClient>();
var fhirService = serviceProvider.GetRequiredService<IFhirService>();
var resourceIdentityOptions = serviceProvider.GetRequiredService<IOptions<ResourceIdentityOptions>>();
return ResourceIdentityServiceFactory.Instance.Create(resourceIdentityOptions.Value, fhirClient);
return ResourceIdentityServiceFactory.Instance.Create(resourceIdentityOptions.Value, fhirService);
}
}
}
1 change: 1 addition & 0 deletions src/console/Microsoft.Health.Fhir.Ingest.Console.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
<ProjectReference Include="..\lib\Microsoft.Health.Fhir.Ingest\Microsoft.Health.Fhir.Ingest.csproj" />
<ProjectReference Include="..\lib\Microsoft.Health.Fhir.R4.Ingest\Microsoft.Health.Fhir.R4.Ingest.csproj" />
<ProjectReference Include="..\lib\Microsoft.Health.Expressions\Microsoft.Health.Expressions.csproj" />
<PackageReference Include="Microsoft.Health.Fhir.R4.Client" Version="2.0.55" />
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.NET.Sdk.Functions" Version="4.0.1" />
<PackageReference Include="Ensure.That" Version="10.0.0" />
<PackageReference Include="Ensure.That" Version="10.1.0" />
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// -------------------------------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// -------------------------------------------------------------------------------------------------

using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading;
using System.Threading.Tasks;
using Azure.Core;
using EnsureThat;
using Microsoft.Health.Common.Telemetry;
using Microsoft.Health.Extensions.Fhir.Telemetry.Metrics;
using Microsoft.Health.Logging.Telemetry;

namespace Microsoft.Health.Extensions.Fhir
{
public class BearerTokenAuthorizationMessageHandler : DelegatingHandler
{
public BearerTokenAuthorizationMessageHandler(Uri uri, TokenCredential tokenCredentialProvider, ITelemetryLogger logger)
{
TokenCredential = EnsureArg.IsNotNull(tokenCredentialProvider, nameof(tokenCredentialProvider));
Uri = EnsureArg.IsNotNull(uri, nameof(uri));
Logger = EnsureArg.IsNotNull(logger, nameof(logger));
Scopes = new string[] { Uri.ToString().EndsWith(@"/") ? Uri + ".default" : Uri + "/.default" };
}

private ITelemetryLogger Logger { get; }

private TokenCredential TokenCredential { get; }

private Uri Uri { get; }

private string[] Scopes { get; }

protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
var requestContext = new TokenRequestContext(Scopes);
var accessToken = await TokenCredential.GetTokenAsync(requestContext, cancellationToken);
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken.Token);
var response = await base.SendAsync(request, cancellationToken);

if (!response.IsSuccessStatusCode)
{
var statusDescription = response.ReasonPhrase.Replace(" ", string.Empty);
var severity = response.StatusCode == System.Net.HttpStatusCode.TooManyRequests ? ErrorSeverity.Informational : ErrorSeverity.Critical;
Logger.LogMetric(FhirClientMetrics.HandledException($"{ErrorType.FHIRServiceError}{statusDescription}", severity), 1);
}

return response;
}
}
}
45 changes: 19 additions & 26 deletions src/lib/Microsoft.Health.Extensions.Fhir.R4/BundleExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
using System.Threading.Tasks;
using EnsureThat;
using Hl7.Fhir.Model;
using Hl7.Fhir.Rest;
using Microsoft.Health.Extensions.Fhir.Service;

namespace Microsoft.Health.Extensions.Fhir
{
Expand Down Expand Up @@ -41,15 +41,18 @@ public static IEnumerable<TResource> ReadFromBundle<TResource>(this Bundle bundl
}
}

public static async Task<TResource> ReadOneFromBundleWithContinuationAsync<TResource>(this Bundle bundle, FhirClient fhirClient, bool throwOnMultipleFound = true)
public static async Task<TResource> ReadOneFromBundleWithContinuationAsync<TResource>(
this Bundle bundle,
IFhirService fhirService,
bool throwOnMultipleFound = true)
where TResource : Resource, new()
{
if (bundle == null)
{
return null;
}

var resources = await bundle?.ReadFromBundleWithContinuationAsync<TResource>(fhirClient, 2);
var resources = await bundle?.ReadFromBundleWithContinuationAsync<TResource>(fhirService, 2);

var resourceCount = resources.Count();
if (resourceCount == 0)
Expand All @@ -75,13 +78,17 @@ public static int EntryCount(this Bundle bundle)
return bundle?.Entry?.Count ?? 0;
}

public static async Task<IEnumerable<TResource>> ReadFromBundleWithContinuationAsync<TResource>(this Bundle bundle, FhirClient fhirClient, int? count = null)
private static async Task<IEnumerable<TResource>> ReadFromBundleWithContinuationAsync<TResource>(
this Bundle bundle,
IFhirService fhirService,
int? count = null)
where TResource : Resource
{
EnsureArg.IsNotNull(fhirClient, nameof(fhirClient));
EnsureArg.IsNotNull(fhirService, nameof(fhirService));

var resources = new List<TResource>();
while (bundle != null)

Action<Bundle> storeResources = (bundle) =>
{
foreach (var r in bundle.ReadFromBundle<TResource>(count))
{
Expand All @@ -96,30 +103,16 @@ public static async Task<IEnumerable<TResource>> ReadFromBundleWithContinuationA
count--;
}
}
};

storeResources.Invoke(bundle);

bundle = await fhirClient.ContinueAsync(bundle).ConfigureAwait(false);
await foreach (var currentBundle in fhirService.IterateOverAdditionalBundlesAsync(bundle))
{
storeResources.Invoke(currentBundle);
}

return resources;
}

public static async Task<IEnumerable<TResource>> SearchWithContinuationAsync<TResource>(this FhirClient fhirClient, SearchParams searchParams)
where TResource : Resource
{
EnsureArg.IsNotNull(fhirClient, nameof(fhirClient));
EnsureArg.IsNotNull(searchParams, nameof(searchParams));

var result = await fhirClient.SearchAsync<TResource>(searchParams).ConfigureAwait(false);
return await result.ReadFromBundleWithContinuationAsync<TResource>(fhirClient, searchParams.Count).ConfigureAwait(false);
}

public static async Task<IEnumerable<TResource>> GetWithContinuationAsync<TResource>(this FhirClient fhirClient, Uri resourceUri, int? count = null)
where TResource : Resource
{
EnsureArg.IsNotNull(fhirClient, nameof(fhirClient));

var result = await fhirClient.GetAsync(resourceUri).ConfigureAwait(false) as Bundle;
return await result.ReadFromBundleWithContinuationAsync<TResource>(fhirClient, count).ConfigureAwait(false);
}
}
}
139 changes: 0 additions & 139 deletions src/lib/Microsoft.Health.Extensions.Fhir.R4/FhirClientFactory.cs

This file was deleted.

Loading

0 comments on commit 726cf7d

Please sign in to comment.