diff --git a/TransactionProcessor.BusinessLogic/Manager/TransactionProcessorManager.cs b/TransactionProcessor.BusinessLogic/Manager/TransactionProcessorManager.cs index eff9aeda..6b7851f4 100644 --- a/TransactionProcessor.BusinessLogic/Manager/TransactionProcessorManager.cs +++ b/TransactionProcessor.BusinessLogic/Manager/TransactionProcessorManager.cs @@ -49,71 +49,76 @@ public TransactionProcessorManager(ITransactionProcessorReadModelRepository tran public async Task>> GetContracts(Guid estateId, CancellationToken cancellationToken) { - Result> getContractsResult = await this.TransactionProcessorReadModelRepository.GetContracts(estateId, cancellationToken); + return await AsyncExecutor.ExecuteSafeAsync(async ct =>{ + Result> getContractsResult = await this.TransactionProcessorReadModelRepository.GetContracts(estateId, ct); - if (getContractsResult.IsFailed) - return ResultHelpers.CreateFailure(getContractsResult); + if (getContractsResult.IsFailed) + return ResultHelpers.CreateFailure(getContractsResult); - return Result.Success(getContractsResult.Data); + return Result.Success(getContractsResult.Data); + }, cancellationToken); } public async Task> GetContract(Guid estateId, Guid contractId, CancellationToken cancellationToken) { - Result getContractResult = await this.AggregateService.GetLatest(contractId, cancellationToken); - if (getContractResult.IsFailed) - return ResultHelpers.CreateFailure(getContractResult); + return await AsyncExecutor.ExecuteSafeAsync(async ct => { + Result getContractResult = await this.AggregateService.GetLatest(contractId, ct); + if (getContractResult.IsFailed) + return ResultHelpers.CreateFailure(getContractResult); - ContractAggregate contractAggregate = getContractResult.Data; + ContractAggregate contractAggregate = getContractResult.Data; - if (contractAggregate.IsCreated == false) - { - return Result.NotFound($"No contract found with Id [{estateId}]"); - } - Contract contractModel = contractAggregate.GetContract(); + if (contractAggregate.IsCreated == false) { + return Result.NotFound($"No contract found with Id [{estateId}]"); + } + + Contract contractModel = contractAggregate.GetContract(); - return Result.Success(contractModel); + return Result.Success(contractModel); + }, cancellationToken); } public async Task> GetEstate(Guid estateId, - CancellationToken cancellationToken){ - - Result getEstateResult = await this.AggregateService.GetLatest(estateId, cancellationToken); - if (getEstateResult.IsFailed) - return ResultHelpers.CreateFailure(getEstateResult); - - EstateAggregate estateAggregate = getEstateResult.Data; - if (estateAggregate.IsCreated == false){ - return Result.NotFound($"No estate found with Id [{estateId}]"); - } + CancellationToken cancellationToken) { - Models.Estate.Estate estateModel = estateAggregate.GetEstate(); + return await AsyncExecutor.ExecuteSafeAsync(async ct => { + Result getEstateResult = await this.AggregateService.GetLatest(estateId, ct); + if (getEstateResult.IsFailed) + return ResultHelpers.CreateFailure(getEstateResult); - if (estateModel.Operators != null) - { - foreach (Operator @operator in estateModel.Operators) - { - var getOperatorResult = await this.AggregateService.GetLatest(@operator.OperatorId, cancellationToken); - if (getOperatorResult.IsSuccess) { - OperatorAggregate operatorAggregate = getOperatorResult.Data; - @operator.Name = operatorAggregate.Name; + EstateAggregate estateAggregate = getEstateResult.Data; + if (estateAggregate.IsCreated == false) { + return Result.NotFound($"No estate found with Id [{estateId}]"); + } + + Models.Estate.Estate estateModel = estateAggregate.GetEstate(); + + if (estateModel.Operators != null) { + foreach (Operator @operator in estateModel.Operators) { + var getOperatorResult = await this.AggregateService.GetLatest(@operator.OperatorId, ct); + if (getOperatorResult.IsSuccess) { + OperatorAggregate operatorAggregate = getOperatorResult.Data; + @operator.Name = operatorAggregate.Name; + } } } - } - return Result.Success(estateModel); + return Result.Success(estateModel); + }, cancellationToken); } public async Task>> GetEstates(Guid estateId, CancellationToken cancellationToken){ - Result getEstateResult= await this.TransactionProcessorReadModelRepository.GetEstate(estateId, cancellationToken); - if (getEstateResult.IsFailed) - return Result.NotFound($"No estate found with Id [{estateId}]"); - - return Result.Success(new List(){ - getEstateResult.Data - }); + return await AsyncExecutor.ExecuteSafeAsync(async ct => { + Result getEstateResult = await this.TransactionProcessorReadModelRepository.GetEstate(estateId, ct); + if (getEstateResult.IsFailed) + return Result.NotFound($"No estate found with Id [{estateId}]"); + + return Result.Success(new List() { getEstateResult.Data }); + }, + cancellationToken); } public async Task> GetMerchant(Guid estateId, @@ -153,30 +158,33 @@ public async Task>> GetMerchantContracts(Guid estateId, Guid merchantId, CancellationToken cancellationToken) { - Result> getMerchantContractsResult = await this.TransactionProcessorReadModelRepository.GetMerchantContracts(estateId, merchantId, cancellationToken); - if (getMerchantContractsResult.IsFailed) - return ResultHelpers.CreateFailure(getMerchantContractsResult); + return await AsyncExecutor.ExecuteSafeAsync(async ct => { + Result> getMerchantContractsResult = await this.TransactionProcessorReadModelRepository.GetMerchantContracts(estateId, merchantId, ct); + if (getMerchantContractsResult.IsFailed) + return ResultHelpers.CreateFailure(getMerchantContractsResult); - List contractModels = getMerchantContractsResult.Data; - if (contractModels.Any() == false) - return Result.NotFound($"No contracts for Estate {estateId} and Merchant {merchantId}"); + List contractModels = getMerchantContractsResult.Data; + if (contractModels.Any() == false) + return Result.NotFound($"No contracts for Estate {estateId} and Merchant {merchantId}"); - return Result.Success(contractModels); + return Result.Success(contractModels); + }, cancellationToken); } public async Task>> GetMerchants(Guid estateId, CancellationToken cancellationToken) { - Result> getMerchantsResult = await this.TransactionProcessorReadModelRepository.GetMerchants(estateId, cancellationToken); - if (getMerchantsResult.IsFailed) - return ResultHelpers.CreateFailure(getMerchantsResult); - List merchants = getMerchantsResult.Data; - if (merchants == null || merchants.Any() == false) - { - return Result.NotFound($"No Merchants found for estate Id {estateId}"); - } + return await AsyncExecutor.ExecuteSafeAsync(async ct => { + Result> getMerchantsResult = await this.TransactionProcessorReadModelRepository.GetMerchants(estateId, ct); + if (getMerchantsResult.IsFailed) + return ResultHelpers.CreateFailure(getMerchantsResult); + List merchants = getMerchantsResult.Data; + if (merchants == null || merchants.Any() == false) { + return Result.NotFound($"No Merchants found for estate Id {estateId}"); + } - return Result.Success(merchants); + return Result.Success(merchants); + },cancellationToken); } public async Task>> GetTransactionFeesForProduct(Guid estateId, @@ -224,11 +232,13 @@ public async Task>> GetMerchants(Guid estateId, public async Task>> GetOperators(Guid estateId, CancellationToken cancellationToken) { - Result> getOperatorsResult = await this.TransactionProcessorReadModelRepository.GetOperators(estateId, cancellationToken); - if (getOperatorsResult.IsFailed) - return ResultHelpers.CreateFailure(getOperatorsResult); + return await AsyncExecutor.ExecuteSafeAsync(async ct => { + Result> getOperatorsResult = await this.TransactionProcessorReadModelRepository.GetOperators(estateId, ct); + if (getOperatorsResult.IsFailed) + return ResultHelpers.CreateFailure(getOperatorsResult); - return Result.Success(getOperatorsResult.Data); + return Result.Success(getOperatorsResult.Data); + }, cancellationToken); } public async Task> GetSettlement(Guid estateId, @@ -236,7 +246,8 @@ public async Task> GetSettlement(Guid estateId, Guid settlementId, CancellationToken cancellationToken) { - return await this.TransactionProcessorReadModelRepository.GetSettlement(estateId, merchantId, settlementId, cancellationToken); + return await AsyncExecutor.ExecuteSafeAsync(async ct => { return await this.TransactionProcessorReadModelRepository.GetSettlement(estateId, merchantId, settlementId, ct); }, + cancellationToken); } public async Task>> GetSettlements(Guid estateId, @@ -245,7 +256,12 @@ public async Task>> GetSettlements(Guid estateId, String endDate, CancellationToken cancellationToken) { - return await this.TransactionProcessorReadModelRepository.GetSettlements(estateId, merchantId, startDate, endDate, cancellationToken); + return await AsyncExecutor.ExecuteSafeAsync(async ct => { + Result> getSettlementsResult = await this.TransactionProcessorReadModelRepository.GetSettlements(estateId, merchantId, startDate, endDate, ct); + if (getSettlementsResult.IsFailed) return ResultHelpers.CreateFailure(getSettlementsResult); + + return Result.Success(getSettlementsResult.Data); + }, cancellationToken); } public async Task> GetPendingSettlement(Guid estateId, diff --git a/TransactionProcessor.Database/Contexts/EstateManagementGenericContext.cs b/TransactionProcessor.Database/Contexts/EstateManagementGenericContext.cs index 961e19b7..f18ee18d 100644 --- a/TransactionProcessor.Database/Contexts/EstateManagementGenericContext.cs +++ b/TransactionProcessor.Database/Contexts/EstateManagementGenericContext.cs @@ -402,22 +402,25 @@ public static class EstateManagementContextExtensions public static async Task> LoadEstate(this EstateManagementContext context, IDomainEvent domainEvent, CancellationToken cancellationToken) { Guid estateId = DomainEventHelper.GetEstateId(domainEvent); - Estate estate = await context.Estates.SingleOrDefaultAsync(e => e.EstateId == estateId, cancellationToken); - return estate switch + IQueryable query = context.Estates.Where(e => e.EstateId == estateId); + Result estateResult = await DbQueryHelpers.ExecuteQuerySafeSingleOrDefault(query, cancellationToken, $"Error getting estate with Id {estateId}"); + + return estateResult.Status switch { - null => Result.NotFound($"Estate not found with Id {estateId}"), - _ => Result.Success(estate) + ResultStatus.NotFound => Result.NotFound($"Estate not found with Id {estateId}"), + _ => estateResult }; } public static async Task> LoadOperator(this EstateManagementContext context, Guid operatorId, CancellationToken cancellationToken) { - Operator @operator = await context.Operators.SingleOrDefaultAsync(e => e.OperatorId == operatorId, cancellationToken); + IQueryable query = context.Operators.Where(e => e.OperatorId == operatorId); + Result operatorResult = await DbQueryHelpers.ExecuteQuerySafeSingleOrDefault(query, cancellationToken, $"Error getting operator with Id {operatorId}"); - return @operator switch + return operatorResult.Status switch { - null => Result.NotFound($"Operator not found with Id {operatorId}"), - _ => Result.Success(@operator) + ResultStatus.NotFound => Result.NotFound($"Operator not found with Id {operatorId}"), + _ => operatorResult }; } @@ -433,13 +436,14 @@ public static async Task> LoadOriginalMerchantDevice(this { Guid merchantId = DomainEventHelper.GetMerchantId(domainEvent); Guid deviceId = DomainEventHelper.GetOriginalDeviceId(domainEvent); - MerchantDevice device = await context.MerchantDevices.SingleOrDefaultAsync(d => d.DeviceId == deviceId && - d.MerchantId == merchantId, cancellationToken); + IQueryable query = context.MerchantDevices.Where(d => d.DeviceId == deviceId && + d.MerchantId == merchantId); + Result deviceResult = await DbQueryHelpers.ExecuteQuerySafeSingleOrDefault(query, cancellationToken, $"Error getting original device with Id {deviceId} for Merchant {merchantId}"); - return device switch + return deviceResult.Status switch { - null => Result.NotFound($"Original Device Id {deviceId} not found for Merchant {merchantId}"), - _ => Result.Success(device) + ResultStatus.NotFound => Result.NotFound($"Original Device Id {deviceId} not found for Merchant {merchantId}"), + _ => deviceResult }; } @@ -447,36 +451,40 @@ public static async Task> LoadMerchantDevice(this EstateM { Guid merchantId = DomainEventHelper.GetMerchantId(domainEvent); Guid deviceId = DomainEventHelper.GetDeviceId(domainEvent); - MerchantDevice device = await context.MerchantDevices.SingleOrDefaultAsync(d => d.DeviceId == deviceId && - d.MerchantId == merchantId, cancellationToken); + IQueryable query = context.MerchantDevices.Where(d => d.DeviceId == deviceId && + d.MerchantId == merchantId); + Result deviceResult = await DbQueryHelpers.ExecuteQuerySafeSingleOrDefault(query, cancellationToken, $"Error getting device with Id {deviceId} for Merchant {merchantId}"); - return device switch + return deviceResult.Status switch { - null => Result.NotFound($"Device Id {deviceId} not found for Merchant {merchantId}"), - _ => Result.Success(device) + ResultStatus.NotFound => Result.NotFound($"Device Id {deviceId} not found for Merchant {merchantId}"), + _ => deviceResult }; } public static async Task> LoadFile(this EstateManagementContext context, IDomainEvent domainEvent, CancellationToken cancellationToken) { Guid fileId = DomainEventHelper.GetFileId(domainEvent); - File file = await context.Files.SingleOrDefaultAsync(e => e.FileId == fileId, cancellationToken: cancellationToken); + IQueryable query = context.Files.Where(e => e.FileId == fileId); + Result fileResult = await DbQueryHelpers.ExecuteQuerySafeSingleOrDefault(query, cancellationToken, $"Error getting file with Id {fileId}"); - return file switch + return fileResult.Status switch { - null => Result.NotFound($"File not found with Id {fileId}"), - _ => Result.Success(file) + ResultStatus.NotFound => Result.NotFound($"File not found with Id {fileId}"), + _ => fileResult }; } public static async Task> LoadMerchant(this EstateManagementContext context, IDomainEvent domainEvent, CancellationToken cancellationToken) { Guid merchantId = DomainEventHelper.GetMerchantId(domainEvent); - Merchant merchant = await context.Merchants.SingleOrDefaultAsync(e => e.MerchantId == merchantId, cancellationToken: cancellationToken); - return merchant switch + + IQueryable query = context.Merchants.Where(e => e.MerchantId == merchantId); + Result merchantResult = await DbQueryHelpers.ExecuteQuerySafeSingleOrDefault(query, cancellationToken, $"Error getting merchant with Id {merchantId}"); + return merchantResult.Status switch { - null => Result.NotFound($"Merchant not found with Id {merchantId}"), - _ => Result.Success(merchant) + ResultStatus.NotFound => Result.NotFound($"Merchant not found with Id {merchantId}"), + _ => merchantResult }; } @@ -485,13 +493,12 @@ public static async Task> LoadMerchantAddress(this Estat Guid merchantId = DomainEventHelper.GetMerchantId(domainEvent); Guid addressId = DomainEventHelper.GetAddressId(domainEvent); - MerchantAddress merchantAddress = await context.MerchantAddresses.SingleOrDefaultAsync(e => e.MerchantId == merchantId && - e.AddressId == addressId, cancellationToken: cancellationToken); - - return merchantAddress switch + IQueryable query = context.MerchantAddresses.Where(e => e.MerchantId == merchantId && e.AddressId == addressId); + Result merchantAddressResult = await DbQueryHelpers.ExecuteQuerySafeSingleOrDefault(query, cancellationToken, $"Error getting merchant address with Id {addressId} for merchant {merchantId}"); + return merchantAddressResult.Status switch { - null => Result.NotFound($"Merchant Address {addressId} not found with merchant Id {merchantId}"), - _ => Result.Success(merchantAddress) + ResultStatus.NotFound => Result.NotFound($"Merchant Address {addressId} not found with merchant Id {merchantId}"), + _ => merchantAddressResult }; } @@ -500,60 +507,60 @@ public static async Task> LoadMerchantContact(this Estat Guid merchantId = DomainEventHelper.GetMerchantId(domainEvent); Guid contactId = DomainEventHelper.GetContactId(domainEvent); - MerchantContact merchantContact = await context.MerchantContacts.SingleOrDefaultAsync(e => e.MerchantId == merchantId && - e.ContactId == contactId, cancellationToken: cancellationToken); - return merchantContact switch + IQueryable query = context.MerchantContacts.Where(e => e.MerchantId == merchantId && e.ContactId == contactId); + Result merchantContactResult = await DbQueryHelpers.ExecuteQuerySafeSingleOrDefault(query, cancellationToken, $"Error getting merchant contact with Id {contactId} for merchant {merchantId}"); + return merchantContactResult.Status switch { - null => Result.NotFound($"Merchant Contact {contactId} not found with merchant Id {merchantId}"), - _ => Result.Success(merchantContact) + ResultStatus.NotFound => Result.NotFound($"Merchant Contact {contactId} not found with merchant Id {merchantId}"), + _ => merchantContactResult }; } public static async Task> LoadReconcilation(this EstateManagementContext context, IDomainEvent domainEvent, CancellationToken cancellationToken) { Guid transactionId = DomainEventHelper.GetTransactionId(domainEvent); - Reconciliation reconciliation = - await context.Reconciliations.SingleOrDefaultAsync(t => t.TransactionId == transactionId, cancellationToken: cancellationToken); - return reconciliation switch + IQueryable query = context.Reconciliations.Where(t => t.TransactionId == transactionId); + Result reconciliationResult = await DbQueryHelpers.ExecuteQuerySafeSingleOrDefault(query, cancellationToken, $"Error getting reconciliation with Id {transactionId}"); + return reconciliationResult.Status switch { - null => Result.NotFound($"Reconciliation not found with Id {transactionId}"), - _ => Result.Success(reconciliation) + ResultStatus.NotFound => Result.NotFound($"Reconciliation not found with Id {transactionId}"), + _ => reconciliationResult }; } public static async Task> LoadSettlement(this EstateManagementContext context, IDomainEvent domainEvent, CancellationToken cancellationToken) { Guid settlementId = DomainEventHelper.GetSettlementId(domainEvent); - Settlement settlement = await context.Settlements.SingleOrDefaultAsync(e => e.SettlementId == settlementId, cancellationToken: cancellationToken); - - return settlement switch + IQueryable query = context.Settlements.Where(e => e.SettlementId == settlementId); + Result settlementResult = await DbQueryHelpers.ExecuteQuerySafeSingleOrDefault(query, cancellationToken, $"Error getting settlement with Id {settlementId}"); + return settlementResult.Status switch { - null => Result.NotFound($"Settlement not found with Id {settlementId}"), - _ => Result.Success(settlement) + ResultStatus.NotFound => Result.NotFound($"Settlement not found with Id {settlementId}"), + _ => settlementResult }; } public static async Task> LoadStatementHeader(this EstateManagementContext context, IDomainEvent domainEvent, CancellationToken cancellationToken) { Guid statementHeaderId = DomainEventHelper.GetStatementHeaderId(domainEvent); - StatementHeader statementHeader = await context.StatementHeaders.SingleOrDefaultAsync(e => e.StatementId == statementHeaderId, cancellationToken: cancellationToken); - - return statementHeader switch + IQueryable query = context.StatementHeaders.Where(e => e.StatementId == statementHeaderId); + Result statementHeaderResult = await DbQueryHelpers.ExecuteQuerySafeSingleOrDefault(query, cancellationToken, $"Error getting statement header with Id {statementHeaderId}"); + return statementHeaderResult.Status switch { - null => Result.NotFound($"Statement Header not found with Id {statementHeaderId}"), - _ => Result.Success(statementHeader) + ResultStatus.NotFound => Result.NotFound($"Statement Header not found with Id {statementHeaderId}"), + _ => statementHeaderResult }; } public static async Task> LoadTransaction(this EstateManagementContext context, IDomainEvent domainEvent, CancellationToken cancellationToken) { Guid transactionId = DomainEventHelper.GetTransactionId(domainEvent); - Transaction transaction = await context.Transactions.SingleOrDefaultAsync(e => e.TransactionId == transactionId, cancellationToken: cancellationToken); - - return transaction switch + IQueryable query = context.Transactions.Where(e => e.TransactionId == transactionId); + Result transactionResult = await DbQueryHelpers.ExecuteQuerySafeSingleOrDefault(query, cancellationToken, $"Error getting transaction with Id {transactionId}"); + return transactionResult.Status switch { - null => Result.NotFound($"Transaction not found with Id {transactionId}"), - _ => Result.Success(transaction) + ResultStatus.NotFound => Result.NotFound($"Transaction not found with Id {transactionId}"), + _ => transactionResult }; } @@ -572,24 +579,24 @@ public static async Task> LoadTransaction(this EstateManagem public static async Task> LoadContract(this EstateManagementContext context, IDomainEvent domainEvent, CancellationToken cancellationToken) { Guid contractId = DomainEventHelper.GetContractId(domainEvent); - Entities.Contract contract = await context.Contracts.SingleOrDefaultAsync(e => e.ContractId == contractId, cancellationToken: cancellationToken); - - return contract switch + IQueryable query = context.Contracts.Where(e => e.ContractId == contractId); + Result contractResult = await DbQueryHelpers.ExecuteQuerySafeSingleOrDefault(query, cancellationToken, $"Error getting contract with Id {contractId}"); + return contractResult.Status switch { - null => Result.NotFound($"Contract not found with Id {contractId}"), - _ => Result.Success(contract) + ResultStatus.NotFound => Result.NotFound($"Contract not found with Id {contractId}"), + _ => contractResult }; } public static async Task> LoadContractProductTransactionFee(this EstateManagementContext context, IDomainEvent domainEvent, CancellationToken cancellationToken) { Guid contractProductTransactionFeeId = DomainEventHelper.GetContractProductTransactionFeeId(domainEvent); - ContractProductTransactionFee contractProductTransactionFee = await context.ContractProductTransactionFees.SingleOrDefaultAsync(e => e.ContractProductTransactionFeeId == contractProductTransactionFeeId, cancellationToken: cancellationToken); - - return contractProductTransactionFee switch + IQueryable query = context.ContractProductTransactionFees.Where(e => e.ContractProductTransactionFeeId == contractProductTransactionFeeId); + Result contractProductTransactionFeeResult = await DbQueryHelpers.ExecuteQuerySafeSingleOrDefault(query, cancellationToken, $"Error getting contract product transaction fee with Id {contractProductTransactionFeeId}"); + return contractProductTransactionFeeResult.Status switch { - null => Result.NotFound($"Contract Product Transaction Fee not found with Id {contractProductTransactionFeeId}"), - _ => Result.Success(contractProductTransactionFee) + ResultStatus.NotFound => Result.NotFound($"Contract Product Transaction Fee not found with Id {contractProductTransactionFeeId}"), + _ => contractProductTransactionFeeResult }; } } diff --git a/TransactionProcessor.Database/Contexts/Extensions.cs b/TransactionProcessor.Database/Contexts/Extensions.cs index 006d5000..dacec6c0 100644 --- a/TransactionProcessor.Database/Contexts/Extensions.cs +++ b/TransactionProcessor.Database/Contexts/Extensions.cs @@ -1,5 +1,7 @@ -using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.DynamicLinq; +using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; +using SimpleResults; using TransactionProcessor.Database.Entities; using TransactionProcessor.Database.Entities.Summary; using TransactionProcessor.Database.ViewEntities; @@ -483,4 +485,58 @@ public static ModelBuilder SetupFloatActivity(this ModelBuilder modelBuilder) } #endregion +} + +public static class DbQueryHelpers { + public static async Task> ExecuteQuerySafeSum(IQueryable query, + CancellationToken cancellationToken, + string contextMessage = null) + { + try + { + T item = await query.SumAsync(cancellationToken); + return Result.Success(item); + } + catch (Exception ex) + { + string msg = contextMessage == null ? $"Error executing query: {ex.Message}" : $"{contextMessage}: {ex.Message}"; + return Result.Failure(msg); + } + } + + public static async Task>> ExecuteQuerySafeToList(IQueryable query, + CancellationToken cancellationToken, + string contextMessage = null) + { + try + { + List items = await query.ToListAsync(cancellationToken); + return Result.Success(items); + } + catch (Exception ex) + { + string msg = contextMessage == null ? $"Error executing query: {ex.Message}" : $"{contextMessage}: {ex.Message}"; + return Result.Failure(msg); + } + } + + public static async Task> ExecuteQuerySafeSingleOrDefault(IQueryable query, + CancellationToken cancellationToken, + string contextMessage = null) + { + try + { + T item = await query.SingleOrDefaultAsync(cancellationToken); + + if (item == null) + return Result.NotFound(); + + return Result.Success(item); + } + catch (Exception ex) + { + string msg = contextMessage == null ? $"Error executing query: {ex.Message}" : $"{contextMessage}: {ex.Message}"; + return Result.Failure(msg); + } + } } \ No newline at end of file diff --git a/TransactionProcessor.Database/TransactionProcessor.Database.csproj b/TransactionProcessor.Database/TransactionProcessor.Database.csproj index 6e10b42f..3cd76ede 100644 --- a/TransactionProcessor.Database/TransactionProcessor.Database.csproj +++ b/TransactionProcessor.Database/TransactionProcessor.Database.csproj @@ -23,6 +23,7 @@ + diff --git a/TransactionProcessor.Repository/ITransactionProcessorReadModelRepository.cs b/TransactionProcessor.Repository/ITransactionProcessorReadModelRepository.cs index 697e7acc..34265cf3 100644 --- a/TransactionProcessor.Repository/ITransactionProcessorReadModelRepository.cs +++ b/TransactionProcessor.Repository/ITransactionProcessorReadModelRepository.cs @@ -2188,3 +2188,33 @@ public async Task RemoveOperatorFromEstate(EstateDomainEvents.OperatorRe } } } + + +public static class AsyncExecutor +{ + public static async Task> ExecuteSafeAsync(Func>> func, CancellationToken cancellationToken) + { + try + { + return await func(cancellationToken); + } + catch (Exception ex) + { + Logger.LogError(new Exception("Error executing async operation", ex)); + return Result.Failure(ex.Message); + } + } + + public static async Task ExecuteSafeAsync(Func> func, CancellationToken cancellationToken) + { + try + { + return await func(cancellationToken); + } + catch (Exception ex) + { + Logger.LogError(new Exception("Error executing async operation", ex)); + return Result.Failure(ex.Message); + } + } +} \ No newline at end of file