在 EF Core 中使用診斷接聽程式
提示
您可以從 GitHub 下載本文的範例 。
診斷接聽程式允許接聽目前 .NET 處理序中發生的任何 EF Core 事件。 類別 DiagnosticListener 是 .NET 中通用機制的一 部分,可從執行中的應用程式取得診斷資訊。
診斷接聽程式不適合從單一 DbCoNtext 執行個體取得事件。 EF Core 攔截器 會使用個別內容註冊來提供相同事件的存取權。
診斷接聽程式並非針對記錄而設計。 請考慮使用 簡單的記錄 或 Microsoft.Extensions.Logging 進行記錄。
範例:觀察診斷事件
解析 EF Core 事件是兩個步驟的程式。 首先, 必須建立本身的 DiagnosticListener
觀察者 :
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());
}
}
}
方法 OnNext
會尋找來自 EF Core 的 DiagnosticListener。 此接聽程式的名稱為 「Microsoft.EntityFrameworkCore」,可從 類別取得 DbLoggerCategory ,如下所示。
然後,此觀察者必須全域註冊,例如,在應用程式的 Main
方法中:
DiagnosticListener.AllListeners.Subscribe(new DiagnosticObserver());
其次,一旦找到 EF Core DiagnosticListener,就會建立新的索引鍵/值觀察者來訂閱實際的 EF Core 事件。 例如:
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} ");
}
}
}
這個 OnNext
方法這次會針對每個 EF Core 事件使用索引鍵/值組來呼叫。 索引鍵是事件的名稱,可從下列其中一個取得:
- CoreEventId 適用于所有 EF Core 資料庫提供者通用的事件
- RelationalEventId 適用于所有關系資料庫提供者通用的事件
- 與目前資料庫提供者特定的事件類似的類別。 例如, SqlServerEventId 針對 SQL Server 提供者。
索引鍵/值組的值是事件特有的承載類型。 預期承載的類型記載于這些事件類別中定義的每個事件上。
例如,上述程式碼會處理 ContextInitialized 和 ConnectionOpening 事件。 對於其中第一個,承載為 ContextInitializedEventData 。 第二個是 ConnectionEventData 。
提示
ToString 會在每個 EF Core 事件資料類別中覆寫,以產生事件的對等記錄訊息。 例如,呼叫 ContextInitializedEventData.ToString
會產生 「Entity Framework Core 5.0.0 使用提供者 'Microsoft.EntityFrameworkCore.Sqlite' 來初始化 'BlogsCoNtext',且選項為:None」。
此 範例 包含簡單的主控台應用程式,對部落格資料庫進行變更,並列印出所遇到的診斷事件。
public static async Task Main()
{
DiagnosticListener.AllListeners.Subscribe(new DiagnosticObserver());
using (var context = new BlogsContext())
{
await context.Database.EnsureDeletedAsync();
await context.Database.EnsureCreatedAsync();
context.Add(
new Blog { Name = "EF Blog", Posts = { new Post { Title = "EF Core 3.1!" }, new Post { Title = "EF Core 5.0!" } } });
await context.SaveChangesAsync();
}
using (var context = new BlogsContext())
{
var blog = await context.Blogs.Include(e => e.Posts).SingleAsync();
blog.Name = "EF Core Blog";
context.Remove(blog.Posts.First());
blog.Posts.Add(new Post { Title = "EF Core 6.0!" });
await context.SaveChangesAsync();
}
此程式碼的輸出會顯示偵測到的事件:
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