Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Collecting database events from a .NET 6 application causes it to crash #57709

Closed
davidmikh opened this issue Aug 19, 2021 · 7 comments · Fixed by #58145
Closed

Collecting database events from a .NET 6 application causes it to crash #57709

davidmikh opened this issue Aug 19, 2021 · 7 comments · Fixed by #58145

Comments

@davidmikh
Copy link

davidmikh commented Aug 19, 2021

Description

Applications that generate database operation related events (either by using EF Core or with using normal SQL queries) will crash when database operation related events are being collected from them due to a System.Reflection.AmbiguousMatchException. Below are instructions on how to repro the issue:

  1. Run a .NET 6 application that does database operations either through EF Core or regular SQL commands (I can provide an example if needed via email)

  2. Profile the application using dotnet-trace with the following command (this command is specific to Windows, if running on Linux the quotation marks in the providers string need to be slightly different):

dotnet-trace collect -p <PID> --providers Microsoft-Diagnostics-DiagnosticSource:00000003:5:FilterAndPayloadSpecs=\"SqlClientDiagnosticListener/System.Data.SqlClient.WriteCommandBefore@Activity1Start:-Command;Command.CommandText;ConnectionId;Operation;Command.Connection.ServerVersion;Command.CommandTimeout;Command.CommandType;Command.Connection.ConnectionString;Command.Connection.Database;Command.Connection.DataSource;Command.Connection.PacketSize\r\nSqlClientDiagnosticListener/System.Data.SqlClient.WriteCommandAfter@Activity1Stop:\r\nMicrosoft.EntityFrameworkCore/Microsoft.EntityFrameworkCore.Database.Command.CommandExecuting@Activity2Start:-Command.CommandText;Command;ConnectionId;IsAsync;Command.Connection.ClientConnectionId;Command.Connection.ServerVersion;Command.CommandTimeout;Command.CommandType;Command.Connection.ConnectionString;Command.Connection.Database;Command.Connection.DataSource;Command.Connection.PacketSize\r\nMicrosoft.EntityFrameworkCore/Microsoft.EntityFrameworkCore.Database.Command.CommandExecuted@Activity2Stop:\",System.Threading.Tasks.TplEventSource

The application will then crash with the following exception:

System.Reflection.AmbiguousMatchException: 'Ambiguous match found.'

Where the stack trace looks like this:

   at System.RuntimeType.GetPropertyImpl(String name, BindingFlags bindingAttr, Binder binder, Type returnType, Type[] types, ParameterModifier[] modifiers)
   at System.Type.GetProperty(String name, BindingFlags bindingAttr)
   at System.Diagnostics.DiagnosticSourceEventSource.TransformSpec.PropertySpec.PropertyFetch.FetcherForProperty(Type type, String propertyName)
   at System.Diagnostics.DiagnosticSourceEventSource.TransformSpec.PropertySpec.Fetch(Object obj)
   at System.Diagnostics.DiagnosticSourceEventSource.TransformSpec.Morph(Object obj)
   at System.Diagnostics.DiagnosticSourceEventSource.FilterAndTransform.Morph(Object args)
   at System.Diagnostics.DiagnosticSourceEventSource.FilterAndTransform.<>c__DisplayClass2_1.<.ctor>g__OnEventWritten|2(KeyValuePair`2 evnt)
   at System.Diagnostics.DiagnosticSourceEventSource.CallbackObserver`1.OnNext(T value)
   at System.Diagnostics.DiagnosticListener.Write(String name, Object value)
   at Microsoft.EntityFrameworkCore.Diagnostics.IDiagnosticsLogger.DispatchEventData(EventDefinitionBase definition, EventData eventData, Boolean diagnosticSourceEnabled, Boolean simpleLogEnabled)
   at Microsoft.EntityFrameworkCore.Diagnostics.RelationalLoggerExtensions.CommandReaderExecuting(IDiagnosticsLogger`1 diagnostics, IRelationalConnection connection, DbCommand command, DbContext context, Guid commandId, Guid connectionId, DateTimeOffset startTime)
   at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReader(RelationalCommandParameterObject parameterObject)
   at Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable`1.Enumerator.InitializeReader(DbContext _, Boolean result)
   at Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable`1.Enumerator.MoveNext()
   at EFTestApp.Program.Main() in C:\dtl-bhrb4jy0\_work\r1\a\tempTestRoot\ApexSolutions\TestCase5\DBTool_LinuxContainer_Attach_EFCore_SQLite\Program.cs:line 43

Configuration

Operating system: 64 bit Windows
.NET version: 6.0.100-preview.7.21379.14
dotnet-trace version: 5.0.236902+5366510b270d0f0ebffc9e36e9496688b20b96c2

This seems to be specific to .NET 6, though I'm not sure which version it started to appear in. If you make the application target .NET 5 instead of .NET 6 then collecting database events from it will work as expected (won't cause the application to crash).

Regression?

This is a regression, if you change the application to target .NET 5 and everything else remains the same (same application, same OS, same version of dotnet-trace) then you will be able to collect database related events without issue. This is the version of .NET 5 I tested this with: 5.0.9

Other information

There is no known workaround currently other than downgrading the version of .NET your application uses. This issue also blocks the Visual Studio Performance Profiler's database tool from supporting .NET 6 in any scenario since it collects database events from applications.

@dotnet-issue-labeler dotnet-issue-labeler bot added area-System.Diagnostics.Tracing untriaged New issue has not been triaged by the area owner labels Aug 19, 2021
@ghost
Copy link

ghost commented Aug 19, 2021

Tagging subscribers to this area: @tarekgh, @tommcdon, @pjanotti
See info in area-owners.md if you want to be subscribed.

Issue Details

Description

Applications that generate database operation related events (either by using EF Core or with using normal SQL queries) will crash when database operation related events are being collected from them due to a System.Reflection.AmbiguousMatchException. Below are instructions on how to repro the issue:

  1. Run a .NET 6 application that does database operations either through EF Core or regular SQL commands (I can provide an example if needed via email)

  2. Profile the application using dotnet-trace with the following command (this command is specific to Windows, if running on Linux the quotation marks in the providers string need to be slightly different):

dotnet-trace collect -p --providers Microsoft-Diagnostics-DiagnosticSource:00000003:5:FilterAndPayloadSpecs=\SqlClientDiagnosticListener/System.Data.SqlClient.WriteCommandBefore@Activity1Start:-Command;Command.CommandText;ConnectionId;Operation;Command.Connection.ServerVersion;Command.CommandTimeout;Command.CommandType;Command.Connection.ConnectionString;Command.Connection.Database;Command.Connection.DataSource;Command.Connection.PacketSize\r\nSqlClientDiagnosticListener/System.Data.SqlClient.WriteCommandAfter@Activity1Stop:\r\nMicrosoft.EntityFrameworkCore/Microsoft.EntityFrameworkCore.Database.Command.CommandExecuting@Activity2Start:-Command.CommandText;Command;ConnectionId;IsAsync;Command.Connection.ClientConnectionId;Command.Connection.ServerVersion;Command.CommandTimeout;Command.CommandType;Command.Connection.ConnectionString;Command.Connection.Database;Command.Connection.DataSource;Command.Connection.PacketSize\r\nMicrosoft.EntityFrameworkCore/Microsoft.EntityFrameworkCore.Database.Command.CommandExecuted@Activity2Stop:,System.Threading.Tasks.TplEventSource

The application will then crash with the following exception:

System.Reflection.AmbiguousMatchException: 'Ambiguous match found.'

Where the stack trace looks like this:

at System.RuntimeType.GetPropertyImpl(String name, BindingFlags bindingAttr, Binder binder, Type returnType, Type[] types, ParameterModifier[] modifiers)
at System.Type.GetProperty(String name, BindingFlags bindingAttr)
at System.Diagnostics.DiagnosticSourceEventSource.TransformSpec.PropertySpec.PropertyFetch.FetcherForProperty(Type type, String propertyName)
at System.Diagnostics.DiagnosticSourceEventSource.TransformSpec.PropertySpec.Fetch(Object obj)
at System.Diagnostics.DiagnosticSourceEventSource.TransformSpec.Morph(Object obj)
at System.Diagnostics.DiagnosticSourceEventSource.FilterAndTransform.Morph(Object args)
at System.Diagnostics.DiagnosticSourceEventSource.FilterAndTransform.<>c__DisplayClass2_1.<.ctor>g__OnEventWritten|2(KeyValuePair2 evnt) at System.Diagnostics.DiagnosticSourceEventSource.CallbackObserver1.OnNext(T value)
at System.Diagnostics.DiagnosticListener.Write(String name, Object value)
at Microsoft.EntityFrameworkCore.Diagnostics.IDiagnosticsLogger.DispatchEventData(EventDefinitionBase definition, EventData eventData, Boolean diagnosticSourceEnabled, Boolean simpleLogEnabled)
at Microsoft.EntityFrameworkCore.Diagnostics.RelationalLoggerExtensions.CommandReaderExecuting(IDiagnosticsLogger1 diagnostics, IRelationalConnection connection, DbCommand command, DbContext context, Guid commandId, Guid connectionId, DateTimeOffset startTime) at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReader(RelationalCommandParameterObject parameterObject) at Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable1.Enumerator.InitializeReader(DbContext _, Boolean result)
at Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable`1.Enumerator.MoveNext()
at EFTestApp.Program.Main() in C:\dtl-bhrb4jy0_work\r1\a\tempTestRoot\ApexSolutions\TestCase5\DBTool_LinuxContainer_Attach_EFCore_SQLite\Program.cs:line 43

Configuration

Operating system: 64 bit Windows
.NET version: 6.0.100-preview.7.21379.14
dotnet-trace version: 5.0.236902+5366510b270d0f0ebffc9e36e9496688b20b96c2

This seems to be specific to .NET 6, though I'm not sure which version it started to appear in. If you make the application target .NET 5 instead of .NET 6 then collecting database events from it will work as expected (won't cause the application to crash).

Regression?

This is a regression, if you change the application to target .NET 5 and everything else remains the same (same application, same OS, same version of dotnet-trace) then you will be able to collect database related events without issue. This is the version of .NET 5 I tested this with: 5.0.9

Other information

There is no known workaround currently other than downgrading the version of .NET your application uses. This issue also blocks the Visual Studio Performance Profiler's database tool from supporting .NET 6 in any scenario since it collects database events from applications.

Author: davidmikh
Assignees: -
Labels:

area-System.Diagnostics.Tracing, untriaged

Milestone: -

@tommcdon
Copy link
Member

@josalem This is a regression between .NET 5 and .NET 6, possibly related to changes in DiagnosticSourceEventSource.

@tommcdon tommcdon added this to the 6.0.0 milestone Aug 19, 2021
@tommcdon tommcdon removed the untriaged New issue has not been triaged by the area owner label Aug 19, 2021
@davmason
Copy link
Member

I took a look, it's failing due to the code added in #55613. The EF code is trying to fire an event with a SqliteCommand as an argument and it has a Connection property, but so does its base class DbCommand. The call to GetProperty throws an AmbiguousMatchException.

Changing from typeInfo.GetProperty() to typeInfo.GetProperties().FirstOrDefault() would fix the exception, but I don't know off the top of my head if that does what we want. Presumably we want to prefer the derived class fields over the base class fields.

It's definitely possible to fix once we give it some thought.

@tarekgh
Copy link
Member

tarekgh commented Aug 19, 2021

Would it make sense calling first typeInfo.GetDeclaredProperty and if it returns null, at that time call typeInfo.GetProperties().FirstOrDefault()? I am not sure if this will affect the performance, but I am not expecting that regress old scenarios but maybe be slower for new scenarios which need getting the property from parent classes.

@davmason
Copy link
Member

Would it make sense calling first typeInfo.GetDeclaredProperty and if it returns null, at that time call typeInfo.GetProperties().FirstOrDefault()? I am not sure if this will affect the performance, but I am not expecting that regress old scenarios but maybe be slower for new scenarios which need getting the property from parent classes.

I had starting thinking along the same lines. The performance of this code that generates event manifests is already pretty bad, I doubt one extra call would make things noticeably worse. This is probably a good solution to start with

@josalem josalem self-assigned this Aug 23, 2021
@ghost ghost added the in-pr There is an active PR which will close this issue when it is merged label Aug 25, 2021
@ghost ghost removed the in-pr There is an active PR which will close this issue when it is merged label Aug 26, 2021
@josalem
Copy link
Contributor

josalem commented Aug 26, 2021

Reopening till this is merged into .net6-rc2

@josalem josalem reopened this Aug 26, 2021
@ghost ghost added in-pr There is an active PR which will close this issue when it is merged and removed in-pr There is an active PR which will close this issue when it is merged labels Aug 26, 2021
@tommcdon
Copy link
Member

Closing via #58212

@ghost ghost locked as resolved and limited conversation to collaborators Sep 28, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants