diff --git a/src/Sentry.AspNetCore/BindableSentryAspNetCoreOptions.cs b/src/Sentry.AspNetCore/BindableSentryAspNetCoreOptions.cs
new file mode 100644
index 0000000000..83b0aeabe4
--- /dev/null
+++ b/src/Sentry.AspNetCore/BindableSentryAspNetCoreOptions.cs
@@ -0,0 +1,32 @@
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.AspNetCore.Http;
+using Sentry.Extensibility;
+using Sentry.Extensions.Logging;
+
+#if NETSTANDARD2_0
+using IWebHostEnvironment = Microsoft.AspNetCore.Hosting.IHostingEnvironment;
+#else
+using Microsoft.Extensions.Hosting;
+#endif
+
+namespace Sentry.AspNetCore;
+
+///
+internal class BindableSentryAspNetCoreOptions : BindableSentryLoggingOptions
+{
+ public bool? IncludeActivityData { get; set; }
+ public RequestSize? MaxRequestBodySize { get; set; }
+ public bool? FlushOnCompletedRequest { get; set; }
+ public bool? FlushBeforeRequestCompleted { get; set; }
+ public bool? AdjustStandardEnvironmentNameCasing { get; set; }
+
+ public void ApplyTo(SentryAspNetCoreOptions options)
+ {
+ base.ApplyTo(options);
+ options.IncludeActivityData = IncludeActivityData ?? options.IncludeActivityData;
+ options.MaxRequestBodySize = MaxRequestBodySize ?? options.MaxRequestBodySize;
+ options.FlushOnCompletedRequest = FlushOnCompletedRequest ?? options.FlushOnCompletedRequest;
+ options.FlushBeforeRequestCompleted = FlushBeforeRequestCompleted ?? options.FlushBeforeRequestCompleted;
+ options.AdjustStandardEnvironmentNameCasing = AdjustStandardEnvironmentNameCasing ?? options.AdjustStandardEnvironmentNameCasing;
+ }
+}
diff --git a/src/Sentry.AspNetCore/Sentry.AspNetCore.csproj b/src/Sentry.AspNetCore/Sentry.AspNetCore.csproj
index b792f3d350..8522f35022 100644
--- a/src/Sentry.AspNetCore/Sentry.AspNetCore.csproj
+++ b/src/Sentry.AspNetCore/Sentry.AspNetCore.csproj
@@ -6,6 +6,11 @@
Official ASP.NET Core integration for Sentry - Open-source error tracking that helps developers monitor and fix crashes in real time.
+
+ true
+ true
+
+
@@ -26,6 +31,7 @@
+
diff --git a/src/Sentry.AspNetCore/SentryAspNetCoreOptionsSetup.cs b/src/Sentry.AspNetCore/SentryAspNetCoreOptionsSetup.cs
index 900953a495..882ae922a4 100644
--- a/src/Sentry.AspNetCore/SentryAspNetCoreOptionsSetup.cs
+++ b/src/Sentry.AspNetCore/SentryAspNetCoreOptionsSetup.cs
@@ -1,3 +1,4 @@
+using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging.Configuration;
using Microsoft.Extensions.Options;
using Sentry.Extensions.Logging;
@@ -13,6 +14,7 @@ namespace Sentry.AspNetCore;
///
/// Sets up ASP.NET Core option for Sentry.
///
+#if NETSTANDARD2_0
public class SentryAspNetCoreOptionsSetup : ConfigureFromConfigurationOptions
{
///
@@ -30,7 +32,53 @@ public SentryAspNetCoreOptionsSetup(
public override void Configure(SentryAspNetCoreOptions options)
{
base.Configure(options);
+ options.AddDiagnosticSourceIntegration();
+ options.DeduplicateUnhandledException();
+ }
+}
+
+#else
+public class SentryAspNetCoreOptionsSetup : IConfigureOptions
+{
+ private readonly IConfiguration _config;
+
+ ///
+ /// Creates a new instance of .
+ ///
+ public SentryAspNetCoreOptionsSetup(ILoggerProviderConfiguration providerConfiguration)
+ : this(providerConfiguration.Configuration)
+ {
+ }
+ ///
+ /// Creates a new instance of .
+ ///
+ internal SentryAspNetCoreOptionsSetup(IConfiguration config)
+ {
+ ArgumentNullException.ThrowIfNull(config);
+ _config = config;
+ }
+
+ ///
+ /// Configures the .
+ ///
+ public void Configure(SentryAspNetCoreOptions options)
+ {
+ ArgumentNullException.ThrowIfNull(options);
+
+ var bindable = new BindableSentryAspNetCoreOptions();
+ _config.Bind(bindable);
+ bindable.ApplyTo(options);
+
+ options.DeduplicateUnhandledException();
+ }
+}
+#endif
+
+internal static class SentryAspNetCoreOptionsExtensions
+{
+ internal static void DeduplicateUnhandledException(this SentryAspNetCoreOptions options)
+ {
options.AddLogEntryFilter((category, _, eventId, _)
// https://github.com/aspnet/KestrelHttpServer/blob/0aff4a0440c2f393c0b98e9046a8e66e30a56cb0/src/Kestrel.Core/Internal/Infrastructure/KestrelTrace.cs#L33
// 13 = Application unhandled exception, which is captured by the middleware so the LogError of kestrel ends up as a duplicate with less info
@@ -39,9 +87,5 @@ public override void Configure(SentryAspNetCoreOptions options)
category,
"Microsoft.AspNetCore.Server.Kestrel",
StringComparison.Ordinal));
-
-#if NETSTANDARD2_0
- options.AddDiagnosticSourceIntegration();
-#endif
}
}
diff --git a/src/Sentry.AspNetCore/SentryTunnelMiddleware.cs b/src/Sentry.AspNetCore/SentryTunnelMiddleware.cs
index 4be7cbf8d5..2278f61a01 100644
--- a/src/Sentry.AspNetCore/SentryTunnelMiddleware.cs
+++ b/src/Sentry.AspNetCore/SentryTunnelMiddleware.cs
@@ -1,5 +1,6 @@
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
+using Sentry.Internal.Extensions;
namespace Sentry.AspNetCore;
@@ -70,7 +71,14 @@ public async Task InvokeAsync(HttpContext context, RequestDelegate next)
try
{
+#if NETSTANDARD2_0
var headerJson = JsonSerializer.Deserialize>(header);
+#else
+ var headerJson = JsonSerializer.Deserialize(
+ header,
+ SentryJsonContext.Default.DictionaryStringObject
+ );
+#endif
if (headerJson == null)
{
response.StatusCode = StatusCodes.Status400BadRequest;
diff --git a/src/Sentry.AspNetCore/SentryWebHostBuilderExtensions.cs b/src/Sentry.AspNetCore/SentryWebHostBuilderExtensions.cs
index ee83bf9560..931da5bcf2 100644
--- a/src/Sentry.AspNetCore/SentryWebHostBuilderExtensions.cs
+++ b/src/Sentry.AspNetCore/SentryWebHostBuilderExtensions.cs
@@ -1,4 +1,5 @@
using Microsoft.AspNetCore.Builder;
+using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Configuration;
@@ -83,8 +84,13 @@ public static IWebHostBuilder UseSentry(
logging.AddConfiguration();
var section = context.Configuration.GetSection("Sentry");
+#if NETSTANDARD2_0
_ = logging.Services.Configure(section);
-
+#else
+ _ = logging.Services.AddSingleton>(_ =>
+ new SentryAspNetCoreOptionsSetup(section)
+ );
+#endif
_ = logging.Services
.AddSingleton, SentryAspNetCoreOptionsSetup>();
_ = logging.Services.AddSingleton();
diff --git a/src/Sentry/Internal/Extensions/JsonExtensions.cs b/src/Sentry/Internal/Extensions/JsonExtensions.cs
index 0c95721e05..3dc403efb7 100644
--- a/src/Sentry/Internal/Extensions/JsonExtensions.cs
+++ b/src/Sentry/Internal/Extensions/JsonExtensions.cs
@@ -887,6 +887,7 @@ public static void WriteString(
[JsonSerializable(typeof(GrowableArray))]
[JsonSerializable(typeof(Dictionary))]
+[JsonSerializable(typeof(Dictionary))]
internal partial class SentryJsonContext : JsonSerializerContext
{
}
diff --git a/test/Sentry.AspNetCore.Tests/ApiApprovalTests.Run.DotNet6_0.verified.txt b/test/Sentry.AspNetCore.Tests/ApiApprovalTests.Run.DotNet6_0.verified.txt
index d8085ec032..df39c25e34 100644
--- a/test/Sentry.AspNetCore.Tests/ApiApprovalTests.Run.DotNet6_0.verified.txt
+++ b/test/Sentry.AspNetCore.Tests/ApiApprovalTests.Run.DotNet6_0.verified.txt
@@ -58,10 +58,10 @@ namespace Sentry.AspNetCore
public Sentry.Extensibility.RequestSize MaxRequestBodySize { get; set; }
public Sentry.AspNetCore.TransactionNameProvider? TransactionNameProvider { get; set; }
}
- public class SentryAspNetCoreOptionsSetup : Microsoft.Extensions.Options.ConfigureFromConfigurationOptions
+ public class SentryAspNetCoreOptionsSetup : Microsoft.Extensions.Options.IConfigureOptions
{
public SentryAspNetCoreOptionsSetup(Microsoft.Extensions.Logging.Configuration.ILoggerProviderConfiguration providerConfiguration) { }
- public override void Configure(Sentry.AspNetCore.SentryAspNetCoreOptions options) { }
+ public void Configure(Sentry.AspNetCore.SentryAspNetCoreOptions options) { }
}
public static class SentryBuilderExtensions
{
diff --git a/test/Sentry.AspNetCore.Tests/ApiApprovalTests.Run.DotNet7_0.verified.txt b/test/Sentry.AspNetCore.Tests/ApiApprovalTests.Run.DotNet7_0.verified.txt
index d8085ec032..df39c25e34 100644
--- a/test/Sentry.AspNetCore.Tests/ApiApprovalTests.Run.DotNet7_0.verified.txt
+++ b/test/Sentry.AspNetCore.Tests/ApiApprovalTests.Run.DotNet7_0.verified.txt
@@ -58,10 +58,10 @@ namespace Sentry.AspNetCore
public Sentry.Extensibility.RequestSize MaxRequestBodySize { get; set; }
public Sentry.AspNetCore.TransactionNameProvider? TransactionNameProvider { get; set; }
}
- public class SentryAspNetCoreOptionsSetup : Microsoft.Extensions.Options.ConfigureFromConfigurationOptions
+ public class SentryAspNetCoreOptionsSetup : Microsoft.Extensions.Options.IConfigureOptions
{
public SentryAspNetCoreOptionsSetup(Microsoft.Extensions.Logging.Configuration.ILoggerProviderConfiguration providerConfiguration) { }
- public override void Configure(Sentry.AspNetCore.SentryAspNetCoreOptions options) { }
+ public void Configure(Sentry.AspNetCore.SentryAspNetCoreOptions options) { }
}
public static class SentryBuilderExtensions
{
diff --git a/test/Sentry.AspNetCore.Tests/ApiApprovalTests.Run.DotNet8_0.verified.txt b/test/Sentry.AspNetCore.Tests/ApiApprovalTests.Run.DotNet8_0.verified.txt
index d8085ec032..df39c25e34 100644
--- a/test/Sentry.AspNetCore.Tests/ApiApprovalTests.Run.DotNet8_0.verified.txt
+++ b/test/Sentry.AspNetCore.Tests/ApiApprovalTests.Run.DotNet8_0.verified.txt
@@ -58,10 +58,10 @@ namespace Sentry.AspNetCore
public Sentry.Extensibility.RequestSize MaxRequestBodySize { get; set; }
public Sentry.AspNetCore.TransactionNameProvider? TransactionNameProvider { get; set; }
}
- public class SentryAspNetCoreOptionsSetup : Microsoft.Extensions.Options.ConfigureFromConfigurationOptions
+ public class SentryAspNetCoreOptionsSetup : Microsoft.Extensions.Options.IConfigureOptions
{
public SentryAspNetCoreOptionsSetup(Microsoft.Extensions.Logging.Configuration.ILoggerProviderConfiguration providerConfiguration) { }
- public override void Configure(Sentry.AspNetCore.SentryAspNetCoreOptions options) { }
+ public void Configure(Sentry.AspNetCore.SentryAspNetCoreOptions options) { }
}
public static class SentryBuilderExtensions
{
diff --git a/test/Sentry.AspNetCore.Tests/SentryAspNetCoreOptionsSetupTests.cs b/test/Sentry.AspNetCore.Tests/SentryAspNetCoreOptionsSetupTests.cs
index 49524f6b9a..8cf76716ab 100644
--- a/test/Sentry.AspNetCore.Tests/SentryAspNetCoreOptionsSetupTests.cs
+++ b/test/Sentry.AspNetCore.Tests/SentryAspNetCoreOptionsSetupTests.cs
@@ -1,3 +1,4 @@
+using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Configuration;
@@ -11,29 +12,60 @@ namespace Sentry.AspNetCore.Tests;
public class SentryAspNetCoreOptionsSetupTests
{
- private readonly SentryAspNetCoreOptionsSetup _sut = new(
- Substitute.For>());
+ class Fixture
+ {
+ public Dictionary Configuration { get; set; } = new();
+
+ public SentryAspNetCoreOptionsSetup GetSut()
+ {
+ var config = new ConfigurationBuilder()
+ .AddInMemoryCollection(Configuration)
+ .Build();
+ var loggingConfig = Substitute.For>();
+ loggingConfig.Configuration.Returns(config);
+ return new(loggingConfig);
+ }
+ }
+ private readonly Fixture _fixture = new();
private readonly SentryAspNetCoreOptions _target = new();
[Fact]
public void Filters_KestrelApplicationEvent_NoException_Filtered()
{
- _sut.Configure(_target);
+ // Arrange
+ var sut = _fixture.GetSut();
+
+ // Act
+ sut.Configure(_target);
+
+ //Assert
Assert.Contains(_target.Filters, f => f.Filter("Microsoft.AspNetCore.Server.Kestrel", LogLevel.Critical, 13, null));
}
[Fact]
public void Filters_KestrelApplicationEvent_WithException_Filtered()
{
- _sut.Configure(_target);
+ // Arrange
+ var sut = _fixture.GetSut();
+
+ // Act
+ sut.Configure(_target);
+
+ // Assert
Assert.Contains(_target.Filters, f => f.Filter("Microsoft.AspNetCore.Server.Kestrel", LogLevel.Critical, 13, new Exception()));
}
[Fact]
public void Filters_KestrelEventId1_WithException_NotFiltered()
{
- _sut.Configure(_target);
+ // Arrange
+ var sut = _fixture.GetSut();
+
+ // Act
+ sut.Configure(_target);
+
+ // Assert
Assert.DoesNotContain(_target.Filters, f => f.Filter("Microsoft.AspNetCore.Server.Kestrel", LogLevel.Trace, 1, null));
}