Catatan
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba masuk atau mengubah direktori.
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba mengubah direktori.
Petunjuk / Saran
Konten ini adalah kutipan dari eBook, .NET Microservices Architecture for Containerized .NET Applications, tersedia di .NET Docs atau sebagai PDF yang dapat diunduh gratis dan dapat dibaca secara offline.
Untuk Azure SQL Database, Entity Kerangka Kerja (EF) Core sudah menyediakan ketahanan sambungan database internal dan logika coba lagi. Tetapi Anda perlu mengaktifkan strategi eksekusi Kerangka Kerja Entitas untuk setiap DbContext sambungan jika Anda ingin memiliki sambungan Inti EF yang tangguh.
Misalnya, kode berikut di tingkat sambungan Inti EF memungkinkan sambungan SQL tangguh yang dicoba kembali jika sambungan gagal.
// Program.cs from any ASP.NET Core Web API
// Other code ...
builder.Services.AddDbContext<CatalogContext>(options =>
{
options.UseSqlServer(
builder.Configuration["ConnectionString"],
sqlServerOptionsAction: sqlOptions =>
{
sqlOptions.EnableRetryOnFailure(
maxRetryCount: 10,
maxRetryDelay: TimeSpan.FromSeconds(30),
errorNumbersToAdd: null);
});
});
Penting
Microsoft menyarankan agar Anda menggunakan alur autentikasi paling aman yang tersedia. Jika Anda menyambungkan ke Azure SQL, Identitas Terkelola untuk sumber daya Azure adalah metode autentikasi yang direkomendasikan.
Strategi eksekusi dan transaksi eksplisit menggunakan BeginTransaction dan beberapa DbContexts
Ketika percobaan ulang diaktifkan dalam sambungan Inti EF, setiap operasi yang Anda lakukan menggunakan Inti EF menjadi operasi yang dapat diulang sendiri. Setiap kueri dan setiap panggilan ke SaveChanges akan dicoba kembali sebagai unit jika terjadi kegagalan sementara.
Tetapi, jika kode Anda memulai transaksi menggunakan BeginTransaction, Anda menentukan grup operasi Anda sendiri yang perlu ditangani sebagai unit. Segala sesuatu di dalam transaksi harus digulung balik jika terjadi kegagalan.
Jika Anda mencoba menjalankan transaksi tersebut saat menggunakan strategi eksekusi EF (kebijakan coba lagi) dan Anda memanggil SaveChanges dari beberapa DbContexts, Anda akan mendapatkan pengecualian seperti ini:
System.InvalidOperationException: Strategi eksekusi yang dikonfigurasi 'SqlServerRetryingExecutionStrategy' tidak mendukung transaksi yang dimulai pengguna. Gunakan strategi eksekusi yang dikembalikan oleh 'DbContext.Database.CreateExecutionStrategy()' untuk menjalankan semua operasi dalam transaksi sebagai unit yang dapat dicoba kembali.
Solusinya adalah memanggil strategi eksekusi EF secara manual dengan delegasi yang mewakili semua yang perlu dijalankan. Jika terjadi kegagalan sementara, strategi eksekusi akan memanggil delegasi lagi. Misalnya, kode berikut menunjukkan bagaimana penerapannya di eShopOnContainers dengan dua beberapa DbContexts (_catalogContext dan IntegrationEventLogContext) saat memperbarui produk lalu menyimpan objek ProductPriceChangedIntegrationEvent, yang perlu menggunakan DbContext berbeda.
public async Task<IActionResult> UpdateProduct(
[FromBody]CatalogItem productToUpdate)
{
// Other code ...
var oldPrice = catalogItem.Price;
var raiseProductPriceChangedEvent = oldPrice != productToUpdate.Price;
// Update current product
catalogItem = productToUpdate;
// Save product's data and publish integration event through the Event Bus
// if price has changed
if (raiseProductPriceChangedEvent)
{
//Create Integration Event to be published through the Event Bus
var priceChangedEvent = new ProductPriceChangedIntegrationEvent(
catalogItem.Id, productToUpdate.Price, oldPrice);
// Achieving atomicity between original Catalog database operation and the
// IntegrationEventLog thanks to a local transaction
await _catalogIntegrationEventService.SaveEventAndCatalogContextChangesAsync(
priceChangedEvent);
// Publish through the Event Bus and mark the saved event as published
await _catalogIntegrationEventService.PublishThroughEventBusAsync(
priceChangedEvent);
}
// Just save the updated product because the Product's Price hasn't changed.
else
{
await _catalogContext.SaveChangesAsync();
}
}
DbContext pertama adalah _catalogContext dan DbContext kedua berada dalam objek _catalogIntegrationEventService. Tindakan Penerapan dilakukan di semua objek DbContext menggunakan strategi eksekusi EF.
Untuk mencapai beberapa penerapan DbContext ini, SaveEventAndCatalogContextChangesAsync menggunakan kelas ResilientTransaction, seperti yang ditunjukkan dalam kode berikut:
public class CatalogIntegrationEventService : ICatalogIntegrationEventService
{
//…
public async Task SaveEventAndCatalogContextChangesAsync(
IntegrationEvent evt)
{
// Use of an EF Core resiliency strategy when using multiple DbContexts
// within an explicit BeginTransaction():
// https://learn.microsoft.com/ef/core/miscellaneous/connection-resiliency
await ResilientTransaction.New(_catalogContext).ExecuteAsync(async () =>
{
// Achieving atomicity between original catalog database
// operation and the IntegrationEventLog thanks to a local transaction
await _catalogContext.SaveChangesAsync();
await _eventLogService.SaveEventAsync(evt,
_catalogContext.Database.CurrentTransaction.GetDbTransaction());
});
}
}
Metode ResilientTransaction.ExecuteAsync ini pada dasarnya memulai transaksi dari yang diteruskan DbContext (_catalogContext) lalu menjadikan EventLogService menggunakan transaksi tersebut untuk menyimpan perubahan dari IntegrationEventLogContext dan kemudian melakukan seluruh transaksi.
public class ResilientTransaction
{
private DbContext _context;
private ResilientTransaction(DbContext context) =>
_context = context ?? throw new ArgumentNullException(nameof(context));
public static ResilientTransaction New (DbContext context) =>
new ResilientTransaction(context);
public async Task ExecuteAsync(Func<Task> action)
{
// Use of an EF Core resiliency strategy when using multiple DbContexts
// within an explicit BeginTransaction():
// https://learn.microsoft.com/ef/core/miscellaneous/connection-resiliency
var strategy = _context.Database.CreateExecutionStrategy();
await strategy.ExecuteAsync(async () =>
{
await using var transaction = await _context.Database.BeginTransactionAsync();
await action();
await transaction.CommitAsync();
});
}
}
Sumber Daya Tambahan:
Ketahanan Sambungan dan Intersepsi Perintah dengan EF dalam Aplikasi MVC ASP.NET
https://learn.microsoft.com/aspnet/mvc/overview/getting-started/getting-started-with-ef-using-mvc/connection-resiliency-and-command-interception-with-the-entity-framework-in-an-asp-net-mvc-applicationCesar de la Torre. Menggunakan Sambungan dan Transaksi SQL Inti Kerangka Kerja Entitas Tangguh
https://devblogs.microsoft.com/cesardelatorre/using-resilient-entity-framework-core-sql-connections-and-transactions-retries-with-exponential-backoff/