From 2ca2942cd7c32090b2ee386d972394548556157b Mon Sep 17 00:00:00 2001 From: brian_pos Date: Fri, 22 Apr 2022 14:15:33 +1000 Subject: [PATCH 1/4] Support providing the HttpClient itself to the FhirClient instead of just the HttpClientHandler (as another alternative) This then supports creating unit tests as described here for webapi based projects https://www.hanselman.com/blog/minimal-apis-in-net-6-but-where-are-the-unit-tests --- .../Rest/FhirClientTests.cs | 90 ++++++++++++++++++- src/Hl7.Fhir.Core/Rest/FhirClient.cs | 33 ++++--- 2 files changed, 112 insertions(+), 11 deletions(-) diff --git a/src/Hl7.Fhir.Core.Tests/Rest/FhirClientTests.cs b/src/Hl7.Fhir.Core.Tests/Rest/FhirClientTests.cs index 4aef5badcd..6821b98e7f 100644 --- a/src/Hl7.Fhir.Core.Tests/Rest/FhirClientTests.cs +++ b/src/Hl7.Fhir.Core.Tests/Rest/FhirClientTests.cs @@ -1383,7 +1383,7 @@ public void CallsCallbacks() [TestMethod] [TestCategory("FhirClient"), TestCategory("IntegrationTest")] - public void CallsCallbacksHttpClient() + public void CallsCallbacksHttpClientHandler() { using (var handler = new HttpClientEventHandler()) { @@ -1468,6 +1468,94 @@ public void CallsCallbacksHttpClient() } } + [TestMethod] + [TestCategory("FhirClient"), TestCategory("IntegrationTest")] + public void CallsCallbacksHttpClient() + { + using (var handler = new HttpClientEventHandler()) + using (var httpClient = new HttpClient(handler)) + { + using (FhirClient client = new FhirClient(testEndpoint, httpClient: httpClient)) + { + client.Settings.ParserSettings.AllowUnrecognizedEnums = true; + + bool calledBefore = false; + HttpStatusCode? status = null; + byte[] body = null; + byte[] bodyOut = null; + + handler.OnBeforeRequest += (sender, e) => + { + calledBefore = true; + bodyOut = e.Body; + }; + + handler.OnAfterResponse += (sender, e) => + { + body = e.Body; + status = e.RawResponse.StatusCode; + }; + + var pat = client.Read("Patient/" + patientId); + Assert.IsTrue(calledBefore); + Assert.IsNotNull(status); + Assert.IsNotNull(body); + + var bodyText = HttpUtil.DecodeBody(body, Encoding.UTF8); + + Assert.IsTrue(bodyText.Contains(" + { + calledBefore = true; + bodyOut = e.Body; + }; + + handler.OnAfterResponse += (sender, e) => + { + body = e.Body; + status = e.RawResponse.StatusCode; + }; + + var pat = client.Read("Patient/" + patientId); + Assert.IsTrue(calledBefore); + Assert.IsNotNull(status); + Assert.IsNotNull(body); + + var bodyText = HttpUtil.DecodeBody(body, Encoding.UTF8); + + Assert.IsTrue(bodyText.Contains(" @@ -27,7 +27,8 @@ public partial class FhirClient : BaseFhirClient /// If the endpoint does not end with a slash (/), it will be added. /// /// - /// If the messageHandler is provided then it must be disposed by the caller + /// If the messageHandler, or httpClient is provided then it must be disposed by the caller + /// Only one of the messageHandler or httpClient can be provided /// /// /// The URL of the server to connect to.
@@ -35,16 +36,27 @@ public partial class FhirClient : BaseFhirClient /// /// /// + /// /// - public FhirClient(Uri endpoint, FhirClientSettings settings = null, HttpMessageHandler messageHandler = null, IStructureDefinitionSummaryProvider provider = null) : base(endpoint, settings, provider) + public FhirClient(Uri endpoint, FhirClientSettings settings = null, HttpMessageHandler messageHandler = null, HttpClient httpClient = null, IStructureDefinitionSummaryProvider provider = null) : base(endpoint, settings, provider) { - // If user does not supply message handler, add decompression strategy in default handler. - var handler = messageHandler ?? new HttpClientHandler() + HttpClientRequester requester; + if (httpClient != null) { - AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate - }; + if (messageHandler != null) throw new ArgumentException("Must not provide both messageHandler and httpClient parameters", nameof(messageHandler)); - var requester = new HttpClientRequester(Endpoint, Settings, handler, messageHandler == null); + requester = new HttpClientRequester(Endpoint, Settings, httpClient); + } + else + { + // If user does not supply message handler, create our own and add decompression strategy in default handler. + var handler = messageHandler ?? new HttpClientHandler() + { + AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate + }; + + requester = new HttpClientRequester(Endpoint, Settings, handler, messageHandler == null); + } Requester = requester; // Expose default request headers to user. @@ -62,9 +74,10 @@ public FhirClient(Uri endpoint, FhirClientSettings settings = null, HttpMessageH /// /// /// + /// /// - public FhirClient(string endpoint, FhirClientSettings settings = null, HttpMessageHandler messageHandler = null, IStructureDefinitionSummaryProvider provider = null) - : this(new Uri(endpoint), settings, messageHandler, provider) + public FhirClient(string endpoint, FhirClientSettings settings = null, HttpMessageHandler messageHandler = null, HttpClient httpClient = null, IStructureDefinitionSummaryProvider provider = null) + : this(new Uri(endpoint), settings, messageHandler, httpClient, provider) { } From 6dc665015032489f0e7f966639d080e5ba82dbbd Mon Sep 17 00:00:00 2001 From: brian_pos Date: Fri, 22 Apr 2022 22:44:13 +1000 Subject: [PATCH 2/4] Update the constructor based on the review feedback --- src/Hl7.Fhir.Core/Rest/FhirClient.cs | 68 +++++++++++++++++++--------- 1 file changed, 47 insertions(+), 21 deletions(-) diff --git a/src/Hl7.Fhir.Core/Rest/FhirClient.cs b/src/Hl7.Fhir.Core/Rest/FhirClient.cs index bde3877295..eef183a10c 100644 --- a/src/Hl7.Fhir.Core/Rest/FhirClient.cs +++ b/src/Hl7.Fhir.Core/Rest/FhirClient.cs @@ -6,7 +6,6 @@ * available at https://raw.githubusercontent.com/FirelyTeam/firely-net-sdk/master/LICENSE */ -using Hl7.Fhir.Model; using Hl7.Fhir.Serialization; using Hl7.Fhir.Specification; using System; @@ -36,33 +35,45 @@ public partial class FhirClient : BaseFhirClient /// /// /// - /// /// - public FhirClient(Uri endpoint, FhirClientSettings settings = null, HttpMessageHandler messageHandler = null, HttpClient httpClient = null, IStructureDefinitionSummaryProvider provider = null) : base(endpoint, settings, provider) + public FhirClient(Uri endpoint, FhirClientSettings settings = null, HttpMessageHandler messageHandler = null, IStructureDefinitionSummaryProvider provider = null) : base(endpoint, settings, provider) { - HttpClientRequester requester; - if (httpClient != null) + // If user does not supply message handler, create our own and add decompression strategy in default handler. + var handler = messageHandler ?? new HttpClientHandler() { - if (messageHandler != null) throw new ArgumentException("Must not provide both messageHandler and httpClient parameters", nameof(messageHandler)); - - requester = new HttpClientRequester(Endpoint, Settings, httpClient); - } - else - { - // If user does not supply message handler, create our own and add decompression strategy in default handler. - var handler = messageHandler ?? new HttpClientHandler() - { - AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate - }; + AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate + }; - requester = new HttpClientRequester(Endpoint, Settings, handler, messageHandler == null); - } + HttpClientRequester requester = new HttpClientRequester(Endpoint, Settings, handler, messageHandler == null); Requester = requester; // Expose default request headers to user. RequestHeaders = requester.Client.DefaultRequestHeaders; } + /// + /// Creates a new client using a default endpoint + /// If the endpoint does not end with a slash (/), it will be added. + /// + /// + /// If the messageHandler, or httpClient is provided then it must be disposed by the caller + /// Only one of the messageHandler or httpClient can be provided + /// + /// + /// The URL of the server to connect to.
+ /// If the trailing '/' is not present, then it will be appended automatically + /// + /// + /// + /// + public FhirClient(Uri endpoint, HttpClient httpClient, FhirClientSettings settings = null, IStructureDefinitionSummaryProvider provider = null) : base(endpoint, settings, provider) + { + HttpClientRequester requester = new HttpClientRequester(Endpoint, Settings, httpClient); + Requester = requester; + + // Expose default request headers to user. + RequestHeaders = requester.Client.DefaultRequestHeaders; + } /// /// Creates a new client using a default endpoint @@ -74,10 +85,25 @@ public FhirClient(Uri endpoint, FhirClientSettings settings = null, HttpMessageH /// /// /// + /// + public FhirClient(string endpoint, FhirClientSettings settings = null, HttpMessageHandler messageHandler = null, IStructureDefinitionSummaryProvider provider = null) + : this(new Uri(endpoint), settings, messageHandler, provider) + { + } + + /// + /// Creates a new client using a default endpoint + /// If the endpoint does not end with a slash (/), it will be added. + /// + /// + /// The URL of the server to connect to.
+ /// If the trailing '/' is not present, then it will be appended automatically + /// + /// /// /// - public FhirClient(string endpoint, FhirClientSettings settings = null, HttpMessageHandler messageHandler = null, HttpClient httpClient = null, IStructureDefinitionSummaryProvider provider = null) - : this(new Uri(endpoint), settings, messageHandler, httpClient, provider) + public FhirClient(string endpoint, HttpClient httpClient, FhirClientSettings settings = null, IStructureDefinitionSummaryProvider provider = null) + : this(new Uri(endpoint), httpClient, settings, provider) { } @@ -191,7 +217,7 @@ public ParserSettings ParserSettings } #endregion - [Obsolete ("OnBeforeRequest is deprecated, please add a HttpClientEventHandler or another HttpMessageHandler to the constructor to use this functionality", true)] + [Obsolete("OnBeforeRequest is deprecated, please add a HttpClientEventHandler or another HttpMessageHandler to the constructor to use this functionality", true)] public event EventHandler OnBeforeRequest; [Obsolete("OnAfterResponse is deprecated, please add a HttpClientEventHandler or another HttpMessageHandler to the constructor to use this functionality", true)] From 7a1f82e50bffce138ac53598d1d76e88b02d4e45 Mon Sep 17 00:00:00 2001 From: brian_pos Date: Tue, 26 Apr 2022 06:47:00 +1000 Subject: [PATCH 3/4] Update code comments --- src/Hl7.Fhir.Core/Rest/FhirClient.cs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/Hl7.Fhir.Core/Rest/FhirClient.cs b/src/Hl7.Fhir.Core/Rest/FhirClient.cs index eef183a10c..12fa75d112 100644 --- a/src/Hl7.Fhir.Core/Rest/FhirClient.cs +++ b/src/Hl7.Fhir.Core/Rest/FhirClient.cs @@ -26,8 +26,7 @@ public partial class FhirClient : BaseFhirClient /// If the endpoint does not end with a slash (/), it will be added. ///
/// - /// If the messageHandler, or httpClient is provided then it must be disposed by the caller - /// Only one of the messageHandler or httpClient can be provided + /// If the messageHandler is provided then it must be disposed by the caller /// /// /// The URL of the server to connect to.
@@ -56,8 +55,7 @@ public FhirClient(Uri endpoint, FhirClientSettings settings = null, HttpMessageH /// If the endpoint does not end with a slash (/), it will be added. /// /// - /// If the messageHandler, or httpClient is provided then it must be disposed by the caller - /// Only one of the messageHandler or httpClient can be provided + /// The httpClient must be disposed by the caller /// /// /// The URL of the server to connect to.
@@ -79,6 +77,9 @@ public FhirClient(Uri endpoint, HttpClient httpClient, FhirClientSettings settin /// Creates a new client using a default endpoint /// If the endpoint does not end with a slash (/), it will be added. /// + /// + /// If the messageHandler is provided then it must be disposed by the caller + /// /// /// The URL of the server to connect to.
/// If the trailing '/' is not present, then it will be appended automatically @@ -95,6 +96,9 @@ public FhirClient(string endpoint, FhirClientSettings settings = null, HttpMessa /// Creates a new client using a default endpoint /// If the endpoint does not end with a slash (/), it will be added. /// + /// + /// The httpClient must be disposed by the caller + /// /// /// The URL of the server to connect to.
/// If the trailing '/' is not present, then it will be appended automatically From 6b55ad62b3258b5d62af32f87a6550250c95a515 Mon Sep 17 00:00:00 2001 From: Marco Visser Date: Tue, 26 Apr 2022 11:21:06 +0200 Subject: [PATCH 4/4] Reference new common --- common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common b/common index daca988a75..fbf6876613 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit daca988a7547659811754dfb3a6a51b6c55bd0a5 +Subproject commit fbf6876613e690202f30ff195c7244eb8719f35c