diff --git a/CHANGELOG.md b/CHANGELOG.md
index b889cbc3f5..5d18578360 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -11,6 +11,7 @@
- Fixed baggage propagation when an exception is thrown from middleware ([#2487](https://github.com/getsentry/sentry-dotnet/pull/2487))
- Fix Durable Functions preventing orchestrators from completing ([#2491](https://github.com/getsentry/sentry-dotnet/pull/2491))
- Re-enable HubTests.FlushOnDispose_SendsEnvelope ([#2492](https://github.com/getsentry/sentry-dotnet/pull/2492))
+- Introduced `HttpMessageHandler` in favor of the now deprecated `HttpClientHandler` on the options. This allows the SDK to support NSUrlSessionHandler on iOS ([#2503](https://github.com/getsentry/sentry-dotnet/pull/2503))
- Fixed the SDK failing to report issues via Blazor WebAssembly due to a `PlatformNotSupportedException` ([#2506](https://github.com/getsentry/sentry-dotnet/pull/2506))
### Dependencies
diff --git a/samples/Sentry.Samples.Console.Customized/Program.cs b/samples/Sentry.Samples.Console.Customized/Program.cs
index ae347ef6f4..b1af6291fd 100644
--- a/samples/Sentry.Samples.Console.Customized/Program.cs
+++ b/samples/Sentry.Samples.Console.Customized/Program.cs
@@ -90,8 +90,8 @@ await SentrySdk.ConfigureScopeAsync(async scope =>
// Using a proxy:
o.HttpProxy = null; //new WebProxy("https://localhost:3128");
- // Example customizing the HttpClientHandlers created
- o.CreateHttpClientHandler = () => new HttpClientHandler
+ // Example customizing the HttpMessageHandlers created
+ o.CreateHttpMessageHandler = () => new HttpClientHandler
{
ServerCertificateCustomValidationCallback = (_, certificate, _, _) =>
!certificate.Archived
diff --git a/samples/Sentry.Samples.Console.Profiling/Program.cs b/samples/Sentry.Samples.Console.Profiling/Program.cs
index bf3fdf1dc1..5d3d1ee1c2 100644
--- a/samples/Sentry.Samples.Console.Profiling/Program.cs
+++ b/samples/Sentry.Samples.Console.Profiling/Program.cs
@@ -85,7 +85,7 @@ await SentrySdk.ConfigureScopeAsync(async scope =>
o.HttpProxy = null; //new WebProxy("https://localhost:3128");
// Example customizing the HttpClientHandlers created
- o.CreateHttpClientHandler = () => new HttpClientHandler
+ o.CreateHttpMessageHandler = () => new HttpClientHandler
{
ServerCertificateCustomValidationCallback = (_, certificate, _, _) =>
!certificate.Archived
diff --git a/src/Sentry/Internal/Http/DefaultSentryHttpClientFactory.cs b/src/Sentry/Internal/Http/DefaultSentryHttpClientFactory.cs
index 51ac29f6fc..f8577e5bd7 100644
--- a/src/Sentry/Internal/Http/DefaultSentryHttpClientFactory.cs
+++ b/src/Sentry/Internal/Http/DefaultSentryHttpClientFactory.cs
@@ -20,25 +20,77 @@ public HttpClient Create(SentryOptions options)
throw new ArgumentNullException(nameof(options));
}
- var httpClientHandler = options.CreateHttpClientHandler?.Invoke() ?? new HttpClientHandler();
- if (options.HttpProxy != null)
+ HttpMessageHandler handler = options.CreateHttpMessageHandler?.Invoke() ?? new HttpClientHandler();
+ if (handler is HttpClientHandler httpClientHandler)
{
- httpClientHandler.Proxy = options.HttpProxy;
- options.LogInfo("Using Proxy: {0}", options.HttpProxy);
- }
+ if (options.HttpProxy != null)
+ {
+ httpClientHandler.Proxy = options.HttpProxy;
+ options.LogInfo("Using Proxy: {0}", options.HttpProxy);
+ }
- // If the platform supports automatic decompression
- if (SupportsAutomaticDecompression(httpClientHandler))
- {
- // if the SDK is configured to accept compressed data
- httpClientHandler.AutomaticDecompression = options.DecompressionMethods;
+ // If the platform supports automatic decompression
+ if (SupportsAutomaticDecompression(httpClientHandler))
+ {
+ // if the SDK is configured to accept compressed data
+ httpClientHandler.AutomaticDecompression = options.DecompressionMethods;
+ }
+ else
+ {
+ options.LogWarning("No response compression supported by HttpClientHandler.");
+ }
}
- else
+#if IOS
+ if (handler is System.Net.Http.NSUrlSessionHandler nsUrlSessionHandler)
{
- options.LogDebug("No response compression supported by HttpClientHandler.");
- }
+ if (options.HttpProxy != null)
+ {
+ bool supportsProxy = false;
+ if (nsUrlSessionHandler.SupportsProxy)
+ {
+ supportsProxy = true;
+ try
+ {
+ // Code analysis reports this as error, since it is marked as unsupported.
+ // Being aware of that this code is meant to support this feature as soon as
+ // supports it.
+#pragma warning disable CA1416
+ nsUrlSessionHandler.Proxy = options.HttpProxy;
+#pragma warning restore CA1416
+ options.LogInfo("Using Proxy: {0}", options.HttpProxy);
+ }
+ catch (PlatformNotSupportedException)
+ {
+ supportsProxy = false;
+ }
+ }
+ if (!supportsProxy)
+ {
+ options.LogWarning("No proxy supported by NSUrlSessionHandler.");
+ }
+ }
- HttpMessageHandler handler = httpClientHandler;
+ // If the platform supports automatic decompression
+ bool compressionSupported = false;
+ try
+ {
+ if (nsUrlSessionHandler.SupportsAutomaticDecompression)
+ {
+ // if the SDK is configured to accept compressed data
+ nsUrlSessionHandler.AutomaticDecompression = options.DecompressionMethods;
+ compressionSupported = true;
+ }
+ }
+ catch (PlatformNotSupportedException)
+ {
+ compressionSupported = false;
+ }
+ if (!compressionSupported)
+ {
+ options.LogInfo("No response compression supported by NSUrlSessionHandler.");
+ }
+ }
+#endif
if (options.RequestBodyCompressionLevel != CompressionLevel.NoCompression)
{
diff --git a/src/Sentry/SentryOptions.cs b/src/Sentry/SentryOptions.cs
index fa99c1644d..7dbc14e97b 100644
--- a/src/Sentry/SentryOptions.cs
+++ b/src/Sentry/SentryOptions.cs
@@ -540,10 +540,30 @@ public int MaxCacheItems
///
public IWebProxy? HttpProxy { get; set; }
+ ///
+ /// private field to hold the , since a typecheck or cast won't work here.
+ ///
+ private Func? _createClientHandler = null;
+
///
/// Creates the inner most .
+ /// Deprecated in favor of .
+ ///
+ [Obsolete("Use CreateHttpMessageHandler instead")]
+ public Func? CreateHttpClientHandler
+ {
+ get => _createClientHandler;
+ set
+ {
+ CreateHttpMessageHandler = value;
+ _createClientHandler = value;
+ }
+ }
+
+ ///
+ /// Creates the inner most .
///
- public Func? CreateHttpClientHandler { get; set; }
+ public Func? CreateHttpMessageHandler { get; set; }
///
/// A callback invoked when a is created.
diff --git a/test/Sentry.Google.Cloud.Functions.Tests/IntegrationTests.cs b/test/Sentry.Google.Cloud.Functions.Tests/IntegrationTests.cs
index f4411ee92d..a073e84e74 100644
--- a/test/Sentry.Google.Cloud.Functions.Tests/IntegrationTests.cs
+++ b/test/Sentry.Google.Cloud.Functions.Tests/IntegrationTests.cs
@@ -34,7 +34,7 @@ async Task VerifyAsync(HttpRequestMessage message)
{
// So we can assert on the payload without the need to Gzip decompress
o.RequestBodyCompressionLevel = CompressionLevel.NoCompression;
- o.CreateHttpClientHandler = () => new CallbackHttpClientHandler(VerifyAsync);
+ o.CreateHttpMessageHandler = () => new CallbackHttpClientHandler(VerifyAsync);
});
services.AddFunctionTarget();
})
diff --git a/test/Sentry.Profiling.Tests/SamplingTransactionProfilerTests.cs b/test/Sentry.Profiling.Tests/SamplingTransactionProfilerTests.cs
index 40d7e6e9cc..c6c47f0402 100644
--- a/test/Sentry.Profiling.Tests/SamplingTransactionProfilerTests.cs
+++ b/test/Sentry.Profiling.Tests/SamplingTransactionProfilerTests.cs
@@ -131,7 +131,7 @@ async Task VerifyAsync(HttpRequestMessage message)
FileSystem = fileSystem,
// So we don't need to deal with gzip'ed payload
RequestBodyCompressionLevel = CompressionLevel.NoCompression,
- CreateHttpClientHandler = () => new CallbackHttpClientHandler(VerifyAsync),
+ CreateHttpMessageHandler = () => new CallbackHttpClientHandler(VerifyAsync),
// Not to send some session envelope
AutoSessionTracking = false,
Debug = true,
diff --git a/test/Sentry.Tests/ApiApprovalTests.Run.Core3_1.verified.txt b/test/Sentry.Tests/ApiApprovalTests.Run.Core3_1.verified.txt
index 8f01bbf7d5..7c4bb4c1d5 100644
--- a/test/Sentry.Tests/ApiApprovalTests.Run.Core3_1.verified.txt
+++ b/test/Sentry.Tests/ApiApprovalTests.Run.Core3_1.verified.txt
@@ -603,7 +603,9 @@ namespace Sentry
public bool CaptureFailedRequests { get; set; }
public System.Action? ConfigureClient { get; set; }
public System.Func? CrashedLastRun { get; set; }
+ [System.Obsolete("Use CreateHttpMessageHandler instead")]
public System.Func? CreateHttpClientHandler { get; set; }
+ public System.Func? CreateHttpMessageHandler { get; set; }
public bool Debug { get; set; }
public System.Net.DecompressionMethods DecompressionMethods { get; set; }
public Sentry.DeduplicateMode DeduplicateMode { get; set; }
diff --git a/test/Sentry.Tests/ApiApprovalTests.Run.DotNet6_0.verified.txt b/test/Sentry.Tests/ApiApprovalTests.Run.DotNet6_0.verified.txt
index 6cc1c4e4a6..e2a943d0d3 100644
--- a/test/Sentry.Tests/ApiApprovalTests.Run.DotNet6_0.verified.txt
+++ b/test/Sentry.Tests/ApiApprovalTests.Run.DotNet6_0.verified.txt
@@ -604,7 +604,9 @@ namespace Sentry
public bool CaptureFailedRequests { get; set; }
public System.Action? ConfigureClient { get; set; }
public System.Func? CrashedLastRun { get; set; }
+ [System.Obsolete("Use CreateHttpMessageHandler instead")]
public System.Func? CreateHttpClientHandler { get; set; }
+ public System.Func? CreateHttpMessageHandler { get; set; }
public bool Debug { get; set; }
public System.Net.DecompressionMethods DecompressionMethods { get; set; }
public Sentry.DeduplicateMode DeduplicateMode { get; set; }
diff --git a/test/Sentry.Tests/ApiApprovalTests.Run.DotNet7_0.verified.txt b/test/Sentry.Tests/ApiApprovalTests.Run.DotNet7_0.verified.txt
index 6cc1c4e4a6..e2a943d0d3 100644
--- a/test/Sentry.Tests/ApiApprovalTests.Run.DotNet7_0.verified.txt
+++ b/test/Sentry.Tests/ApiApprovalTests.Run.DotNet7_0.verified.txt
@@ -604,7 +604,9 @@ namespace Sentry
public bool CaptureFailedRequests { get; set; }
public System.Action? ConfigureClient { get; set; }
public System.Func? CrashedLastRun { get; set; }
+ [System.Obsolete("Use CreateHttpMessageHandler instead")]
public System.Func? CreateHttpClientHandler { get; set; }
+ public System.Func? CreateHttpMessageHandler { get; set; }
public bool Debug { get; set; }
public System.Net.DecompressionMethods DecompressionMethods { get; set; }
public Sentry.DeduplicateMode DeduplicateMode { get; set; }
diff --git a/test/Sentry.Tests/ApiApprovalTests.Run.Net4_8.verified.txt b/test/Sentry.Tests/ApiApprovalTests.Run.Net4_8.verified.txt
index 5374f5f004..ac94a57bac 100644
--- a/test/Sentry.Tests/ApiApprovalTests.Run.Net4_8.verified.txt
+++ b/test/Sentry.Tests/ApiApprovalTests.Run.Net4_8.verified.txt
@@ -602,7 +602,9 @@ namespace Sentry
public bool CaptureFailedRequests { get; set; }
public System.Action? ConfigureClient { get; set; }
public System.Func? CrashedLastRun { get; set; }
+ [System.Obsolete("Use CreateHttpMessageHandler instead")]
public System.Func? CreateHttpClientHandler { get; set; }
+ public System.Func? CreateHttpMessageHandler { get; set; }
public bool Debug { get; set; }
public System.Net.DecompressionMethods DecompressionMethods { get; set; }
public Sentry.DeduplicateMode DeduplicateMode { get; set; }
diff --git a/test/Sentry.Tests/HubTests.cs b/test/Sentry.Tests/HubTests.cs
index f1999225ae..8945b04b51 100644
--- a/test/Sentry.Tests/HubTests.cs
+++ b/test/Sentry.Tests/HubTests.cs
@@ -328,7 +328,7 @@ async Task VerifyAsync(HttpRequestMessage message)
FileSystem = fileSystem,
// So we don't need to deal with gzip'ed payload
RequestBodyCompressionLevel = CompressionLevel.NoCompression,
- CreateHttpClientHandler = () => new CallbackHttpClientHandler(VerifyAsync),
+ CreateHttpMessageHandler = () => new CallbackHttpClientHandler(VerifyAsync),
// Not to send some session envelope
AutoSessionTracking = false,
Debug = true,
diff --git a/test/Sentry.Tests/Internals/DefaultSentryHttpClientFactoryTests.cs b/test/Sentry.Tests/Internals/DefaultSentryHttpClientFactoryTests.cs
index 1cf5b87c63..8e54d3b73a 100644
--- a/test/Sentry.Tests/Internals/DefaultSentryHttpClientFactoryTests.cs
+++ b/test/Sentry.Tests/Internals/DefaultSentryHttpClientFactoryTests.cs
@@ -98,7 +98,7 @@ public void Create_DefaultHeaders_AcceptJson()
public void Create_ProvidedCreateHttpClientHandler_ReturnedHandlerUsed()
{
var handler = Substitute.For();
- _fixture.HttpOptions.CreateHttpClientHandler = () => handler;
+ _fixture.HttpOptions.CreateHttpMessageHandler = () => handler;
var sut = Fixture.GetSut();
var client = sut.Create(_fixture.HttpOptions);
@@ -109,7 +109,7 @@ public void Create_ProvidedCreateHttpClientHandler_ReturnedHandlerUsed()
[Fact]
public void Create_NullCreateHttpClientHandler_HttpClientHandlerUsed()
{
- _fixture.HttpOptions.CreateHttpClientHandler = null;
+ _fixture.HttpOptions.CreateHttpMessageHandler = null;
var sut = Fixture.GetSut();
var client = sut.Create(_fixture.HttpOptions);
@@ -120,7 +120,7 @@ public void Create_NullCreateHttpClientHandler_HttpClientHandlerUsed()
[Fact]
public void Create_NullReturnedCreateHttpClientHandler_HttpClientHandlerUsed()
{
- _fixture.HttpOptions.CreateHttpClientHandler = () => null;
+ _fixture.HttpOptions.CreateHttpMessageHandler = () => null;
var sut = Fixture.GetSut();
var client = sut.Create(_fixture.HttpOptions);
diff --git a/test/Sentry.Tests/SentryClientTests.cs b/test/Sentry.Tests/SentryClientTests.cs
index fa9bd8aedc..abc5bb3123 100644
--- a/test/Sentry.Tests/SentryClientTests.cs
+++ b/test/Sentry.Tests/SentryClientTests.cs
@@ -1063,7 +1063,7 @@ public void Ctor_CreateHttpClientHandler_InvokedConfigureHandler()
var invoked = false;
_fixture.BackgroundWorker = null;
_fixture.SentryOptions.Dsn = ValidDsn;
- _fixture.SentryOptions.CreateHttpClientHandler = () =>
+ _fixture.SentryOptions.CreateHttpMessageHandler = () =>
{
invoked = true;
return Substitute.For();