sentry-dotnet icon indicating copy to clipboard operation
sentry-dotnet copied to clipboard

Unable to use ISentryEventExceptionProcessor with Scoped DI

Open udlose opened this issue 6 years ago • 4 comments

Framework used: ASP.NET Core

Runtime used: .NET Core Version: 2.2.7

NuGet packages used: Sentry.AspNetCore Version: 1.2.0

I get a Startup error with the following exception when I register ISentryEventExceptionProcessor as a Scoped instance. This works correctly if I register it as Transient or Singleton.

Exception:

 An error occurred while starting the application.
 InvalidOperationException: Cannot resolve 'System.Collections.Generic.IEnumerable`1[Sentry.Extensibility.ISentryEventExceptionProcessor]' from root provider because it requires scoped service 'Sentry.Extensibility.ISentryEventExceptionProcessor'.
 Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteValidator.ValidateResolution(Type serviceType, IServiceScope scope, IServiceScope rootScope)
 
 InvalidOperationException: Cannot resolve 'System.Collections.Generic.IEnumerable`1[Sentry.Extensibility.ISentryEventExceptionProcessor]' from root provider because it requires scoped service 'Sentry.Extensibility.ISentryEventExceptionProcessor'.
 Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteValidator.ValidateResolution(Type serviceType, IServiceScope scope, IServiceScope rootScope)
 Microsoft.Extensions.DependencyInjection.ServiceProvider.Microsoft.Extensions.DependencyInjection.ServiceLookup.IServiceProviderEngineCallback.OnResolve(Type serviceType, IServiceScope scope)
 Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngine.GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope)
 Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngine.GetService(Type serviceType)
 Microsoft.Extensions.DependencyInjection.ServiceProvider.GetService(Type serviceType)
 Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetService<T>(IServiceProvider provider)
 Microsoft.AspNetCore.Builder.ApplicationBuilderExtensions.UseSentry(IApplicationBuilder app) in ApplicationBuilderExtensions.cs
 Sentry.AspNetCore.SentryStartupFilter+<>c__DisplayClass0_0.<Configure>b__0(IApplicationBuilder e) in SentryStartupFilter.cs
 Microsoft.AspNetCore.Server.IIS.Core.IISServerSetupFilter+<>c__DisplayClass2_0.<Configure>b__0(IApplicationBuilder app)
 Microsoft.AspNetCore.HostFilteringStartupFilter+<>c__DisplayClass0_0.<Configure>b__0(IApplicationBuilder app)
 Microsoft.AspNetCore.Hosting.Internal.AutoRequestServicesStartupFilter+<>c__DisplayClass0_0.<Configure>b__0(IApplicationBuilder builder)
 Microsoft.AspNetCore.Hosting.Internal.WebHost.BuildApplication()

In my Program.cs:

WebHost.CreateDefaultBuilder(args)
    .ConfigureLogging((hostingContext, logging) =>
    {
        // Requires `using Microsoft.Extensions.Logging;`
        logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
        logging.AddConsole();
        logging.AddDebug();
        logging.AddEventSourceLogger();
    })
    .UseStartup<Startup>()
    .UseSentry();

In my Startup for DI registration:

// Sentry (logging/exception handling)
services.AddTransient<ISentryEventProcessor, CustomEventProcessor>();

//This does not work
services.AddScoped<ISentryEventExceptionProcessor, CustomEventExceptionProcessor>();
//This works
//services.AddSingleton<ISentryEventExceptionProcessor, CustomEventExceptionProcessor>();
//This works
//services.AddTransient<ISentryEventExceptionProcessor, CustomEventExceptionProcessor>();

CustomEventExceptionProcessor:

public class CustomEventExceptionProcessor : ISentryEventExceptionProcessor
{
    public void Process(Exception exception, SentryEvent sentryEvent)
    {
        //throw new NotImplementedException();
    }
}

CustomEventProcessor:

public class CustomEventProcessor : ISentryEventProcessor
{
    public SentryEvent Process(SentryEvent @event)
    {
        //throw new NotImplementedException();
        return @event;
    }
}

udlose avatar Dec 02 '19 22:12 udlose

Thanks for raising this. I'll take a look soon.

bruno-garcia avatar Dec 06 '19 12:12 bruno-garcia

any updates on this?

udlose avatar Mar 04 '20 17:03 udlose

Sorry but I haven't had time to look at it yet. I suspect that the DI container doesn't use AsyncLocal for Scoped lifetime (creates a new container with the reference held by the HttpContext and somehow the callback we have is for an outer instance of the container (since we get it when the app starts). If that's the case, we could change it so that we register the EventProcessorProvider in the SentryMiddleware grabbing the container from the HttpContext. This way we'd be resolving Scoped properly.

Would really appreciate some help with this since we're pretty busy here right now working on release health

bruno-garcia avatar Mar 05 '20 15:03 bruno-garcia

Is there a workaround to make this work? I would like to supply the user details (in a different scoped service) and can only do it if I inject ISentryEventExceptionProcessor as a scoped service.

Yourstress avatar May 28 '20 23:05 Yourstress