روشهای مختلف انجام چند کار به صورت همزمان در C# .NET - قسمت دوم
نویسنده: یاسر مرادی
تاریخ: ۱۳۹۸/۰۸/۱۰ ۱۹:۱۵
آدرس: www.dntips.ir
| مطالب | ۳۶۹۴ |
| نویسندگان | ۲۷۶ |
| گروههای مطالب | ۱۰۲۴ |
| نقشههای راه | ۱۱۹ |
| دورهها | ۱۴ |
| اشتراکها | ۱۷۹۱۴ |
public async Task DoSomethingWithCustomer(Customer customer)
{
using var dbContext = new AppDbContext();
// ...
} services.AddDbContextPool<AppDbContext>(); public async Task DoSomethingWithCustomer(Customer customer)
{
using var scope = _serviceProvider.CreateScope();
var dbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
var httpClient = scope.ServiceProvider.GetRequiredService<IHttpClientFactory>().CreateClient();
// ...
} public interface IOrderHistoryService
{
Task BuildCustomerHistory();
}
public class OrderHistoryService : IOrderHistoryService
{
private AppDbContext _dbContext;
public OrderHistoryService(AppDbContext dbContext)
{
_dbContext = dbContext;
}
public async Task BuildCustomerHistory()
{
// ...
}
} var orders = await GetRecentOrdersAsync(userId); var logs = await GetSystemLogsAsync(); var stats = await GetUserStatsAsync(userId); return new DashboardDto(orders, logs, stats);
"A second operation started on this context before a previous operation completed. This is usually caused by different threads using the same instance of DbContext, however instance members are not guaranteed to be thread-safe."
using var context = new AppDbContext(options);)، اما استفاده از کارخانه برای وابستگیتزریق (Dependency Injection) تمیزتر است.builder.Services.AddDbContextFactory<AppDbContext>(options =>
{
options.UseNpgsql(builder.Configuration.GetConnectionString("db"));
});using Microsoft.EntityFrameworkCore;
public class DashboardService(IDbContextFactory<AppDbContext> contextFactory)
{
public async Task<DashboardDto> GetDashboardAsync(int userId)
{
// ۱. شروع taskها (پرسوجوها بلافاصله شروع به اجرا میکنند)
var ordersTask = GetOrdersAsync(userId);
var logsTask = GetSystemLogsAsync();
var statsTask = GetUserStatsAsync(userId);
// ۲. منتظر ماندن برای تکمیل همه
await Task.WhenAll(ordersTask, logsTask, statsTask);
// ۳. بازگشت نتایج
return new DashboardDto(
await ordersTask,
await logsTask,
await statsTask
);
}
private async Task<List<Order>> GetOrdersAsync(int userId)
{
await using var context = await contextFactory.CreateDbContextAsync();
return await context.Orders
.AsNoTracking() // برای پرسوجوهای فقطخواندنی، tracking را خاموش کنید تا عملکرد بهتر شود
.Where(o => o.UserId == userId)
.OrderByDescending(o => o.CreatedAt)
.ThenByDescending(o => o.Amount)
.Take(50)
.ToListAsync();
}
private async Task<List<SystemLog>> GetSystemLogsAsync()
{
await using var context = await contextFactory.CreateDbContextAsync();
return await context.SystemLogs
.AsNoTracking()
.OrderByDescending(l => l.Timestamp)
.Take(50)
.ToListAsync();
}
private async Task<UserStats?> GetUserStatsAsync(int userId)
{
await using var context = await contextFactory.CreateDbContextAsync();
return await context.Users
.Where(u => u.Id == userId)
.Select(u => new UserStats { OrderCount = u.Orders.Count })
.FirstOrDefaultAsync();
}
}await using استفاده کنید تا بعد از پرسوجو، اتصال به pool برگردد.