diff --git a/src/Managing.Api/Controllers/DataController.cs b/src/Managing.Api/Controllers/DataController.cs index a8911dfa..de27f9cb 100644 --- a/src/Managing.Api/Controllers/DataController.cs +++ b/src/Managing.Api/Controllers/DataController.cs @@ -3,6 +3,7 @@ using Managing.Api.Models.Responses; using Managing.Application.Abstractions.Grains; using Managing.Application.Abstractions.Services; using Managing.Application.ManageBot.Commands; +using Managing.Core; using Managing.Domain.Backtests; using Managing.Domain.Bots; using Managing.Domain.Candles; @@ -35,6 +36,7 @@ public class DataController : ControllerBase private readonly IMediator _mediator; private readonly ITradingService _tradingService; private readonly IGrainFactory _grainFactory; + private readonly IServiceScopeFactory _serviceScopeFactory; /// /// Initializes a new instance of the class. @@ -48,6 +50,7 @@ public class DataController : ControllerBase /// Mediator for handling commands and queries. /// Service for trading operations. /// Orleans grain factory for accessing grains. + /// Service scope factory for creating scoped services. public DataController( IExchangeService exchangeService, IAccountService accountService, @@ -56,7 +59,8 @@ public class DataController : ControllerBase IAgentService agentService, IMediator mediator, ITradingService tradingService, - IGrainFactory grainFactory) + IGrainFactory grainFactory, + IServiceScopeFactory serviceScopeFactory) { _exchangeService = exchangeService; _accountService = accountService; @@ -66,6 +70,7 @@ public class DataController : ControllerBase _mediator = mediator; _tradingService = tradingService; _grainFactory = grainFactory; + _serviceScopeFactory = serviceScopeFactory; } /// @@ -405,9 +410,12 @@ public class DataController : ControllerBase var endDate = DateTime.UtcNow; var agentBalanceHistory = await _agentService.GetAgentBalances(agentName, startDate, endDate); - // Convert to detailed view model with additional information + // Convert to detailed view model with additional information using separate scopes to avoid DbContext concurrency var result = await Task.WhenAll( - userStrategies.Select(strategy => MapStrategyToViewModelAsync(strategy, agentBalanceHistory)) + userStrategies.Select(strategy => + ServiceScopeHelpers.WithScopedService( + _serviceScopeFactory, + async tradingService => await MapStrategyToViewModelAsync(strategy, agentBalanceHistory, tradingService))) ); return Ok(result); @@ -446,7 +454,7 @@ public class DataController : ControllerBase var agentBalanceHistory = await _agentService.GetAgentBalances(agentName, startDate, endDate); // Map the strategy to a view model using the shared method - var result = await MapStrategyToViewModelAsync(strategy, agentBalanceHistory); + var result = await MapStrategyToViewModelAsync(strategy, agentBalanceHistory, _tradingService); return Ok(result); } @@ -456,9 +464,10 @@ public class DataController : ControllerBase /// /// The trading bot to map /// Agent balance history data + /// Trading service for fetching positions /// A view model with detailed strategy information private async Task MapStrategyToViewModelAsync(Bot strategy, - AgentBalanceHistory agentBalanceHistory) + AgentBalanceHistory agentBalanceHistory, ITradingService tradingService) { // Calculate volume statistics decimal totalVolume = strategy.Volume; @@ -469,8 +478,8 @@ public class DataController : ControllerBase int winRate = wins + losses > 0 ? (wins * 100) / (wins + losses) : 0; - // Fetch positions associated with this bot - var positions = await _tradingService.GetPositionsByInitiatorIdentifierAsync(strategy.Identifier); + // Fetch positions associated with this bot using the provided trading service + var positions = await tradingService.GetPositionsByInitiatorIdentifierAsync(strategy.Identifier); // Convert agent balance history to wallet balances dictionary var walletBalances = agentBalanceHistory?.AgentBalances?