From 05c5579b8154a4d56c475e4c0c1907965de06a1c Mon Sep 17 00:00:00 2001 From: Stuart Ferguson Date: Wed, 13 May 2026 17:22:48 +0100 Subject: [PATCH 01/11] Refactor to use Shared.Serialisation, remove Newtonsoft.Json Replaced Newtonsoft.Json with Shared.Serialisation and SystemTextJsonSerializer across all projects. Updated service classes and tests to use injected serialization delegates. Upgraded multiple NuGet dependencies. Refactored DockerHelper and integration tests for new serialization and string-based role IDs. Removed obsolete code and unnecessary usings. Dropped Microsoft.AspNetCore.Http.Abstractions from MAUI project to resolve Android issues. --- TestCategoryLister/TestCategoryLister.csproj | 2 +- .../TransactionRequestHandlerTests.cs | 2 + .../AuthenticationServiceTests.cs | 2 +- .../ConfigurationServiceTests.cs | 22 +++- .../ServicesTests/MerchantServiceTests.cs | 23 ++-- .../ServicesTests/TransactionServiceTests.cs | 44 ++++---- .../ServicesTests/UpdateServiceTests.cs | 19 +++- ...rocessor.Mobile.BusinessLogic.Tests.csproj | 13 ++- .../TransactionRequestHandler.cs | 6 +- .../Services/AuthenticationService.cs | 10 +- .../Services/ConfigurationService.cs | 70 ++++++------ .../Services/MerchantService.cs | 102 +++++++++--------- .../Services/TransactionService.cs | 45 ++------ .../Services/UpdateService.cs | 25 ++--- ...ctionProcessor.Mobile.BusinessLogic.csproj | 11 +- .../Common/DockerHelper.cs | 28 +++-- .../Steps/SharedSteps.cs | 32 +++--- ...TransactionProcessor.Mobile.UITests.csproj | 12 +-- .../TransactionProcessor.Mobile.csproj | 4 +- 19 files changed, 253 insertions(+), 219 deletions(-) diff --git a/TestCategoryLister/TestCategoryLister.csproj b/TestCategoryLister/TestCategoryLister.csproj index 5b62cc77a..a5958a544 100644 --- a/TestCategoryLister/TestCategoryLister.csproj +++ b/TestCategoryLister/TestCategoryLister.csproj @@ -4,6 +4,6 @@ net10.0 - + \ No newline at end of file diff --git a/TransactionProcessor.Mobile.BusinessLogic.Tests/RequestHandlerTests/TransactionRequestHandlerTests.cs b/TransactionProcessor.Mobile.BusinessLogic.Tests/RequestHandlerTests/TransactionRequestHandlerTests.cs index 457fa7e57..647dc6344 100644 --- a/TransactionProcessor.Mobile.BusinessLogic.Tests/RequestHandlerTests/TransactionRequestHandlerTests.cs +++ b/TransactionProcessor.Mobile.BusinessLogic.Tests/RequestHandlerTests/TransactionRequestHandlerTests.cs @@ -1,4 +1,5 @@ using Moq; +using Shared.Serialisation; using Shouldly; using SimpleResults; using TransactionProcessor.Mobile.BusinessLogic.Database; @@ -43,6 +44,7 @@ public TransactionRequestHandlerTests() { this.ApplicationCache.Object, this.ApplicationInfoService.Object, this.DeviceService.Object); + StringSerialiser.Initialise((IStringSerialiser)new SystemTextJsonSerializer(SystemTextJsonSerializer.GetDefaultJsonSerializerOptions())); } diff --git a/TransactionProcessor.Mobile.BusinessLogic.Tests/ServicesTests/AuthenticationServiceTests.cs b/TransactionProcessor.Mobile.BusinessLogic.Tests/ServicesTests/AuthenticationServiceTests.cs index 8ca77742b..583e329a5 100644 --- a/TransactionProcessor.Mobile.BusinessLogic.Tests/ServicesTests/AuthenticationServiceTests.cs +++ b/TransactionProcessor.Mobile.BusinessLogic.Tests/ServicesTests/AuthenticationServiceTests.cs @@ -1,6 +1,6 @@ using Moq; using SecurityService.Client; -using SecurityService.DataTransferObjects.Responses; +using SecurityService.DataTransferObjects; using Shouldly; using SimpleResults; using TransactionProcessor.Mobile.BusinessLogic.Logging; diff --git a/TransactionProcessor.Mobile.BusinessLogic.Tests/ServicesTests/ConfigurationServiceTests.cs b/TransactionProcessor.Mobile.BusinessLogic.Tests/ServicesTests/ConfigurationServiceTests.cs index 7d645558f..0052704da 100644 --- a/TransactionProcessor.Mobile.BusinessLogic.Tests/ServicesTests/ConfigurationServiceTests.cs +++ b/TransactionProcessor.Mobile.BusinessLogic.Tests/ServicesTests/ConfigurationServiceTests.cs @@ -1,7 +1,7 @@ -using System.Net; -using Newtonsoft.Json; -using RichardSzalay.MockHttp; +using RichardSzalay.MockHttp; +using Shared.Serialisation; using Shouldly; +using System.Net; using TransactionProcessor.Mobile.BusinessLogic.Logging; using TransactionProcessor.Mobile.BusinessLogic.Models; using TransactionProcessor.Mobile.BusinessLogic.Services; @@ -15,10 +15,22 @@ public class ConfigurationServiceTests{ private Func BaseAddressResolver; private IConfigurationService ConfigurationService; + + String Serialise(Object arg) + { + return StringSerialiser.Serialise(arg, new SerialiserOptions(SerialiserPropertyFormat.SnakeCase)); + } + + Object Deserialise(String arg, Type type) + { + return StringSerialiser.DeserializeObject(arg, type, new SerialiserOptions(SerialiserPropertyFormat.SnakeCase)); + } + public ConfigurationServiceTests(){ this.MockHttpMessageHandler = new MockHttpMessageHandler(); this.BaseAddressResolver = (s) => $"http://localhost"; - this.ConfigurationService = new ConfigurationService(this.BaseAddressResolver, this.MockHttpMessageHandler.ToHttpClient()); + this.ConfigurationService = new ConfigurationService(this.BaseAddressResolver, this.MockHttpMessageHandler.ToHttpClient(), Serialise, Deserialise); + StringSerialiser.Initialise((IStringSerialiser)new SystemTextJsonSerializer(SystemTextJsonSerializer.GetDefaultJsonSerializerOptions())); } [Theory] @@ -57,7 +69,7 @@ public async Task ConfigurationService_GetConfiguration_ResultSuccess_And_Config Logger.Initialise(new NullLogger()); this.MockHttpMessageHandler.When($"http://localhost/api/transactionmobileconfiguration/{TestData.DeviceIdentifier}") - .Respond("application/json", JsonConvert.SerializeObject(expectedConfiguration)); // Respond with JSON + .Respond("application/json", StringSerialiser.Serialise(expectedConfiguration)); // Respond with JSON var configurationResult = await this.ConfigurationService.GetConfiguration(TestData.DeviceIdentifier, CancellationToken.None); configurationResult.IsSuccess.ShouldBeTrue(); diff --git a/TransactionProcessor.Mobile.BusinessLogic.Tests/ServicesTests/MerchantServiceTests.cs b/TransactionProcessor.Mobile.BusinessLogic.Tests/ServicesTests/MerchantServiceTests.cs index 0b0bc9fbd..e01098faf 100644 --- a/TransactionProcessor.Mobile.BusinessLogic.Tests/ServicesTests/MerchantServiceTests.cs +++ b/TransactionProcessor.Mobile.BusinessLogic.Tests/ServicesTests/MerchantServiceTests.cs @@ -1,9 +1,9 @@ -using System.Net; -using Moq; -using Newtonsoft.Json; +using Moq; using RichardSzalay.MockHttp; +using Shared.Serialisation; using Shouldly; using SimpleResults; +using System.Net; using TransactionProcessor.Mobile.BusinessLogic.Logging; using TransactionProcessor.Mobile.BusinessLogic.Models; using TransactionProcessor.Mobile.BusinessLogic.Services; @@ -23,6 +23,16 @@ public class MerchantServiceTests{ private readonly IMerchantService MerchantService; + String Serialise(Object arg) + { + return StringSerialiser.Serialise(arg, new SerialiserOptions(SerialiserPropertyFormat.SnakeCase)); + } + + Object Deserialise(String arg, Type type) + { + return StringSerialiser.DeserializeObject(arg, type, new SerialiserOptions(SerialiserPropertyFormat.SnakeCase)); + } + public MerchantServiceTests(){ Logger.Initialise(new NullLogger()); this.MockHttpMessageHandler = new MockHttpMessageHandler(); @@ -31,10 +41,11 @@ public MerchantServiceTests(){ this.ApplicationInfoService = new Mock(); this.ApplicationInfoService.Setup(a => a.VersionString).Returns("1.0.0"); this.MerchantService = new MerchantService(this.BaseAddressResolver, this.MockHttpMessageHandler.ToHttpClient(),this.ApplicationCache.Object, - this.ApplicationInfoService.Object); + this.ApplicationInfoService.Object, Serialise, Deserialise); // Standard cache mocking here this.ApplicationCache.Setup(a => a.GetAccessToken()).Returns(TestData.AccessToken); + StringSerialiser.Initialise((IStringSerialiser)new SystemTextJsonSerializer(SystemTextJsonSerializer.GetDefaultJsonSerializerOptions())); } [Fact] @@ -65,7 +76,7 @@ public async Task MerchantService_GetContractProducts_ContractProductsAreReturne this.MockHttpMessageHandler.When($"http://localhost/api/merchants/contracts?application_version=1.0.0") - .Respond("application/json", JsonConvert.SerializeObject(contracts)); // Respond with JSON + .Respond("application/json", StringSerialiser.Serialise(contracts)); // Respond with JSON var result = await this.MerchantService.GetContractProducts(CancellationToken.None); result.IsSuccess.ShouldBeTrue(); @@ -112,7 +123,7 @@ public async Task MerchantService_GetMerchantDetails_MerchantDetailsReturned(){ }; this.MockHttpMessageHandler.When($"http://localhost/api/merchants?application_version=1.0.0") - .Respond("application/json", JsonConvert.SerializeObject(merchantResponse)); // Respond with JSON + .Respond("application/json", StringSerialiser.Serialise(merchantResponse)); // Respond with JSON Result merchantDetails = await this.MerchantService.GetMerchantDetails(CancellationToken.None); merchantDetails.IsSuccess.ShouldBeTrue(); diff --git a/TransactionProcessor.Mobile.BusinessLogic.Tests/ServicesTests/TransactionServiceTests.cs b/TransactionProcessor.Mobile.BusinessLogic.Tests/ServicesTests/TransactionServiceTests.cs index 5839d0189..be71d1b3f 100644 --- a/TransactionProcessor.Mobile.BusinessLogic.Tests/ServicesTests/TransactionServiceTests.cs +++ b/TransactionProcessor.Mobile.BusinessLogic.Tests/ServicesTests/TransactionServiceTests.cs @@ -1,11 +1,10 @@ -using System.Net; -using System.Text; using Moq; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; using RichardSzalay.MockHttp; +using Shared.Serialisation; using Shouldly; using SimpleResults; +using System.Net; +using System.Text; using TransactionProcessor.Mobile.BusinessLogic.Logging; using TransactionProcessor.Mobile.BusinessLogic.Models; using TransactionProcessor.Mobile.BusinessLogic.Services; @@ -23,15 +22,26 @@ public class TransactionServiceTests{ private Mock ApplicationCache; + String Serialise(Object arg) + { + return StringSerialiser.Serialise(arg, new SerialiserOptions(SerialiserPropertyFormat.SnakeCase)); + } + + Object Deserialise(String arg, Type type) + { + return StringSerialiser.DeserializeObject(arg, type, new SerialiserOptions(SerialiserPropertyFormat.SnakeCase)); + } + public TransactionServiceTests(){ this.MockHttpMessageHandler = new MockHttpMessageHandler(); this.BaseAddressResolver = (s) => $"http://localhost"; this.ApplicationCache = new Mock(); - this.TransactionService = new TransactionService(this.BaseAddressResolver, this.MockHttpMessageHandler.ToHttpClient(), this.ApplicationCache.Object); + this.TransactionService = new TransactionService(this.BaseAddressResolver, this.MockHttpMessageHandler.ToHttpClient(), this.ApplicationCache.Object, this.Serialise,this.Deserialise); this.ApplicationCache.Setup(s => s.GetAccessToken()).Returns(new TokenResponseModel(){ AccessToken = "token" }); Logger.Initialise(new Logging.NullLogger()); + StringSerialiser.Initialise((IStringSerialiser)new SystemTextJsonSerializer(SystemTextJsonSerializer.GetDefaultJsonSerializerOptions())); } [Fact] @@ -54,7 +64,7 @@ public async Task TransactionService_PerformLogon_LogonPerformed(){ }; this.MockHttpMessageHandler.When($"http://localhost/api/logontransactions") - .Respond("application/json", JsonConvert.SerializeObject(expectedResponse)); // Respond with JSON + .Respond("application/json", StringSerialiser.Serialise(expectedResponse)); // Respond with JSON Result performLogonResult = await this.TransactionService.PerformLogon(requestModel, CancellationToken.None); @@ -92,7 +102,7 @@ public async Task TransactionService_PerformLogon_RequestPayload_DoesNotContainT requestPayload = req.Content!.ReadAsStringAsync().GetAwaiter().GetResult(); return new HttpResponseMessage(HttpStatusCode.OK){ - Content = new StringContent(JsonConvert.SerializeObject(expectedResponse), Encoding.UTF8, "application/json") + Content = new StringContent(StringSerialiser.Serialise(expectedResponse), Encoding.UTF8, "application/json") }; }); @@ -101,12 +111,6 @@ public async Task TransactionService_PerformLogon_RequestPayload_DoesNotContainT performLogonResult.IsSuccess.ShouldBeTrue(); requestPayload.ShouldNotBeNullOrWhiteSpace(); requestPayload.ShouldNotContain("$type"); - - JObject requestJson = JObject.Parse(requestPayload); - requestJson["ApplicationVersion"]?.Value().ShouldBe(TestData.ApplicationVersion); - requestJson["DeviceIdentifier"]?.Value().ShouldBe(TestData.DeviceIdentifier); - requestJson["TransactionDateTime"]?.Value().ShouldBe(TestData.TransactionDateTime); - requestJson["TransactionNumber"]?.Value().ShouldBe(TestData.TransactionNumber); } [Theory] @@ -155,7 +159,7 @@ public async Task TransactionService_PerformMobileTopup_MobileTopupPerformed(){ }; this.MockHttpMessageHandler.When($"http://localhost/api/saletransactions") - .Respond("application/json", JsonConvert.SerializeObject(expectedResponse)); // Respond with JSON + .Respond("application/json", StringSerialiser.Serialise(expectedResponse)); // Respond with JSON Result performMobileTopupResult = await this.TransactionService.PerformMobileTopup(requestModel, CancellationToken.None); @@ -218,7 +222,7 @@ public async Task TransactionService_PerformVoucherIssue_VoucherIssuePerformed() }; this.MockHttpMessageHandler.When($"http://localhost/api/saletransactions") - .Respond("application/json", JsonConvert.SerializeObject(expectedResponse)); // Respond with JSON + .Respond("application/json", StringSerialiser.Serialise(expectedResponse)); // Respond with JSON Result performVoucherIssueResult = await this.TransactionService.PerformVoucherIssue(requestModel, CancellationToken.None); @@ -284,7 +288,7 @@ public async Task TransactionService_PerformBillPaymentGetAccount_GetAccountPerf }; this.MockHttpMessageHandler.When($"http://localhost/api/saletransactions") - .Respond("application/json", JsonConvert.SerializeObject(expectedResponse)); // Respond with JSON + .Respond("application/json", StringSerialiser.Serialise(expectedResponse)); // Respond with JSON Result performBillPaymentGetAccountResult = await this.TransactionService.PerformBillPaymentGetAccount(requestModel, CancellationToken.None); performBillPaymentGetAccountResult.ShouldNotBeNull(); @@ -346,7 +350,7 @@ public async Task TransactionService_PerformBillPaymentGetMeter_GetMeterPerforme }; this.MockHttpMessageHandler.When($"http://localhost/api/saletransactions") - .Respond("application/json", JsonConvert.SerializeObject(expectedResponse)); // Respond with JSON + .Respond("application/json", StringSerialiser.Serialise(expectedResponse)); // Respond with JSON Result performBillPaymentGetMeterResult = await this.TransactionService.PerformBillPaymentGetMeter(requestModel, CancellationToken.None); @@ -381,7 +385,7 @@ public async Task TransactionService_PerformBillPaymentGetMeter_NoAdditionalResp }; this.MockHttpMessageHandler.When($"http://localhost/api/saletransactions") - .Respond("application/json", JsonConvert.SerializeObject(expectedResponse)); // Respond with JSON + .Respond("application/json", StringSerialiser.Serialise(expectedResponse)); // Respond with JSON Result performBillPaymentGetMeterResult = await this.TransactionService.PerformBillPaymentGetMeter(requestModel, CancellationToken.None); @@ -440,7 +444,7 @@ public async Task TransactionService_PerformBillPaymentMakePayment_MakePaymentPe }; this.MockHttpMessageHandler.When($"http://localhost/api/saletransactions") - .Respond("application/json", JsonConvert.SerializeObject(expectedResponse)); // Respond with JSON + .Respond("application/json", StringSerialiser.Serialise(expectedResponse)); // Respond with JSON Result performBillPaymentGetMeterResult = await this.TransactionService.PerformBillPaymentMakePayment(requestModel, CancellationToken.None); @@ -507,7 +511,7 @@ public async Task TransactionService_PerformReconciliation_ReconciliationPerform }; this.MockHttpMessageHandler.When($"http://localhost/api/reconciliationtransactions") - .Respond("application/json", JsonConvert.SerializeObject(expectedResponse)); // Respond with JSON + .Respond("application/json", StringSerialiser.Serialise(expectedResponse)); // Respond with JSON Result performReconciliationResult = await this.TransactionService.PerformReconciliation(requestModel, CancellationToken.None); diff --git a/TransactionProcessor.Mobile.BusinessLogic.Tests/ServicesTests/UpdateServiceTests.cs b/TransactionProcessor.Mobile.BusinessLogic.Tests/ServicesTests/UpdateServiceTests.cs index 3bc2aed45..adf5b159a 100644 --- a/TransactionProcessor.Mobile.BusinessLogic.Tests/ServicesTests/UpdateServiceTests.cs +++ b/TransactionProcessor.Mobile.BusinessLogic.Tests/ServicesTests/UpdateServiceTests.cs @@ -1,5 +1,5 @@ -using Newtonsoft.Json; -using RichardSzalay.MockHttp; +using RichardSzalay.MockHttp; +using Shared.Serialisation; using Shouldly; using SimpleResults; using TransactionProcessor.Mobile.BusinessLogic.Logging; @@ -14,10 +14,21 @@ public class UpdateServiceTests private readonly IUpdateService UpdateService; + String Serialise(Object arg) + { + return StringSerialiser.Serialise(arg, new SerialiserOptions(SerialiserPropertyFormat.SnakeCase)); + } + + Object Deserialise(String arg, Type type) + { + return StringSerialiser.DeserializeObject(arg, type, new SerialiserOptions(SerialiserPropertyFormat.SnakeCase)); + } + public UpdateServiceTests() { this.MockHttpMessageHandler = new MockHttpMessageHandler(); - this.UpdateService = new UpdateService(_ => "http://localhost", this.MockHttpMessageHandler.ToHttpClient()); + this.UpdateService = new UpdateService(_ => "http://localhost", this.MockHttpMessageHandler.ToHttpClient(), Serialise, Deserialise); + StringSerialiser.Initialise((IStringSerialiser)new SystemTextJsonSerializer(SystemTextJsonSerializer.GetDefaultJsonSerializerOptions())); } [Fact] @@ -34,7 +45,7 @@ public async Task UpdateService_CheckForUpdates_ResultSuccess_And_UpdateResponse }; this.MockHttpMessageHandler.When("http://localhost/api/applicationupdates/check") - .Respond("application/json", JsonConvert.SerializeObject(expectedResponse)); + .Respond("application/json", StringSerialiser.Serialise(expectedResponse)); Result updateResult = await this.UpdateService.CheckForUpdates(TestData.ApplicationVersion, "com.transactionprocessor.mobile", diff --git a/TransactionProcessor.Mobile.BusinessLogic.Tests/TransactionProcessor.Mobile.BusinessLogic.Tests.csproj b/TransactionProcessor.Mobile.BusinessLogic.Tests/TransactionProcessor.Mobile.BusinessLogic.Tests.csproj index 66e1a7263..65364bcc3 100644 --- a/TransactionProcessor.Mobile.BusinessLogic.Tests/TransactionProcessor.Mobile.BusinessLogic.Tests.csproj +++ b/TransactionProcessor.Mobile.BusinessLogic.Tests/TransactionProcessor.Mobile.BusinessLogic.Tests.csproj @@ -9,9 +9,9 @@ - + - + @@ -21,10 +21,17 @@ runtime; build; native; contentfiles; analyzers; buildtransitive all - + runtime; build; native; contentfiles; analyzers; buildtransitive all + + all + + + + all + diff --git a/TransactionProcessor.Mobile.BusinessLogic/RequestHandlers/TransactionRequestHandler.cs b/TransactionProcessor.Mobile.BusinessLogic/RequestHandlers/TransactionRequestHandler.cs index 3fa6244de..4ea2f76dc 100644 --- a/TransactionProcessor.Mobile.BusinessLogic/RequestHandlers/TransactionRequestHandler.cs +++ b/TransactionProcessor.Mobile.BusinessLogic/RequestHandlers/TransactionRequestHandler.cs @@ -1,8 +1,6 @@ using MediatR; -using Microsoft.Extensions.Logging; -using Newtonsoft.Json; +using Shared.Serialisation; using SimpleResults; -using System.Diagnostics; using TransactionProcessor.Mobile.BusinessLogic.Common; using TransactionProcessor.Mobile.BusinessLogic.Database; using TransactionProcessor.Mobile.BusinessLogic.Models; @@ -123,7 +121,7 @@ public async Task> Handle(TransactionCommands. await this.UpdateTransactionRecord(transaction.transactionRecord.UpdateFrom(result)); if (result.IsSuccess && result.Data.IsSuccessful == false) { - return Result.Failure($"Logon transaction not successful {JsonConvert.SerializeObject(result.Data)}"); + return Result.Failure($"Logon transaction not successful {StringSerialiser.Serialise(result.Data)}"); } return Result.Success(result.Data); diff --git a/TransactionProcessor.Mobile.BusinessLogic/Services/AuthenticationService.cs b/TransactionProcessor.Mobile.BusinessLogic/Services/AuthenticationService.cs index 70f43a1ae..62e5547ef 100644 --- a/TransactionProcessor.Mobile.BusinessLogic/Services/AuthenticationService.cs +++ b/TransactionProcessor.Mobile.BusinessLogic/Services/AuthenticationService.cs @@ -1,7 +1,7 @@ -using Newtonsoft.Json; -using SecurityService.Client; -using SecurityService.DataTransferObjects.Responses; +using SecurityService.Client; +using SecurityService.DataTransferObjects; using Shared.Results; +using Shared.Serialisation; using SimpleResults; using TransactionProcessor.Mobile.BusinessLogic.Logging; using TransactionProcessor.Mobile.BusinessLogic.Models; @@ -55,7 +55,7 @@ public async Task> GetToken(String username, } Logger.LogInformation($"Token for {username} requested successfully"); - Logger.LogDebug($"Token Response: [{JsonConvert.SerializeObject(tokenResult.Data.AccessToken)}]"); + Logger.LogDebug($"Token Response: [{StringSerialiser.Serialise(tokenResult.Data.AccessToken)}]"); return Result.Success(new TokenResponseModel { @@ -89,7 +89,7 @@ public async Task> RefreshAccessToken(String refreshT } Logger.LogInformation($"Refresh Token requested successfully"); - Logger.LogDebug($"Token Response: [{JsonConvert.SerializeObject(tokenResult.Data.AccessToken)}]"); + Logger.LogDebug($"Token Response: [{StringSerialiser.Serialise(tokenResult.Data.AccessToken)}]"); return Result.Success(new TokenResponseModel { diff --git a/TransactionProcessor.Mobile.BusinessLogic/Services/ConfigurationService.cs b/TransactionProcessor.Mobile.BusinessLogic/Services/ConfigurationService.cs index f3f837185..fdb32e51f 100644 --- a/TransactionProcessor.Mobile.BusinessLogic/Services/ConfigurationService.cs +++ b/TransactionProcessor.Mobile.BusinessLogic/Services/ConfigurationService.cs @@ -1,6 +1,6 @@ -using System.Net; -using System.Text; -using Newtonsoft.Json; +using System.Text; +using Shared.Results; +using Shared.Serialisation; using SimpleResults; using TransactionProcessor.Mobile.BusinessLogic.Logging; using TransactionProcessor.Mobile.BusinessLogic.Models; @@ -22,7 +22,7 @@ public class ConfigurationService : ClientProxyBase.ClientProxyBase, IConfigurat private readonly Func BaseAddressResolver; public ConfigurationService(Func baseAddressResolver, - HttpClient httpClient) : base(httpClient) { + HttpClient httpClient, Func serialise, Func deserialise) : base(httpClient, serialise, deserialise) { this.BaseAddressResolver = baseAddressResolver; } @@ -36,19 +36,19 @@ private String BuildRequestUrl(String route) return requestUri; } - protected override async Task HandleResponse(HttpResponseMessage responseMessage, - CancellationToken cancellationToken) - { - String content = await responseMessage.Content.ReadAsStringAsync(); + //protected override async Task HandleResponse(HttpResponseMessage responseMessage, + // CancellationToken cancellationToken) + //{ + // String content = await responseMessage.Content.ReadAsStringAsync(); - if (responseMessage.StatusCode == HttpStatusCode.NotFound) - { - // No error as maybe running under CI (which has no internet) - return content; - } + // if (responseMessage.StatusCode == HttpStatusCode.NotFound) + // { + // // No error as maybe running under CI (which has no internet) + // return content; + // } - return await base.HandleResponse(responseMessage, cancellationToken); - } + // return await base.HandleResponse(responseMessage, cancellationToken); + //} public async Task> GetConfiguration(String deviceIdentifier, CancellationToken cancellationToken) @@ -60,33 +60,27 @@ public async Task> GetConfiguration(String deviceIdentifie { Logger.LogInformation($"About to request configuration for device identifier {deviceIdentifier}"); Logger.LogDebug($"Configuration Request details: Uri {requestUri}"); - - // Make the Http Call here - HttpResponseMessage httpResponse = await this.HttpClient.GetAsync(requestUri, cancellationToken); - Logger.LogDebug($"Configuration Response [{httpResponse.StatusCode}]"); - - // Process the response - String content = await this.HandleResponse(httpResponse, cancellationToken); - Logger.LogDebug($"Configuration Response Content [{content}]"); - + // call was successful so now deserialise the body to the response object - ConfigurationResponse apiResponse = JsonConvert.DeserializeObject(content); + Result? apiResponse = await this.Get(requestUri, cancellationToken); + if (apiResponse.IsFailed) + return ResultHelpers.CreateFailure(apiResponse); Logger.LogDebug($"About to build Configuration"); response = new Configuration() { - ClientSecret = apiResponse.ClientSecret, - ClientId = apiResponse.ClientId, - ApplicationUpdateUri = apiResponse.ApplicationUpdateUri, - EnableAutoUpdates = apiResponse.EnableAutoUpdates, - SecurityServiceUri = apiResponse.HostAddresses.Single(h => h.ServiceType == ServiceType.Security).Uri, + ClientSecret = apiResponse.Data.ClientSecret, + ClientId = apiResponse.Data.ClientId, + ApplicationUpdateUri = apiResponse.Data.ApplicationUpdateUri, + EnableAutoUpdates = apiResponse.Data.EnableAutoUpdates, + SecurityServiceUri = apiResponse.Data.HostAddresses.Single(h => h.ServiceType == ServiceType.Security).Uri, TransactionProcessorAclUri = - apiResponse.HostAddresses.Single(h => h.ServiceType == ServiceType.TransactionProcessorAcl).Uri, - LogMessageBatchSize = apiResponse.LogMessageBatchSize.GetValueOrDefault(), - SentryDsn = apiResponse.SentryDsn ?? String.Empty, + apiResponse.Data.HostAddresses.Single(h => h.ServiceType == ServiceType.TransactionProcessorAcl).Uri, + LogMessageBatchSize = apiResponse.Data.LogMessageBatchSize.GetValueOrDefault(), + SentryDsn = apiResponse.Data.SentryDsn ?? String.Empty, }; Logger.LogDebug($"About to xlate log level"); - response.LogLevel = apiResponse.LogLevel switch + response.LogLevel = apiResponse.Data.LogLevel switch { LoggingLevel.Debug => LogLevel.Debug, LoggingLevel.Error => LogLevel.Error, @@ -98,7 +92,7 @@ public async Task> GetConfiguration(String deviceIdentifie }; Logger.LogInformation($"Configuration for device identifier {deviceIdentifier} requested successfully"); - Logger.LogDebug($"Configuration Response: [{content}]"); + Logger.LogDebug($"Configuration Response: [{StringSerialiser.Serialise(apiResponse.Data)}]"); return Result.Success(response); } @@ -122,10 +116,10 @@ public async Task PostDiagnosticLogs(String deviceIdentifier, { messages = logMessages }; - StringContent content = new StringContent(JsonConvert.SerializeObject(container), Encoding.UTF8, "application/json"); + StringContent content = new(StringSerialiser.Serialise(container), Encoding.UTF8, "application/json"); - HttpResponseMessage httpResponse = await this.HttpClient.PostAsync(requestUri, content, cancellationToken); + Result? result = await this.Post(requestUri, content, cancellationToken); - await this.HandleResponse(httpResponse, cancellationToken); + // TODO: return the result to the caller so that we can retry if it fails (and also log any errors that occur here) } } diff --git a/TransactionProcessor.Mobile.BusinessLogic/Services/MerchantService.cs b/TransactionProcessor.Mobile.BusinessLogic/Services/MerchantService.cs index aeb5222b3..7eb573c40 100644 --- a/TransactionProcessor.Mobile.BusinessLogic/Services/MerchantService.cs +++ b/TransactionProcessor.Mobile.BusinessLogic/Services/MerchantService.cs @@ -1,7 +1,6 @@ using System.Diagnostics.CodeAnalysis; -using System.Net.Http.Headers; -using ClientProxyBase; -using Newtonsoft.Json; +using Shared.Results; +using Shared.Serialisation; using SimpleResults; using TransactionProcessor.Mobile.BusinessLogic.Logging; using TransactionProcessor.Mobile.BusinessLogic.Models; @@ -39,7 +38,10 @@ public class MerchantService : ClientProxyBase.ClientProxyBase, IMerchantService public MerchantService(Func baseAddressResolver, HttpClient httpClient, IApplicationCache applicationCache, - IApplicationInfoService applicationInfoService) : base(httpClient) { + IApplicationInfoService applicationInfoService, + Func serialise, + Func deserialise) : base(httpClient, serialise, deserialise) + { this.BaseAddressResolver = baseAddressResolver; this.ApplicationCache = applicationCache; this.ApplicationInfoService = applicationInfoService; @@ -68,28 +70,19 @@ public async Task>> GetContractProducts(Cancel Logger.LogInformation("About to request merchant contracts"); Logger.LogDebug($"Merchant Contract Request details: Access Token {accessToken.AccessToken}"); - HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, requestUri); - request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken.AccessToken); - var httpResponse = await this.HttpClient.SendAsync(request, cancellationToken); - - // Process the response - Result content = await this.HandleResponseX(httpResponse, cancellationToken); + Result>? responseDataResult = await this.Get>(requestUri, cancellationToken); - if (content.IsFailed) { - Logger.LogInformation($"GetMerchantContracts failed {content.Status}"); - return Result.Failure(content.Message); + if (responseDataResult.IsFailed) { + Logger.LogInformation($"GetMerchantContracts failed {responseDataResult.Status}"); + return ResultHelpers.CreateFailure(responseDataResult); } - Logger.LogDebug($"Transaction Response details: Status {httpResponse.StatusCode} Payload {content.Data}"); - - List? responseData = JsonConvert.DeserializeObject>(content.Data); + Logger.LogInformation($"{responseDataResult.Data.Count} for merchant requested successfully"); + Logger.LogDebug($"Merchant Contract Response: [{StringSerialiser.Serialise(responseDataResult.Data)}]"); - Logger.LogInformation($"{responseData.Count} for merchant requested successfully"); - Logger.LogDebug($"Merchant Contract Response: [{JsonConvert.SerializeObject(responseData)}]"); - - foreach (ContractResponse contractResponse in responseData) { + foreach (ContractResponse contractResponse in responseDataResult.Data) { foreach (ContractProduct contractResponseProduct in contractResponse.Products) { - var productType = GetProductType(contractResponse.OperatorName); + ProductType productType = GetProductType(contractResponse.OperatorName); models.Add(new ContractProductModel { OperatorId = contractResponse.OperatorId, @@ -142,48 +135,57 @@ public async Task> GetMerchantDetails(CancellationT Logger.LogInformation("About to request merchant details"); Logger.LogDebug($"Merchant Details Request details: Access Token {accessToken.AccessToken}"); - HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, requestUri); - request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken.AccessToken); - var httpResponse = await this.HttpClient.SendAsync(request, cancellationToken); + //HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, requestUri); + //request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken.AccessToken); + //var httpResponse = await this.HttpClient.SendAsync(request, cancellationToken); + + //// Process the response + //Result content = await this.HandleResponseX(httpResponse, cancellationToken); - // Process the response - Result content = await this.HandleResponseX(httpResponse, cancellationToken); + //if (content.IsFailed) + //{ + // Logger.LogInformation($"GetMerchantContracts failed {content.Status}"); + // return Result.Failure(content.Message); + //} - if (content.IsFailed) + //Logger.LogDebug($"Transaction Response details: Status {httpResponse.StatusCode} Payload {content.Data}"); + + ////ResponseData responseData = this.HandleResponseContent(content.Data); + //MerchantResponse responseData = JsonConvert.DeserializeObject(content.Data); + + Result? responseDataResult = await this.Get(requestUri, cancellationToken); + + if (responseDataResult.IsFailed) { - Logger.LogInformation($"GetMerchantContracts failed {content.Status}"); - return Result.Failure(content.Message); + Logger.LogInformation($"GetMerchantContracts failed {responseDataResult.Status}"); + return ResultHelpers.CreateFailure(responseDataResult); } - Logger.LogDebug($"Transaction Response details: Status {httpResponse.StatusCode} Payload {content.Data}"); - - //ResponseData responseData = this.HandleResponseContent(content.Data); - MerchantResponse responseData = JsonConvert.DeserializeObject(content.Data); Logger.LogInformation("Merchant details requested successfully"); - Logger.LogDebug($"Merchant Details Response: [{JsonConvert.SerializeObject(responseData)}]"); - + Logger.LogDebug($"Merchant Details Response: [{StringSerialiser.Serialise(responseDataResult.Data)}]"); + MerchantDetailsModel model = new MerchantDetailsModel { - EstateId = responseData.EstateId, - MerchantId = responseData.MerchantId, - MerchantName = responseData.MerchantName, - NextStatementDate = responseData.NextStatementDate, + EstateId = responseDataResult.Data.EstateId, + MerchantId = responseDataResult.Data.MerchantId, + MerchantName = responseDataResult.Data.MerchantName, + NextStatementDate = responseDataResult.Data.NextStatementDate, LastStatementDate = new DateTime(), - SettlementSchedule = responseData.SettlementSchedule.ToString(), + SettlementSchedule = responseDataResult.Data.SettlementSchedule.ToString(), //AvailableBalance = merchantResponse.AvailableBalance, //Balance = merchantResponse.Balance, Contact = new ContactModel { - Name = responseData.Contacts.First().ContactName, - EmailAddress = responseData.Contacts.First().ContactEmailAddress, - MobileNumber = responseData.Contacts.First().ContactPhoneNumber + Name = responseDataResult.Data.Contacts.First().ContactName, + EmailAddress = responseDataResult.Data.Contacts.First().ContactEmailAddress, + MobileNumber = responseDataResult.Data.Contacts.First().ContactPhoneNumber }, Address = new AddressModel { - AddressLine3 = responseData.Addresses.First().AddressLine3, - Town = responseData.Addresses.First().Town, - AddressLine4 = responseData.Addresses.First().AddressLine4, - PostalCode = responseData.Addresses.First().PostalCode, - Region = responseData.Addresses.First().Region, - AddressLine1 = responseData.Addresses.First().AddressLine1, - AddressLine2 = responseData.Addresses.First().AddressLine2 + AddressLine3 = responseDataResult.Data.Addresses.First().AddressLine3, + Town = responseDataResult.Data.Addresses.First().Town, + AddressLine4 = responseDataResult.Data.Addresses.First().AddressLine4, + PostalCode = responseDataResult.Data.Addresses.First().PostalCode, + Region = responseDataResult.Data.Addresses.First().Region, + AddressLine1 = responseDataResult.Data.Addresses.First().AddressLine1, + AddressLine2 = responseDataResult.Data.Addresses.First().AddressLine2 } }; diff --git a/TransactionProcessor.Mobile.BusinessLogic/Services/TransactionService.cs b/TransactionProcessor.Mobile.BusinessLogic/Services/TransactionService.cs index 0db1abe04..27567bb5a 100644 --- a/TransactionProcessor.Mobile.BusinessLogic/Services/TransactionService.cs +++ b/TransactionProcessor.Mobile.BusinessLogic/Services/TransactionService.cs @@ -1,8 +1,4 @@ -using System.Net; -using System.Net.Http.Headers; -using System.Text; -using ClientProxyBase; -using Newtonsoft.Json; +using Shared.Serialisation; using SimpleResults; using TransactionProcessor.Mobile.BusinessLogic.Common; using TransactionProcessor.Mobile.BusinessLogic.Logging; @@ -47,12 +43,10 @@ public class TransactionService : ClientProxyBase.ClientProxyBase, ITransactionS public TransactionService(Func baseAddressResolver, HttpClient httpClient, - IApplicationCache applicationCache) : base(httpClient) { + IApplicationCache applicationCache, Func serialise, + Func deserialise) : base(httpClient, serialise, deserialise) { this.BaseAddressResolver = baseAddressResolver; this.ApplicationCache = applicationCache; - - // Add the API version header - this.HttpClient.DefaultRequestHeaders.Add("api-version", "1.0"); } #endregion @@ -189,15 +183,6 @@ public async Task> PerformVoucherIssue( return Result.Success(responseModel); } - - protected override async Task> HandleResponseX(HttpResponseMessage responseMessage, - CancellationToken cancellationToken) { - if (responseMessage.StatusCode == HttpStatusCode.HttpVersionNotSupported) { - throw new ApplicationException("Application needs to be updated to the latest version"); - } - - return await base.HandleResponseX(responseMessage, cancellationToken); - } private String BuildRequestUrl(String route) { String baseAddress = this.BaseAddressResolver("TransactionProcessorACL"); @@ -212,33 +197,23 @@ private async Task> SendTransactionRequest result = await this.HandleResponseX(httpResponse, cancellationToken); + Result? result = await this.Post(requestUri, request, accessToken.AccessToken, cancellationToken); if (result.IsSuccess == false) { - Logger.LogWarning("Error performing Voucher transaction"); - return Result.Failure("Error performing Voucher transaction"); + Logger.LogWarning("Error performing transaction"); + return Result.Failure("Error performing transaction"); } - Logger.LogDebug($"Transaction Response details: Status {httpResponse.StatusCode} Payload {result.Data}"); - - var responseData = JsonConvert.DeserializeObject(result.Data); + Logger.LogDebug($"Transaction Response details: Payload {StringSerialiser.Serialise(result.Data)}"); - return Result.Success(responseData); + return Result.Success(result.Data); } catch (Exception ex) { // An exception has occurred, add some additional information to the message diff --git a/TransactionProcessor.Mobile.BusinessLogic/Services/UpdateService.cs b/TransactionProcessor.Mobile.BusinessLogic/Services/UpdateService.cs index 0f2db93dd..708cb547f 100644 --- a/TransactionProcessor.Mobile.BusinessLogic/Services/UpdateService.cs +++ b/TransactionProcessor.Mobile.BusinessLogic/Services/UpdateService.cs @@ -1,5 +1,5 @@ -using System.Text; -using Newtonsoft.Json; +using Shared.Results; +using Shared.Serialisation; using SimpleResults; using TransactionProcessor.Mobile.BusinessLogic.Logging; using TransactionProcessor.Mobile.BusinessLogic.Models; @@ -25,7 +25,8 @@ private sealed record ApplicationUpdateCheckRequest(String ApplicationVersion, private readonly Func BaseAddressResolver; public UpdateService(Func baseAddressResolver, - HttpClient httpClient) : base(httpClient) + HttpClient httpClient, Func serialise, + Func deserialise) : base(httpClient, serialise, deserialise) { this.BaseAddressResolver = baseAddressResolver; } @@ -44,22 +45,16 @@ public async Task> CheckForUpdates(String Logger.LogInformation($"About to check for application updates for device identifier {deviceIdentifier}"); Logger.LogDebug($"Application update request details: Uri {requestUri}"); - using StringContent content = new(JsonConvert.SerializeObject(request), Encoding.UTF8, "application/json"); - using HttpResponseMessage httpResponse = await this.HttpClient.PostAsync(requestUri, content, cancellationToken); - Logger.LogDebug($"Application update response [{httpResponse.StatusCode}]"); + Result? result = await this.Post(requestUri, request, cancellationToken); - String responseContent = await this.HandleResponse(httpResponse, cancellationToken); - Logger.LogDebug($"Application update response content [{responseContent}]"); - - ApplicationUpdateCheckResponse? response = JsonConvert.DeserializeObject(responseContent); - - if (response == null) - { - return Result.Failure("Application update check did not return a valid response."); + if (result.IsFailed) { + return ResultHelpers.CreateFailure(result); } + Logger.LogDebug($"Application update response content [{StringSerialiser.Serialise(result.Data)}]"); + Logger.LogInformation($"Application update check for device identifier {deviceIdentifier} completed successfully"); - return Result.Success(response); + return Result.Success(result.Data); } catch (Exception ex) { diff --git a/TransactionProcessor.Mobile.BusinessLogic/TransactionProcessor.Mobile.BusinessLogic.csproj b/TransactionProcessor.Mobile.BusinessLogic/TransactionProcessor.Mobile.BusinessLogic.csproj index 7d324aaa4..bc5915678 100644 --- a/TransactionProcessor.Mobile.BusinessLogic/TransactionProcessor.Mobile.BusinessLogic.csproj +++ b/TransactionProcessor.Mobile.BusinessLogic/TransactionProcessor.Mobile.BusinessLogic.csproj @@ -7,16 +7,21 @@ - + + + all + - - + + all + + diff --git a/TransactionProcessor.Mobile.UITests/Common/DockerHelper.cs b/TransactionProcessor.Mobile.UITests/Common/DockerHelper.cs index 5eeb324ea..1143277cc 100644 --- a/TransactionProcessor.Mobile.UITests/Common/DockerHelper.cs +++ b/TransactionProcessor.Mobile.UITests/Common/DockerHelper.cs @@ -1,7 +1,4 @@ -using System.Net; -using System.Net.Sockets; -using System.Runtime.InteropServices; -using DotNet.Testcontainers.Builders; +using DotNet.Testcontainers.Builders; using DotNet.Testcontainers.Containers; using DotNet.Testcontainers.Networks; using EventStore.Client; @@ -10,7 +7,11 @@ using Shared.IntegrationTesting; using Shared.IntegrationTesting.TestContainers; using Shared.Logger; +using Shared.Serialisation; using Shouldly; +using System.Net; +using System.Net.Sockets; +using System.Runtime.InteropServices; using TransactionProcessor.Client; using TransactionProcessor.DataTransferObjects.Responses.Contract; using TransactionProcessor.IntegrationTesting.Helpers; @@ -54,6 +55,7 @@ public class DockerHelper : global::Shared.IntegrationTesting.TestContainers.Doc public DockerHelper() { this.TestingContext = new TestingContext(); + StringSerialiser.Initialise((IStringSerialiser)new SystemTextJsonSerializer(SystemTextJsonSerializer.GetDefaultJsonSerializerOptions())); } #endregion @@ -107,6 +109,16 @@ public override async Task CreateSubscriptions() } } + String Serialise(Object arg) + { + return StringSerialiser.Serialise(arg, new SerialiserOptions(SerialiserPropertyFormat.SnakeCase)); + } + + Object Deserialise(String arg, Type type) + { + return StringSerialiser.DeserializeObject(arg, type, new SerialiserOptions(SerialiserPropertyFormat.SnakeCase)); + } + /// /// Starts the containers for scenario run. /// @@ -144,8 +156,8 @@ public override async Task StartContainersForScenarioRun(String scenarioName, Do }; HttpClient httpClient = new HttpClient(clientHandler); - this.SecurityServiceClient = new SecurityServiceClient(this.SecurityServiceBaseAddressResolver, httpClient); - this.TransactionProcessorClient = new TransactionProcessorClient(this.TransactionProcessorBaseAddressResolver, httpClient); + this.SecurityServiceClient = new SecurityServiceClient(this.SecurityServiceBaseAddressResolver, httpClient, Serialise, Deserialise); + this.TransactionProcessorClient = new TransactionProcessorClient(this.TransactionProcessorBaseAddressResolver, httpClient, Serialise, Deserialise); this.HttpClient = new HttpClient(); this.HttpClient.BaseAddress = new Uri(this.TransactionProcessorAclBaseAddressResolver(string.Empty)); @@ -234,7 +246,7 @@ public TestingContext() this.Estates = new List(); this.Clients = new List(); this.Users = new Dictionary(); - this.Roles = new Dictionary(); + this.Roles = new Dictionary(); this.ApiResources = new List(); } @@ -266,7 +278,7 @@ public TestingContext() /// public NlogLogger Logger { get; set; } public Dictionary Users; - public Dictionary Roles; + public Dictionary Roles; public List ApiResources; //public List IdentityResources; diff --git a/TransactionProcessor.Mobile.UITests/Steps/SharedSteps.cs b/TransactionProcessor.Mobile.UITests/Steps/SharedSteps.cs index f11892f1c..dec208ac8 100644 --- a/TransactionProcessor.Mobile.UITests/Steps/SharedSteps.cs +++ b/TransactionProcessor.Mobile.UITests/Steps/SharedSteps.cs @@ -1,14 +1,15 @@ -using System.Net; -using System.Text; -using System.Text.Json; -using Newtonsoft.Json; +using Newtonsoft.Json; using Newtonsoft.Json.Linq; using Reqnroll; -using SecurityService.DataTransferObjects.Requests; +using SecurityService.DataTransferObjects; using SecurityService.IntegrationTesting.Helpers; using Shared.IntegrationTesting; +using Shared.Serialisation; using Shouldly; -using TransactionProcessor.Database.Contexts; +using System.Diagnostics.CodeAnalysis; +using System.Net; +using System.Text; +using System.Text.Json; using TransactionProcessor.DataTransferObjects.Requests.Contract; using TransactionProcessor.DataTransferObjects.Requests.Estate; using TransactionProcessor.DataTransferObjects.Requests.Merchant; @@ -19,6 +20,7 @@ using TransactionProcessor.IntegrationTesting.Helpers; using TransactionProcessor.Mobile.UITests.Common; using TransactionProcessor.Mobile.UITests.Pages; +using TransactionProcessor.ProjectionEngine.Database.Database.Entities; using AssignOperatorRequest = TransactionProcessor.DataTransferObjects.Requests.Estate.AssignOperatorRequest; namespace TransactionProcessor.Mobile.UITests.Steps @@ -51,9 +53,9 @@ public SharedSteps(TestingContext testingContext) { public async Task GivenTheFollowingSecurityRolesExist(DataTable table) { List requests = table.Rows.ToCreateRoleRequests(); - List<(String, Guid)> responses = await this.SecurityServiceSteps.GivenICreateTheFollowingRoles(requests, CancellationToken.None); + List<(String, String)> responses = await this.SecurityServiceSteps.GivenICreateTheFollowingRoles(requests, CancellationToken.None); - foreach ((String, Guid) response in responses) + foreach ((String, String) response in responses) { this.TestingContext.Roles.Add(response.Item1, response.Item2); } @@ -219,7 +221,7 @@ public async Task GivenIHaveCreatedAConfigForMyDevice() { }); HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, $"http://127.0.0.1:{this.TestingContext.DockerHelper.ConfigHostPort}/api/transactionmobileconfiguration"); - request.Content = new StringContent(JsonConvert.SerializeObject(configRequest), Encoding.UTF8, "application/json"); + request.Content = new StringContent(StringSerialiser.Serialise(configRequest), Encoding.UTF8, "application/json"); HttpClientHandler clientHandler = new HttpClientHandler { @@ -274,10 +276,8 @@ public async Task GivenIHaveCreatedAConfigForMyApplication() private async Task GetMerchantBalance(Guid merchantId) { - JsonElement jsonElement = (JsonElement)await this.TestingContext.DockerHelper.ProjectionManagementClient.GetStateAsync("MerchantBalanceProjection", $"MerchantBalance-{merchantId:N}"); - JObject jsonObject = JObject.Parse(jsonElement.GetRawText()); - decimal balanceValue = jsonObject.SelectToken("merchant.balance").Value(); - return balanceValue; + MerchantBalanceProjectionState1 balanceState = await this.TestingContext.DockerHelper.ProjectionManagementClient.GetStateAsync("MerchantBalanceProjection", $"MerchantBalance-{merchantId:N}"); + return balanceState.merchant.balance; } [Given(@"I make the following manual merchant deposits")] @@ -346,3 +346,9 @@ public async Task GivenTheFollowingMetersAreAvailableAtThePataPawaPrePayHost(Dat } } } + +[ExcludeFromCodeCoverage] +public record Merchant(string Id, string Name, int numberOfEventsProcessed, decimal balance); + +[ExcludeFromCodeCoverage] +public record MerchantBalanceProjectionState1(Merchant merchant); diff --git a/TransactionProcessor.Mobile.UITests/TransactionProcessor.Mobile.UITests.csproj b/TransactionProcessor.Mobile.UITests/TransactionProcessor.Mobile.UITests.csproj index d8940fac9..8379eacfe 100644 --- a/TransactionProcessor.Mobile.UITests/TransactionProcessor.Mobile.UITests.csproj +++ b/TransactionProcessor.Mobile.UITests/TransactionProcessor.Mobile.UITests.csproj @@ -16,7 +16,7 @@ - + @@ -28,11 +28,11 @@ - - - - - + + + + + diff --git a/TransactionProcessor.Mobile/TransactionProcessor.Mobile.csproj b/TransactionProcessor.Mobile/TransactionProcessor.Mobile.csproj index 8d2d85a36..057b8b0b5 100644 --- a/TransactionProcessor.Mobile/TransactionProcessor.Mobile.csproj +++ b/TransactionProcessor.Mobile/TransactionProcessor.Mobile.csproj @@ -152,8 +152,8 @@ - - + + From 52965be5261bb7f3c91c533f9b54e8ac1836cefe Mon Sep 17 00:00:00 2001 From: Stuart Ferguson Date: Wed, 13 May 2026 20:02:42 +0100 Subject: [PATCH 02/11] Add JSON serialization infrastructure and update dependencies Implemented flexible JSON serialization with SystemTextJsonSerializer and supporting helpers. Registered serialization services in DI. Upgraded Microsoft.Maui.Controls packages to 10.0.20 and cleaned up project references. Disabled Shell flyout in AppShell.xaml. --- .../Serialisation/Class1.cs | 399 ++++++++++++++++++ TransactionProcessor.Mobile/AppShell.xaml | 1 + .../Extensions/MauiAppBuilderExtensions.cs | 17 +- .../TransactionProcessor.Mobile.csproj | 10 +- 4 files changed, 412 insertions(+), 15 deletions(-) create mode 100644 TransactionProcessor.Mobile.BusinessLogic/Serialisation/Class1.cs diff --git a/TransactionProcessor.Mobile.BusinessLogic/Serialisation/Class1.cs b/TransactionProcessor.Mobile.BusinessLogic/Serialisation/Class1.cs new file mode 100644 index 000000000..d739c3c12 --- /dev/null +++ b/TransactionProcessor.Mobile.BusinessLogic/Serialisation/Class1.cs @@ -0,0 +1,399 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq.Expressions; +using System.Text; +using System.Text.Json; +using System.Text.Json.Serialization; +using System.Text.Json.Serialization.Metadata; + +namespace TransactionProcessor.Mobile.BusinessLogic.Serialisation +{ + public static class ExpressionHelpers + { + public static string GetPropertyName(Expression> expression) + { + if (expression.Body is MemberExpression member) + return member.Member.Name; + + if (expression.Body is UnaryExpression unary && unary.Operand is MemberExpression unaryMember) + return unaryMember.Member.Name; + + throw new ArgumentException("Expression must be a property access", nameof(expression)); + } + } + + public static class Extensions + { + public static JsonSerializerOptions AddModifier( + this JsonSerializerOptions options, + Action modifier) + { + if (options.TypeInfoResolver is not DefaultJsonTypeInfoResolver resolver) + throw new InvalidOperationException("TypeInfoResolver must be DefaultJsonTypeInfoResolver"); + + resolver.Modifiers.Add(modifier); + return options; + } + } + + public static class JsonTypeInfoExtensions + { + public static void IgnoreProperty( + this JsonTypeInfo typeInfo, + Expression> selector) + { + var name = ExpressionHelpers.GetPropertyName(selector); + + var prop = typeInfo.Properties.FirstOrDefault(p => + string.Equals(p.Name, name, StringComparison.OrdinalIgnoreCase)); + + if (prop != null) + { + prop.ShouldSerialize = (_, _) => false; + } + } + + public static void RenameProperty( + this JsonTypeInfo typeInfo, + Expression> selector, + string newName) + { + var name = ExpressionHelpers.GetPropertyName(selector); + + var prop = typeInfo.Properties.FirstOrDefault(p => + string.Equals(p.Name, name, StringComparison.OrdinalIgnoreCase)); + + if (prop != null) + { + prop.Name = newName; + } + } + } + + public static class JsonTypeInfoModifierExtensions + { + /// + /// Apply a modifier only to a specific type T + /// + public static Action ForType(Action modifier) + { + return typeInfo => + { + if (typeInfo.Type == typeof(T)) + { + modifier(typeInfo); + } + }; + } + + /// + /// Apply a modifier to multiple specific types + /// + public static Action ForTypes(IEnumerable types, Action modifier) + { + var set = new HashSet(types); + + return typeInfo => + { + if (set.Contains(typeInfo.Type)) + { + modifier(typeInfo); + } + }; + } + + /// + /// Apply a modifier to a type and all types assignable to it (base class / interface) + /// + public static Action ForAssignableTo(Action modifier) + { + return typeInfo => + { + if (typeof(TBase).IsAssignableFrom(typeInfo.Type)) + { + modifier(typeInfo); + } + }; + } + + /// + /// Combine multiple modifiers into one + /// + public static Action Combine(params Action[] modifiers) + { + return typeInfo => + { + foreach (var modifier in modifiers) + { + modifier(typeInfo); + } + }; + } + } + + public enum SerialiserPropertyFormat + { + CamelCase, + SnakeCase, + CamelCaseUpper, + KebabCase, + KeabCaseUpper, + } + public record SerialiserOptions(SerialiserPropertyFormat PropertyFormat, Boolean IgnoreNullValues = true, Boolean WriteIndented = false); + + public interface IStringSerialiser + { + string Serialize(T obj, SerialiserOptions serialiserOptions = null); + T Deserialize(string json, SerialiserOptions serialiserOptions = null); + + T DeserializeAnonymousType(string json, + T anonymousTypeObject, SerialiserOptions serialiserOptions = null); + + T DeserializeObject(string json, Type type, SerialiserOptions serialiserOptions = null); + + T? GetValue(string json, string propertyName); + } + + public class SystemTextJsonSerializer : IStringSerialiser + { + private readonly JsonSerializerOptions Options; + + public static JsonSerializerOptions GetDefaultJsonSerializerOptions() + { + JsonSerializerOptions options = new JsonSerializerOptions() + { + DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefault, + PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower, + WriteIndented = true, + NumberHandling = JsonNumberHandling.AllowReadingFromString, + TypeInfoResolver = new DefaultJsonTypeInfoResolver + { + Modifiers = { + typeInfo => { + String[] names = new[] { "AggregateId", "AggregateVersion", "EventId", "EventNumber", "EventTimestamp", "EventType" }; + List matches = typeInfo.Properties.Where(p => names.Any(n => string.Equals(p.Name, n, StringComparison.OrdinalIgnoreCase))).ToList(); + + foreach (JsonPropertyInfo match in matches) { + match.ShouldSerialize = (_, + _) => false; + } + } + } + } + }; + options.Converters.Add(new DateTimeSpaceConverter()); + + return options; + } + + public SystemTextJsonSerializer(JsonSerializerOptions options) + { + Options = options; + } + + private JsonSerializerOptions BuildSerialiserOptions(SerialiserOptions serialiserOptions) + { + if (serialiserOptions == null) + { + return Options; + } + + var options = new JsonSerializerOptions(Options); + if (serialiserOptions.IgnoreNullValues) + { + options.DefaultIgnoreCondition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull; + } + if (serialiserOptions.WriteIndented) + { + options.WriteIndented = true; + } + options.PropertyNamingPolicy = serialiserOptions.PropertyFormat switch + { + SerialiserPropertyFormat.CamelCase => JsonNamingPolicy.CamelCase, + SerialiserPropertyFormat.SnakeCase => JsonNamingPolicy.SnakeCaseLower, + SerialiserPropertyFormat.CamelCaseUpper => JsonNamingPolicy.SnakeCaseUpper, + SerialiserPropertyFormat.KebabCase => JsonNamingPolicy.KebabCaseLower, + SerialiserPropertyFormat.KeabCaseUpper => JsonNamingPolicy.KebabCaseUpper, + _ => options.PropertyNamingPolicy + }; + return options; + } + + public string Serialize(T obj, SerialiserOptions serialiserOptions = null) + { + + var options = BuildSerialiserOptions(serialiserOptions); + return obj is null + ? JsonSerializer.Serialize(obj, options) + : JsonSerializer.Serialize(obj, obj.GetType(), options); + } + + public T Deserialize(string json, SerialiserOptions serialiserOptions = null) + { + var options = BuildSerialiserOptions(serialiserOptions); + return JsonSerializer.Deserialize(json, options)!; + } + + public T DeserializeAnonymousType(String json, + T anonymousTypeObject, SerialiserOptions serialiserOptions = null) + { + var options = BuildSerialiserOptions(serialiserOptions); + return JsonSerializer.Deserialize(json, options)!; + } + + public T DeserializeObject(String json, + Type type, SerialiserOptions serialiserOptions = null) + { + var options = BuildSerialiserOptions(serialiserOptions); + return (T)JsonSerializer.Deserialize(json, type, options)!; + } + + public T GetValue(String json, + String propertyName) + { + using var doc = JsonDocument.Parse(json); + var _root = doc.RootElement.Clone(); // important to avoid disposed doc issues + + if (TryFindProperty(_root, propertyName, out var value)) + { + try + { + return value.Deserialize(); + } + catch + { + return default; + } + } + + return default; + } + + private static bool TryFindProperty( + JsonElement element, + string propertyName, + out JsonElement found) + { + switch (element.ValueKind) + { + case JsonValueKind.Object: + foreach (var prop in element.EnumerateObject()) + { + if (string.Equals(prop.Name, propertyName, StringComparison.OrdinalIgnoreCase)) + { + found = prop.Value; + return true; + } + + if (TryFindProperty(prop.Value, propertyName, out found)) + return true; + } + break; + + case JsonValueKind.Array: + foreach (var item in element.EnumerateArray()) + { + if (TryFindProperty(item, propertyName, out found)) + return true; + } + break; + default: + found = default; + return false; + break; + } + + found = default; + return false; + } + } + + public static class StringSerialiser + { + private const String NotInitialisedErrorMessage = "StringSerialiser is not initialised."; + public static Boolean IsInitialised { get; set; } + private static IStringSerialiser Serializer; + + public static void Initialise(IStringSerialiser serialiser) + { + Serializer = serialiser; + IsInitialised = true; + } + + public static string Serialise(T obj, SerialiserOptions serialiserOptions = null) + { + if (!IsInitialised) throw new InvalidOperationException(NotInitialisedErrorMessage); + return Serializer.Serialize(obj, serialiserOptions); + } + + public static T Deserialise(string json, SerialiserOptions serialiserOptions = null) + { + if (!IsInitialised) throw new InvalidOperationException(NotInitialisedErrorMessage); + return Serializer.Deserialize(json, serialiserOptions); + } + + public static T DeserialiseAnonymousType(String json, T anonymousTypeObject, SerialiserOptions serialiserOptions = null) + { + if (!IsInitialised) throw new InvalidOperationException(NotInitialisedErrorMessage); + return Serializer.DeserializeAnonymousType(json, anonymousTypeObject, serialiserOptions); + } + + public static T DeserializeObject(String json, Type type, SerialiserOptions serialiserOptions = null) + { + if (!IsInitialised) throw new InvalidOperationException(NotInitialisedErrorMessage); + return Serializer.DeserializeObject(json, type, serialiserOptions); + } + + public static T GetValue(String json, String propertyName, SerialiserOptions serialiserOptions = null) + { + if (!IsInitialised) throw new InvalidOperationException(NotInitialisedErrorMessage); + return Serializer.GetValue(json, propertyName); + } + } + + public class DateTimeSpaceConverter : JsonConverter + { + private static readonly string[] AcceptedFormats = new[] { + "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd H:mm:ss", "yyyy-MM-ddTHH:mm:ss", "yyyy-MM-ddTHH:mm:ss.FFFFFFFK", "o" // ISO 8601 round-trip + }; + public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + if (reader.TokenType == JsonTokenType.Null) + { + return default; + } + + if (reader.TokenType == JsonTokenType.String) + { + var s = reader.GetString(); + if (string.IsNullOrWhiteSpace(s)) + return default; + + // Try exact known formats first (handles "2026-05-07 06:03:18") + if (DateTime.TryParseExact(s, AcceptedFormats, CultureInfo.InvariantCulture, DateTimeStyles.AssumeLocal | DateTimeStyles.AllowWhiteSpaces, out var dtExact)) + return dtExact; + + // Fall back to general parse + if (DateTime.TryParse(s, CultureInfo.InvariantCulture, DateTimeStyles.AssumeLocal, out var dt)) + return dt; + + throw new JsonException($"Unable to parse DateTime: '{s}'."); + } + + // If JSON contains a number, attempt to treat it as Unix seconds (optional) + if (reader.TokenType == JsonTokenType.Number && reader.TryGetInt64(out long seconds)) + { + return DateTimeOffset.FromUnixTimeSeconds(seconds).LocalDateTime; + } + + throw new JsonException($"Unexpected token parsing DateTime. Token: {reader.TokenType}"); + } + + public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options) + { + // Write in the same "space" format so round-trip matches your input + writer.WriteStringValue(value.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture)); + } + } +} diff --git a/TransactionProcessor.Mobile/AppShell.xaml b/TransactionProcessor.Mobile/AppShell.xaml index 30490d028..f3e436969 100644 --- a/TransactionProcessor.Mobile/AppShell.xaml +++ b/TransactionProcessor.Mobile/AppShell.xaml @@ -11,6 +11,7 @@ xmlns:myAccount="clr-namespace:TransactionProcessor.Mobile.Pages.MyAccount" xmlns:support="clr-namespace:TransactionProcessor.Mobile.Pages.Support" Title="TransactionProcessor.Mobile" + Shell.FlyoutBehavior="Disabled" Shell.TabBarBackgroundColor="{DynamicResource shellTabBarBackgroundColor}" Shell.TabBarForegroundColor="{DynamicResource shellTabBarForegroundColor}" Shell.TabBarTitleColor="{DynamicResource shellTabBarForegroundColor}" diff --git a/TransactionProcessor.Mobile/Extensions/MauiAppBuilderExtensions.cs b/TransactionProcessor.Mobile/Extensions/MauiAppBuilderExtensions.cs index 8fd93c1d7..bbbb3379b 100644 --- a/TransactionProcessor.Mobile/Extensions/MauiAppBuilderExtensions.cs +++ b/TransactionProcessor.Mobile/Extensions/MauiAppBuilderExtensions.cs @@ -1,11 +1,8 @@ using System.Net.Security; using banditoth.MAUI.DeviceId; -using MediatR; using SecurityService.Client; -using SimpleResults; using TransactionMobile.Maui.UIServices; using TransactionProcessor.Mobile.BusinessLogic.Database; -using TransactionProcessor.Mobile.BusinessLogic.Models; using TransactionProcessor.Mobile.BusinessLogic.RequestHandlers; using TransactionProcessor.Mobile.BusinessLogic.Services; using TransactionProcessor.Mobile.BusinessLogic.Services.TrainingModeServices; @@ -26,10 +23,8 @@ using TransactionProcessor.Mobile.Pages.Transactions.BillPayment; using TransactionProcessor.Mobile.Pages.Transactions.MobileTopup; using TransactionProcessor.Mobile.Pages.Transactions.Voucher; -//using TransactionProcessor.Mobile.Platforms.Android; using TransactionProcessor.Mobile.UIServices; -using LogMessage = TransactionProcessor.Mobile.BusinessLogic.Models.LogMessage; -using ClientProxyBase; +using TransactionProcessor.Mobile.BusinessLogic.Serialisation; #if ANDROID @@ -94,7 +89,15 @@ public static MauiAppBuilder ConfigureAppServices(this MauiAppBuilder builder) { builder.Services.RegisterHttpClientX(); builder.Services.AddSingleton(); - builder.ConfigureDeviceIdProvider(); + builder.Services.AddSingleton(); + builder.Services.AddSingleton>(_ => obj => StringSerialiser.Serialise(obj)); + builder.Services.AddSingleton>(_ => (str, type) => StringSerialiser.DeserializeObject(str, type)); + + var serialiserSettings = SystemTextJsonSerializer.GetDefaultJsonSerializerOptions(); + + builder.Services.AddSingleton(serialiserSettings); + + builder.ConfigureDeviceIdProvider(); return builder; } diff --git a/TransactionProcessor.Mobile/TransactionProcessor.Mobile.csproj b/TransactionProcessor.Mobile/TransactionProcessor.Mobile.csproj index 057b8b0b5..53cec3c3c 100644 --- a/TransactionProcessor.Mobile/TransactionProcessor.Mobile.csproj +++ b/TransactionProcessor.Mobile/TransactionProcessor.Mobile.csproj @@ -151,11 +151,9 @@ - - - - + + @@ -163,10 +161,6 @@ - - - - ANDROID From fb65604c515bde56ae5ece6963335b73843fe0f0 Mon Sep 17 00:00:00 2001 From: Stuart Ferguson Date: Thu, 14 May 2026 01:56:34 +0100 Subject: [PATCH 03/11] Refactor: replace Shared.Serialisation with local implementation Removed all usages of Shared.Serialisation in favor of TransactionProcessor.Mobile.BusinessLogic.Serialisation. Updated using directives throughout source and test files. Removed Shared package from project dependencies, retaining Shared.Results where required. No functional changes; dependency and namespace cleanup only. --- .../RequestHandlerTests/TransactionRequestHandlerTests.cs | 2 +- .../ServicesTests/ConfigurationServiceTests.cs | 2 +- .../ServicesTests/MerchantServiceTests.cs | 2 +- .../ServicesTests/TransactionServiceTests.cs | 2 +- .../ServicesTests/UpdateServiceTests.cs | 2 +- .../TransactionProcessor.Mobile.BusinessLogic.Tests.csproj | 4 ---- .../RequestHandlers/TransactionRequestHandler.cs | 2 +- .../Services/AuthenticationService.cs | 2 +- .../Services/ConfigurationService.cs | 2 +- .../Services/MerchantService.cs | 2 +- .../Services/TransactionService.cs | 4 ++-- .../Services/UpdateService.cs | 2 +- .../TransactionProcessor.Mobile.BusinessLogic.csproj | 3 --- .../TransactionProcessor.Mobile.csproj | 1 + 14 files changed, 13 insertions(+), 19 deletions(-) diff --git a/TransactionProcessor.Mobile.BusinessLogic.Tests/RequestHandlerTests/TransactionRequestHandlerTests.cs b/TransactionProcessor.Mobile.BusinessLogic.Tests/RequestHandlerTests/TransactionRequestHandlerTests.cs index 647dc6344..1dd34a34f 100644 --- a/TransactionProcessor.Mobile.BusinessLogic.Tests/RequestHandlerTests/TransactionRequestHandlerTests.cs +++ b/TransactionProcessor.Mobile.BusinessLogic.Tests/RequestHandlerTests/TransactionRequestHandlerTests.cs @@ -1,11 +1,11 @@ using Moq; -using Shared.Serialisation; using Shouldly; using SimpleResults; using TransactionProcessor.Mobile.BusinessLogic.Database; using TransactionProcessor.Mobile.BusinessLogic.Models; using TransactionProcessor.Mobile.BusinessLogic.RequestHandlers; using TransactionProcessor.Mobile.BusinessLogic.Requests; +using TransactionProcessor.Mobile.BusinessLogic.Serialisation; using TransactionProcessor.Mobile.BusinessLogic.Services; using TransactionProcessor.Mobile.BusinessLogic.UIServices; diff --git a/TransactionProcessor.Mobile.BusinessLogic.Tests/ServicesTests/ConfigurationServiceTests.cs b/TransactionProcessor.Mobile.BusinessLogic.Tests/ServicesTests/ConfigurationServiceTests.cs index 0052704da..ee070cd43 100644 --- a/TransactionProcessor.Mobile.BusinessLogic.Tests/ServicesTests/ConfigurationServiceTests.cs +++ b/TransactionProcessor.Mobile.BusinessLogic.Tests/ServicesTests/ConfigurationServiceTests.cs @@ -1,9 +1,9 @@ using RichardSzalay.MockHttp; -using Shared.Serialisation; using Shouldly; using System.Net; using TransactionProcessor.Mobile.BusinessLogic.Logging; using TransactionProcessor.Mobile.BusinessLogic.Models; +using TransactionProcessor.Mobile.BusinessLogic.Serialisation; using TransactionProcessor.Mobile.BusinessLogic.Services; using TransactionProcessor.Mobile.BusinessLogic.Services.DataTransferObjects; diff --git a/TransactionProcessor.Mobile.BusinessLogic.Tests/ServicesTests/MerchantServiceTests.cs b/TransactionProcessor.Mobile.BusinessLogic.Tests/ServicesTests/MerchantServiceTests.cs index e01098faf..7bd51c08d 100644 --- a/TransactionProcessor.Mobile.BusinessLogic.Tests/ServicesTests/MerchantServiceTests.cs +++ b/TransactionProcessor.Mobile.BusinessLogic.Tests/ServicesTests/MerchantServiceTests.cs @@ -1,11 +1,11 @@ using Moq; using RichardSzalay.MockHttp; -using Shared.Serialisation; using Shouldly; using SimpleResults; using System.Net; using TransactionProcessor.Mobile.BusinessLogic.Logging; using TransactionProcessor.Mobile.BusinessLogic.Models; +using TransactionProcessor.Mobile.BusinessLogic.Serialisation; using TransactionProcessor.Mobile.BusinessLogic.Services; using TransactionProcessor.Mobile.BusinessLogic.UIServices; using TransactionProcessorACL.DataTransferObjects.Responses; diff --git a/TransactionProcessor.Mobile.BusinessLogic.Tests/ServicesTests/TransactionServiceTests.cs b/TransactionProcessor.Mobile.BusinessLogic.Tests/ServicesTests/TransactionServiceTests.cs index be71d1b3f..e9247f6b4 100644 --- a/TransactionProcessor.Mobile.BusinessLogic.Tests/ServicesTests/TransactionServiceTests.cs +++ b/TransactionProcessor.Mobile.BusinessLogic.Tests/ServicesTests/TransactionServiceTests.cs @@ -1,12 +1,12 @@ using Moq; using RichardSzalay.MockHttp; -using Shared.Serialisation; using Shouldly; using SimpleResults; using System.Net; using System.Text; using TransactionProcessor.Mobile.BusinessLogic.Logging; using TransactionProcessor.Mobile.BusinessLogic.Models; +using TransactionProcessor.Mobile.BusinessLogic.Serialisation; using TransactionProcessor.Mobile.BusinessLogic.Services; using TransactionProcessorACL.DataTransferObjects.Responses; diff --git a/TransactionProcessor.Mobile.BusinessLogic.Tests/ServicesTests/UpdateServiceTests.cs b/TransactionProcessor.Mobile.BusinessLogic.Tests/ServicesTests/UpdateServiceTests.cs index adf5b159a..223b8ef77 100644 --- a/TransactionProcessor.Mobile.BusinessLogic.Tests/ServicesTests/UpdateServiceTests.cs +++ b/TransactionProcessor.Mobile.BusinessLogic.Tests/ServicesTests/UpdateServiceTests.cs @@ -1,9 +1,9 @@ using RichardSzalay.MockHttp; -using Shared.Serialisation; using Shouldly; using SimpleResults; using TransactionProcessor.Mobile.BusinessLogic.Logging; using TransactionProcessor.Mobile.BusinessLogic.Models; +using TransactionProcessor.Mobile.BusinessLogic.Serialisation; using TransactionProcessor.Mobile.BusinessLogic.Services; namespace TransactionProcessor.Mobile.BusinessLogic.Tests.ServicesTests; diff --git a/TransactionProcessor.Mobile.BusinessLogic.Tests/TransactionProcessor.Mobile.BusinessLogic.Tests.csproj b/TransactionProcessor.Mobile.BusinessLogic.Tests/TransactionProcessor.Mobile.BusinessLogic.Tests.csproj index 65364bcc3..9eb9e1299 100644 --- a/TransactionProcessor.Mobile.BusinessLogic.Tests/TransactionProcessor.Mobile.BusinessLogic.Tests.csproj +++ b/TransactionProcessor.Mobile.BusinessLogic.Tests/TransactionProcessor.Mobile.BusinessLogic.Tests.csproj @@ -25,10 +25,6 @@ runtime; build; native; contentfiles; analyzers; buildtransitive all - - all - - all diff --git a/TransactionProcessor.Mobile.BusinessLogic/RequestHandlers/TransactionRequestHandler.cs b/TransactionProcessor.Mobile.BusinessLogic/RequestHandlers/TransactionRequestHandler.cs index 4ea2f76dc..5968e3975 100644 --- a/TransactionProcessor.Mobile.BusinessLogic/RequestHandlers/TransactionRequestHandler.cs +++ b/TransactionProcessor.Mobile.BusinessLogic/RequestHandlers/TransactionRequestHandler.cs @@ -1,11 +1,11 @@ using MediatR; -using Shared.Serialisation; using SimpleResults; using TransactionProcessor.Mobile.BusinessLogic.Common; using TransactionProcessor.Mobile.BusinessLogic.Database; using TransactionProcessor.Mobile.BusinessLogic.Models; using TransactionProcessor.Mobile.BusinessLogic.Requests; using TransactionProcessor.Mobile.BusinessLogic.Services; +using TransactionProcessor.Mobile.BusinessLogic.Serialisation; using TransactionProcessor.Mobile.BusinessLogic.UIServices; namespace TransactionProcessor.Mobile.BusinessLogic.RequestHandlers; diff --git a/TransactionProcessor.Mobile.BusinessLogic/Services/AuthenticationService.cs b/TransactionProcessor.Mobile.BusinessLogic/Services/AuthenticationService.cs index 62e5547ef..02576301f 100644 --- a/TransactionProcessor.Mobile.BusinessLogic/Services/AuthenticationService.cs +++ b/TransactionProcessor.Mobile.BusinessLogic/Services/AuthenticationService.cs @@ -1,10 +1,10 @@ using SecurityService.Client; using SecurityService.DataTransferObjects; using Shared.Results; -using Shared.Serialisation; using SimpleResults; using TransactionProcessor.Mobile.BusinessLogic.Logging; using TransactionProcessor.Mobile.BusinessLogic.Models; +using TransactionProcessor.Mobile.BusinessLogic.Serialisation; namespace TransactionProcessor.Mobile.BusinessLogic.Services { diff --git a/TransactionProcessor.Mobile.BusinessLogic/Services/ConfigurationService.cs b/TransactionProcessor.Mobile.BusinessLogic/Services/ConfigurationService.cs index fdb32e51f..f8debafc6 100644 --- a/TransactionProcessor.Mobile.BusinessLogic/Services/ConfigurationService.cs +++ b/TransactionProcessor.Mobile.BusinessLogic/Services/ConfigurationService.cs @@ -1,9 +1,9 @@ using System.Text; using Shared.Results; -using Shared.Serialisation; using SimpleResults; using TransactionProcessor.Mobile.BusinessLogic.Logging; using TransactionProcessor.Mobile.BusinessLogic.Models; +using TransactionProcessor.Mobile.BusinessLogic.Serialisation; using TransactionProcessor.Mobile.BusinessLogic.Services.DataTransferObjects; namespace TransactionProcessor.Mobile.BusinessLogic.Services; diff --git a/TransactionProcessor.Mobile.BusinessLogic/Services/MerchantService.cs b/TransactionProcessor.Mobile.BusinessLogic/Services/MerchantService.cs index 7eb573c40..a90adad8c 100644 --- a/TransactionProcessor.Mobile.BusinessLogic/Services/MerchantService.cs +++ b/TransactionProcessor.Mobile.BusinessLogic/Services/MerchantService.cs @@ -1,9 +1,9 @@ using System.Diagnostics.CodeAnalysis; using Shared.Results; -using Shared.Serialisation; using SimpleResults; using TransactionProcessor.Mobile.BusinessLogic.Logging; using TransactionProcessor.Mobile.BusinessLogic.Models; +using TransactionProcessor.Mobile.BusinessLogic.Serialisation; using TransactionProcessor.Mobile.BusinessLogic.UIServices; using TransactionProcessorACL.DataTransferObjects.Responses; using ProductType = TransactionProcessor.Mobile.BusinessLogic.Models.ProductType; diff --git a/TransactionProcessor.Mobile.BusinessLogic/Services/TransactionService.cs b/TransactionProcessor.Mobile.BusinessLogic/Services/TransactionService.cs index 27567bb5a..4fe652161 100644 --- a/TransactionProcessor.Mobile.BusinessLogic/Services/TransactionService.cs +++ b/TransactionProcessor.Mobile.BusinessLogic/Services/TransactionService.cs @@ -1,8 +1,8 @@ -using Shared.Serialisation; -using SimpleResults; +using SimpleResults; using TransactionProcessor.Mobile.BusinessLogic.Common; using TransactionProcessor.Mobile.BusinessLogic.Logging; using TransactionProcessor.Mobile.BusinessLogic.Models; +using TransactionProcessor.Mobile.BusinessLogic.Serialisation; using TransactionProcessorACL.DataTransferObjects; using TransactionProcessorACL.DataTransferObjects.Responses; diff --git a/TransactionProcessor.Mobile.BusinessLogic/Services/UpdateService.cs b/TransactionProcessor.Mobile.BusinessLogic/Services/UpdateService.cs index 708cb547f..de7e3135a 100644 --- a/TransactionProcessor.Mobile.BusinessLogic/Services/UpdateService.cs +++ b/TransactionProcessor.Mobile.BusinessLogic/Services/UpdateService.cs @@ -1,8 +1,8 @@ using Shared.Results; -using Shared.Serialisation; using SimpleResults; using TransactionProcessor.Mobile.BusinessLogic.Logging; using TransactionProcessor.Mobile.BusinessLogic.Models; +using TransactionProcessor.Mobile.BusinessLogic.Serialisation; namespace TransactionProcessor.Mobile.BusinessLogic.Services; diff --git a/TransactionProcessor.Mobile.BusinessLogic/TransactionProcessor.Mobile.BusinessLogic.csproj b/TransactionProcessor.Mobile.BusinessLogic/TransactionProcessor.Mobile.BusinessLogic.csproj index bc5915678..f5dc54271 100644 --- a/TransactionProcessor.Mobile.BusinessLogic/TransactionProcessor.Mobile.BusinessLogic.csproj +++ b/TransactionProcessor.Mobile.BusinessLogic/TransactionProcessor.Mobile.BusinessLogic.csproj @@ -10,9 +10,6 @@ - - all - diff --git a/TransactionProcessor.Mobile/TransactionProcessor.Mobile.csproj b/TransactionProcessor.Mobile/TransactionProcessor.Mobile.csproj index 53cec3c3c..eab23a0cd 100644 --- a/TransactionProcessor.Mobile/TransactionProcessor.Mobile.csproj +++ b/TransactionProcessor.Mobile/TransactionProcessor.Mobile.csproj @@ -155,6 +155,7 @@ + From 77eb27fc6b384eff63b34162aaba48c70f234ae2 Mon Sep 17 00:00:00 2001 From: Stuart Ferguson Date: Thu, 14 May 2026 02:45:35 +0100 Subject: [PATCH 04/11] Initialize StringSerialiser and add debug config code Added initialization of StringSerialiser with DI in MauiProgram. Included commented-out hardcoded Configuration in ConfigurationService for debugging. Added missing using directive for serialisation. --- .../Services/ConfigurationService.cs | 11 +++++++++++ TransactionProcessor.Mobile/MauiProgram.cs | 4 ++++ 2 files changed, 15 insertions(+) diff --git a/TransactionProcessor.Mobile.BusinessLogic/Services/ConfigurationService.cs b/TransactionProcessor.Mobile.BusinessLogic/Services/ConfigurationService.cs index f8debafc6..101d9ce0d 100644 --- a/TransactionProcessor.Mobile.BusinessLogic/Services/ConfigurationService.cs +++ b/TransactionProcessor.Mobile.BusinessLogic/Services/ConfigurationService.cs @@ -66,6 +66,17 @@ public async Task> GetConfiguration(String deviceIdentifie if (apiResponse.IsFailed) return ResultHelpers.CreateFailure(apiResponse); + //response = new Configuration { + // ApplicationUpdateUri = "", + // ClientId = "mobileAppClient", + // ClientSecret = "d192cbc46d834d0da90e8a9d50ded543", + // EnableAutoUpdates = false, + // LogLevel = LogLevel.Debug, + // SecurityServiceUri = "https://127.0.0.1:5001", + // TransactionProcessorAclUri = "https://127.0.0.1:5003", + //}; + //return response; + Logger.LogDebug($"About to build Configuration"); response = new Configuration() { ClientSecret = apiResponse.Data.ClientSecret, diff --git a/TransactionProcessor.Mobile/MauiProgram.cs b/TransactionProcessor.Mobile/MauiProgram.cs index 2013cef1e..4218e814e 100644 --- a/TransactionProcessor.Mobile/MauiProgram.cs +++ b/TransactionProcessor.Mobile/MauiProgram.cs @@ -8,6 +8,7 @@ using TransactionProcessor.Mobile.Extensions; using TransactionProcessor.Mobile.UIServices; using Microsoft.Extensions.DependencyInjection; +using TransactionProcessor.Mobile.BusinessLogic.Serialisation; namespace TransactionProcessor.Mobile { @@ -34,6 +35,9 @@ public static MauiApp CreateMauiApp() Container = builder.Build(); + var serialiser = Container.Services.GetRequiredService(); + StringSerialiser.Initialise(serialiser); + Logger.Initialise(new ConsoleLogger()); return Container; From 6d17413ab6d037b84a432cbc3b17bb6dc23f5fcb Mon Sep 17 00:00:00 2001 From: StuartFerguson Date: Thu, 14 May 2026 16:00:42 +0100 Subject: [PATCH 05/11] Update android_e2e_tests.yml --- .github/workflows/android_e2e_tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/android_e2e_tests.yml b/.github/workflows/android_e2e_tests.yml index 974378f29..7c7327dde 100644 --- a/.github/workflows/android_e2e_tests.yml +++ b/.github/workflows/android_e2e_tests.yml @@ -162,7 +162,7 @@ jobs: uses: actions/upload-artifact@v4 with: name: android-e2e_tests - path: /home/txnproc/trace/ + path: /home/runner/trace/ - name: Upload Appium Logs on Failure if: always() From 8b6d1af598890b92b9ce5458325e6c0f89cfaceb Mon Sep 17 00:00:00 2001 From: Stuart Ferguson Date: Thu, 14 May 2026 18:07:22 +0100 Subject: [PATCH 06/11] ... --- .github/workflows/android_e2e_tests.yml | 2 +- .github/workflows/windows_e2e_tests.yml | 2 +- .../TransactionRequestHandler.cs | 2 +- .../Services/ConfigurationService.cs | 9 +++++---- .../Steps/SharedSteps.cs | 18 +++++++++--------- 5 files changed, 17 insertions(+), 16 deletions(-) diff --git a/.github/workflows/android_e2e_tests.yml b/.github/workflows/android_e2e_tests.yml index 974378f29..7c7327dde 100644 --- a/.github/workflows/android_e2e_tests.yml +++ b/.github/workflows/android_e2e_tests.yml @@ -162,7 +162,7 @@ jobs: uses: actions/upload-artifact@v4 with: name: android-e2e_tests - path: /home/txnproc/trace/ + path: /home/runner/trace/ - name: Upload Appium Logs on Failure if: always() diff --git a/.github/workflows/windows_e2e_tests.yml b/.github/workflows/windows_e2e_tests.yml index 947ebdb73..c5d6c001a 100644 --- a/.github/workflows/windows_e2e_tests.yml +++ b/.github/workflows/windows_e2e_tests.yml @@ -63,7 +63,7 @@ jobs: uses: actions/upload-artifact@v4 with: name: windows-e2e_tests - path: C:\\Users\\runneradmin\\txnproc + path: C:\\Users\\runneradmin\\runner - name: Upload Appium Logs on Failure if: always() diff --git a/TransactionProcessor.Mobile.BusinessLogic/RequestHandlers/TransactionRequestHandler.cs b/TransactionProcessor.Mobile.BusinessLogic/RequestHandlers/TransactionRequestHandler.cs index 5968e3975..b19f3cb75 100644 --- a/TransactionProcessor.Mobile.BusinessLogic/RequestHandlers/TransactionRequestHandler.cs +++ b/TransactionProcessor.Mobile.BusinessLogic/RequestHandlers/TransactionRequestHandler.cs @@ -113,7 +113,7 @@ public async Task> Handle(TransactionCommands. TransactionDateTime = request.TransactionDateTime, TransactionNumber = transaction.transactionNumber.ToString(), DeviceIdentifier = this.DeviceService.GetIdentifier(), - ApplicationVersion = this.ApplicationInfoService.VersionString + ApplicationVersion = "1.0.5"//this.ApplicationInfoService.VersionString }; Result result = await transactionService.PerformLogon(model, cancellationToken); diff --git a/TransactionProcessor.Mobile.BusinessLogic/Services/ConfigurationService.cs b/TransactionProcessor.Mobile.BusinessLogic/Services/ConfigurationService.cs index 101d9ce0d..7d7f34b56 100644 --- a/TransactionProcessor.Mobile.BusinessLogic/Services/ConfigurationService.cs +++ b/TransactionProcessor.Mobile.BusinessLogic/Services/ConfigurationService.cs @@ -66,17 +66,18 @@ public async Task> GetConfiguration(String deviceIdentifie if (apiResponse.IsFailed) return ResultHelpers.CreateFailure(apiResponse); - //response = new Configuration { + //response = new Configuration + //{ // ApplicationUpdateUri = "", // ClientId = "mobileAppClient", // ClientSecret = "d192cbc46d834d0da90e8a9d50ded543", // EnableAutoUpdates = false, // LogLevel = LogLevel.Debug, - // SecurityServiceUri = "https://127.0.0.1:5001", - // TransactionProcessorAclUri = "https://127.0.0.1:5003", + // SecurityServiceUri = "https://192.168.1.86:5001", + // TransactionProcessorAclUri = "http://192.168.1.86:5003", //}; //return response; - + Logger.LogDebug($"Configuration Response is {StringSerialiser.Serialise(apiResponse.Data)}"); Logger.LogDebug($"About to build Configuration"); response = new Configuration() { ClientSecret = apiResponse.Data.ClientSecret, diff --git a/TransactionProcessor.Mobile.UITests/Steps/SharedSteps.cs b/TransactionProcessor.Mobile.UITests/Steps/SharedSteps.cs index dec208ac8..7b70b28f2 100644 --- a/TransactionProcessor.Mobile.UITests/Steps/SharedSteps.cs +++ b/TransactionProcessor.Mobile.UITests/Steps/SharedSteps.cs @@ -201,22 +201,22 @@ public async Task GivenIHaveCreatedAConfigForMyDevice() { ClientDetails clientDetails = this.TestingContext.GetClientDetails("mobileAppClient"); //ClientDetails clientDetails = ClientDetails.Create("clientId-mobileAppClient", "secret-mobile", new List()); var configRequest = new { - clientId = clientDetails.ClientId, - clientSecret = clientDetails.ClientSecret, - deviceIdentifier = deviceSerial, + client_id = clientDetails.ClientId, + client_secret = clientDetails.ClientSecret, + device_identifier = deviceSerial, id = deviceSerial, - enableAutoUpdates = false, - logLevel = 3, - hostAddresses = new List() + enable_auto_updates = false, + log_level = 3, + host_addresses = new List() }; - configRequest.hostAddresses.Add(new + configRequest.host_addresses.Add(new { servicetype = 1, uri = this.TestingContext.DockerHelper.SecurityServiceBaseAddressResolver("").Replace("127.0.0.1", this.TestingContext.DockerHelper.LocalIPAddress) }); - configRequest.hostAddresses.Add(new + configRequest.host_addresses.Add(new { - servicetype = 2, + service_type = 2, uri = this.TestingContext.DockerHelper.TransactionProcessorAclBaseAddressResolver("").Replace("127.0.0.1", this.TestingContext.DockerHelper.LocalIPAddress) }); From 8b9541a9150890d8a2347debce411b8768d4797d Mon Sep 17 00:00:00 2001 From: Stuart Ferguson Date: Thu, 14 May 2026 18:48:36 +0100 Subject: [PATCH 07/11] more token debug --- .../ViewModels/LoginPageViewModel.cs | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/TransactionProcessor.Mobile.BusinessLogic/ViewModels/LoginPageViewModel.cs b/TransactionProcessor.Mobile.BusinessLogic/ViewModels/LoginPageViewModel.cs index cec32e585..2def2f1c5 100644 --- a/TransactionProcessor.Mobile.BusinessLogic/ViewModels/LoginPageViewModel.cs +++ b/TransactionProcessor.Mobile.BusinessLogic/ViewModels/LoginPageViewModel.cs @@ -1,8 +1,10 @@ using CommunityToolkit.Mvvm.Input; using MediatR; using Microsoft.Extensions.Caching.Memory; +using Microsoft.Extensions.Logging; using Microsoft.Extensions.Primitives; using MvvmHelpers.Commands; +using Newtonsoft.Json.Linq; using SimpleResults; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; @@ -110,12 +112,33 @@ private async Task> GetUserToken() { if (tokenResult.IsSuccess) { // Cache the token + int index = 1; + foreach (var chunk in SplitToken(tokenResult.Data.AccessToken, 50)) + { + Logger.LogInformation($"JWT Chunk {index++}: {chunk}"); + } + + this.CacheAccessToken(tokenResult.Data); } return tokenResult; } + public static IEnumerable SplitToken(string token, int chunkSize = 100) + { + if (string.IsNullOrWhiteSpace(token)) + yield break; + + if (chunkSize <= 0) + throw new ArgumentOutOfRangeException(nameof(chunkSize)); + + for (int i = 0; i < token.Length; i += chunkSize) + { + yield return token.Substring(i, Math.Min(chunkSize, token.Length - i)); + } + } + private async Task> PerformLogonTransaction() { // Logon Transaction TransactionCommands.PerformLogonCommand command = new(DateTime.Now); From bbd4ff982a57870dca34c678d3bb7eb82dbcda51 Mon Sep 17 00:00:00 2001 From: Stuart Ferguson Date: Thu, 14 May 2026 19:24:01 +0100 Subject: [PATCH 08/11] not sendint token for contract request :| --- .../Services/MerchantService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/TransactionProcessor.Mobile.BusinessLogic/Services/MerchantService.cs b/TransactionProcessor.Mobile.BusinessLogic/Services/MerchantService.cs index a90adad8c..de239fbf3 100644 --- a/TransactionProcessor.Mobile.BusinessLogic/Services/MerchantService.cs +++ b/TransactionProcessor.Mobile.BusinessLogic/Services/MerchantService.cs @@ -70,7 +70,7 @@ public async Task>> GetContractProducts(Cancel Logger.LogInformation("About to request merchant contracts"); Logger.LogDebug($"Merchant Contract Request details: Access Token {accessToken.AccessToken}"); - Result>? responseDataResult = await this.Get>(requestUri, cancellationToken); + Result>? responseDataResult = await this.Get>(requestUri, accessToken.AccessToken, cancellationToken); if (responseDataResult.IsFailed) { Logger.LogInformation($"GetMerchantContracts failed {responseDataResult.Status}"); From 581b87d4ed627e9b91dc7efe8fb42ed398a0474c Mon Sep 17 00:00:00 2001 From: Stuart Ferguson Date: Thu, 14 May 2026 19:24:44 +0100 Subject: [PATCH 09/11] :| --- .../Services/MerchantService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/TransactionProcessor.Mobile.BusinessLogic/Services/MerchantService.cs b/TransactionProcessor.Mobile.BusinessLogic/Services/MerchantService.cs index de239fbf3..d01cacf5b 100644 --- a/TransactionProcessor.Mobile.BusinessLogic/Services/MerchantService.cs +++ b/TransactionProcessor.Mobile.BusinessLogic/Services/MerchantService.cs @@ -153,7 +153,7 @@ public async Task> GetMerchantDetails(CancellationT ////ResponseData responseData = this.HandleResponseContent(content.Data); //MerchantResponse responseData = JsonConvert.DeserializeObject(content.Data); - Result? responseDataResult = await this.Get(requestUri, cancellationToken); + Result? responseDataResult = await this.Get(requestUri, accessToken.AccessToken, cancellationToken); if (responseDataResult.IsFailed) { From 12c4658418c5ceaceac3d21919ddcfce4e411954 Mon Sep 17 00:00:00 2001 From: Stuart Ferguson Date: Thu, 14 May 2026 20:20:05 +0100 Subject: [PATCH 10/11] another crime i think --- .../Steps/SharedSteps.cs | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/TransactionProcessor.Mobile.UITests/Steps/SharedSteps.cs b/TransactionProcessor.Mobile.UITests/Steps/SharedSteps.cs index 7b70b28f2..1f2da0874 100644 --- a/TransactionProcessor.Mobile.UITests/Steps/SharedSteps.cs +++ b/TransactionProcessor.Mobile.UITests/Steps/SharedSteps.cs @@ -342,7 +342,25 @@ public async Task GivenTheFollowingUsersAreAvailableAtThePataPawaPrePayHost(Data public async Task GivenTheFollowingMetersAreAvailableAtThePataPawaPrePayHost(DataTable table) { List meters = table.Rows.ToPataPawaMeters(); - await this.TransactionProcessorSteps.GivenTheFollowingMetersAreAvailableAtThePataPawaPrePaidHost(meters); + await this.GivenTheFollowingMetersAreAvailableAtThePataPawaPrePaidHost(meters); + } + + public async Task GivenTheFollowingMetersAreAvailableAtThePataPawaPrePaidHost(List meters) + { + await this.SendRequestToTestHost(meters, "/api/developer/patapawaprepay/createmeter"); + } + + public async Task SendRequestToTestHost(List objects, String url) + { + foreach (T o in objects) + { + HttpRequestMessage httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, url); + + httpRequestMessage.Content = new StringContent(StringSerialiser.Serialise(o, new SerialiserOptions(SerialiserPropertyFormat.CamelCase)), Encoding.UTF8, "application/json"); + + HttpResponseMessage response = await this.TestingContext.DockerHelper.TestHostHttpClient.SendAsync(httpRequestMessage); + response.StatusCode.ShouldBe(HttpStatusCode.OK); + } } } } From 60219e56d056399ab59f1d7691e45c3c61d452c1 Mon Sep 17 00:00:00 2001 From: Stuart Ferguson Date: Fri, 15 May 2026 10:44:43 +0100 Subject: [PATCH 11/11] .. --- .../ViewModels/LoginPageViewModel.cs | 23 +------------------ 1 file changed, 1 insertion(+), 22 deletions(-) diff --git a/TransactionProcessor.Mobile.BusinessLogic/ViewModels/LoginPageViewModel.cs b/TransactionProcessor.Mobile.BusinessLogic/ViewModels/LoginPageViewModel.cs index 2def2f1c5..b565d1f10 100644 --- a/TransactionProcessor.Mobile.BusinessLogic/ViewModels/LoginPageViewModel.cs +++ b/TransactionProcessor.Mobile.BusinessLogic/ViewModels/LoginPageViewModel.cs @@ -112,33 +112,12 @@ private async Task> GetUserToken() { if (tokenResult.IsSuccess) { // Cache the token - int index = 1; - foreach (var chunk in SplitToken(tokenResult.Data.AccessToken, 50)) - { - Logger.LogInformation($"JWT Chunk {index++}: {chunk}"); - } - - this.CacheAccessToken(tokenResult.Data); } return tokenResult; } - - public static IEnumerable SplitToken(string token, int chunkSize = 100) - { - if (string.IsNullOrWhiteSpace(token)) - yield break; - - if (chunkSize <= 0) - throw new ArgumentOutOfRangeException(nameof(chunkSize)); - - for (int i = 0; i < token.Length; i += chunkSize) - { - yield return token.Substring(i, Math.Min(chunkSize, token.Length - i)); - } - } - + private async Task> PerformLogonTransaction() { // Logon Transaction TransactionCommands.PerformLogonCommand command = new(DateTime.Now);