Verwenden von diagnoselistener in EF CoreUsing Diagnostic Listeners in EF Core

Tipp

Sie können das Beispiel dieses Artikels von GitHub herunterladen.You can download this article's sample from GitHub.

Diagnoselistener ermöglichen das Lauschen auf EF Core-Ereignisse, die im aktuellen .NET-Prozess auftreten.Diagnostic listeners allow listening for any EF Core event that occurs in the current .NET process. Die- DiagnosticListener Klasse ist Teil eines allgemeinen Mechanismus in .net zum Abrufen von Diagnoseinformationen von ausgelaufenden Anwendungen.The DiagnosticListener class is a part of a common mechanism across .NET for obtaining diagnostic information from running applications.

Diagnoselistener sind nicht geeignet, um Ereignisse aus einer einzelnen DbContext-Instanz abzurufen.Diagnostic listeners are not suitable for getting events from a single DbContext instance. EF Core Interceptors ermöglichen den Zugriff auf dieselben Ereignisse mit pro-Kontext-Registrierung.EF Core interceptors provide access to the same events with per-context registration.

Diagnoselistener sind nicht für Protokollierung konzipiert.Diagnostic listeners are not designed for logging. Verwenden Sie für die Protokollierung die einfache Protokollierung oder Microsoft. Extensions. Logging .Consider using simple logging or Microsoft.Extensions.Logging for logging.

Beispiel: beobachten von Diagnose EreignissenExample: Observing diagnostic events

Das Auflösen von EF Core Ereignissen ist ein zweistufiger Prozess.Resolving EF Core events is a two-step process. Zuerst muss ein Beobachter für DiagnosticListener sich selbst erstellt werden:First, an observer for DiagnosticListener itself must be created:

public class DiagnosticObserver : IObserver<DiagnosticListener>
{
    public void OnCompleted()
        => throw new NotImplementedException();

    public void OnError(Exception error)
        => throw new NotImplementedException();

    public void OnNext(DiagnosticListener value)
    {
        if (value.Name == DbLoggerCategory.Name) // "Microsoft.EntityFrameworkCore"
        {
            value.Subscribe(new KeyValueObserver());
        }
    }
}

Die- OnNext Methode sucht nach dem diagnosticlistener, der aus EF Core stammt.The OnNext method looks for the DiagnosticListener that comes from EF Core. Dieser Listener hat den Namen "Microsoft. entityframeworkcore", der wie gezeigt aus der Klasse abgerufen werden kann DbLoggerCategory .This listener has the name "Microsoft.EntityFrameworkCore", which can be obtained from the DbLoggerCategory class as shown.

Dieser Beobachter muss dann Global registriert werden, z. b. in der-Methode der Anwendung Main :This observer must then be registered globally, for example in the application's Main method:

DiagnosticListener.AllListeners.Subscribe(new DiagnosticObserver());

Zweitens wird ein neuer Schlüsselwert Beobachter erstellt, um die eigentlichen EF Core Ereignisse zu abonnieren, sobald der EF Core diagnosticlistener gefunden wurde.Second, once the EF Core DiagnosticListener is found, a new key-value observer is created to subscribe to the actual EF Core events. Beispiel:For example:

public class KeyValueObserver : IObserver<KeyValuePair<string, object>>
{
    public void OnCompleted()
        => throw new NotImplementedException();

    public void OnError(Exception error)
        => throw new NotImplementedException();

    public void OnNext(KeyValuePair<string, object> value)
    {
        if (value.Key == CoreEventId.ContextInitialized.Name)
        {
            var payload = (ContextInitializedEventData)value.Value;
            Console.WriteLine($"EF is initializing {payload.Context.GetType().Name} ");
        }

        if (value.Key == RelationalEventId.ConnectionOpening.Name)
        {
            var payload = (ConnectionEventData)value.Value;
            Console.WriteLine($"EF is opening a connection to {payload.Connection.ConnectionString} ");
        }
    }
}

Die- OnNext Methode wird diesmal mit einem Schlüssel-Wert-Paar für jedes EF Core Ereignis aufgerufen.The OnNext method is this time called with a key/value pair for each EF Core event. Der Schlüssel ist der Name des Ereignisses, das von einem der folgenden Ergebnisse abgerufen werden kann:The key is the name of the event, which can be obtained from one of:

  • CoreEventId für Ereignisse, die für alle EF Core Datenbankanbieter üblich sindCoreEventId for events common to all EF Core database providers
  • RelationalEventId für Ereignisse, die allen relationalen Datenbankanbietern gemeinsam sindRelationalEventId for events common to all relational database providers
  • Eine ähnliche Klasse für Ereignisse, die für den aktuellen Datenbankanbieter spezifisch sind.A similar class for events specific to the current database provider. Beispielsweise SqlServerEventId für den SQL Server-Anbieter.For example, SqlServerEventId for the SQL Server provider.

Der Wert des Schlüssel-Wert-Paars ist ein für das ereignisspezifischer Nutz Lasttyp.The value of the key/value pair is a payload type specific to the event. Der Typ der zu erwartenden Nutzlast wird für jedes in diesen Ereignis Klassen definierte Ereignis dokumentiert.The type of payload to expect is documented on each event defined in these event classes.

Der obige Code verarbeitet z ContextInitialized . b. das-Ereignis und das- ConnectionOpening Ereignis.For example, the code above handles the ContextInitialized and the ConnectionOpening events. Für den ersten Wert ist die Nutzlast ContextInitializedEventData .For the first of these, the payload is ContextInitializedEventData. Der zweite Wert ist ConnectionEventData .For the second, it is ConnectionEventData.

Tipp

ToString wird in jeder EF Core Ereignisdaten Klasse überschrieben, um die entsprechende Protokollmeldung für das Ereignis zu generieren.ToString is overridden in every EF Core event data class to generate the equivalent log message for the event. Durch Aufrufen von wird z. b. ContextInitializedEventData.ToString "Entity Framework Core 5.0.0" blogscontext "mithilfe des Anbieters" Microsoft. entityframeworkcore. sqlite "mit den Optionen" None "initialisiert.For example, calling ContextInitializedEventData.ToString generates "Entity Framework Core 5.0.0 initialized 'BlogsContext' using provider 'Microsoft.EntityFrameworkCore.Sqlite' with options: None".

Das Beispiel enthält eine einfache Konsolenanwendung, die Änderungen an der Blog Datenbank vornimmt und die gefundenen Diagnose Ereignisse ausgibt.The sample contains a simple console application that makes changes to the blogging database and prints out the diagnostic events encountered.

public static void Main()
{
    DiagnosticListener.AllListeners.Subscribe(new DiagnosticObserver());

    using (var context = new BlogsContext())
    {
        context.Database.EnsureDeleted();
        context.Database.EnsureCreated();

        context.Add(
            new Blog { Name = "EF Blog", Posts = { new Post { Title = "EF Core 3.1!" }, new Post { Title = "EF Core 5.0!" } } });

        context.SaveChanges();
    }

    using (var context = new BlogsContext())
    {
        var blog = context.Blogs.Include(e => e.Posts).Single();

        blog.Name = "EF Core Blog";
        context.Remove(blog.Posts.First());
        blog.Posts.Add(new Post { Title = "EF Core 6.0!" });

        context.SaveChanges();
    }

Die Ausgabe dieses Codes zeigt die erkannten Ereignisse:The output from this code shows the events detected:

EF is initializing BlogsContext
EF is opening a connection to Data Source=blogs.db;Mode=ReadOnly
EF is opening a connection to DataSource=blogs.db
EF is opening a connection to Data Source=blogs.db;Mode=ReadOnly
EF is opening a connection to DataSource=blogs.db
EF is opening a connection to DataSource=blogs.db
EF is opening a connection to DataSource=blogs.db
EF is initializing BlogsContext
EF is opening a connection to DataSource=blogs.db
EF is opening a connection to DataSource=blogs.db