From f6d744495849e86adc29fbcd8da506bc20727e00 Mon Sep 17 00:00:00 2001 From: Loretta Date: Fri, 21 Jun 2024 14:32:04 +0200 Subject: [PATCH] multiple signalr param; improvements, fixes, etc.. --- TIAM.Database/DataLayers/Admins/AdminDal.cs | 1 + TIAM.Services/SignalRTags.cs | 12 +- .../AddressDetailGridComponent.razor | 36 +- .../User/SysAdmins/ManageTransfers.razor | 2 +- .../ServiceProviderGridComponent.razor | 3 +- .../Shared/Components/Grids/TiamGrid.cs | 8 +- .../Shared/SignalRTransferCrudTags.cs | 23 + .../ServiceProviderAPIController.cs | 1 + .../Controllers/TransferDataAPIController.cs | 29 +- .../Server/Properties/launchSettings.json | 78 +- .../Server/Services/DevAdminSignalRhub.cs | 34 +- .../Server/TIAMWebApp.Server.csproj.user | 3 + TIAMWebApp/Shared/Models/APIUrls.cs | 55 +- .../Shared/Services/AcSignalRClientBase.cs | 251 ---- .../Shared/Services/AdminSignalRClient.cs | 17 + .../Services/ServiceProviderDataService.cs | 6 +- .../TIAMWebApp.Shared.Application.csproj | 4 + .../Utility/SignaRClientLogItemWriter.cs | 5 +- .../Shared/Utility/SignalRDataSource.cs | 1018 +---------------- .../Shared/Utility/SignalRDataSourceAsync.cs | 104 -- .../Shared/Utility/TrackingItemHelpers.cs | 47 - .../SignalRClientTest.cs | 88 ++ .../SignalRDataSourceTest.cs | 104 ++ .../Tiam.Services.Client.Tests.csproj | 57 + TourIAmProject.sln | 6 + 25 files changed, 471 insertions(+), 1521 deletions(-) create mode 100644 TIAMSharedUI/Shared/SignalRTransferCrudTags.cs delete mode 100644 TIAMWebApp/Shared/Services/AcSignalRClientBase.cs create mode 100644 TIAMWebApp/Shared/Services/AdminSignalRClient.cs delete mode 100644 TIAMWebApp/Shared/Utility/SignalRDataSourceAsync.cs delete mode 100644 TIAMWebApp/Shared/Utility/TrackingItemHelpers.cs create mode 100644 Tiam.Services.Client.Tests/SignalRClientTest.cs create mode 100644 Tiam.Services.Client.Tests/SignalRDataSourceTest.cs create mode 100644 Tiam.Services.Client.Tests/Tiam.Services.Client.Tests.csproj diff --git a/TIAM.Database/DataLayers/Admins/AdminDal.cs b/TIAM.Database/DataLayers/Admins/AdminDal.cs index 61b7fea7..0c5c2e9d 100644 --- a/TIAM.Database/DataLayers/Admins/AdminDal.cs +++ b/TIAM.Database/DataLayers/Admins/AdminDal.cs @@ -45,6 +45,7 @@ namespace TIAM.Database.DataLayers.Admins public Task> GetTransfersAsync() => SessionAsync(ctx => ctx.GetTransfers().OrderBy(x => x.TransferStatusType).ThenByDescending(x => x.OrderId).ToList()); public Task GetTransfersJsonAsync() => SessionAsync(ctx => ctx.GetTransfers().OrderBy(x => x.TransferStatusType).ThenByDescending(x => x.OrderId).ToJson()); + public Task GetTransfersByUserIdJsonAsync(Guid userId) => SessionAsync(ctx => ctx.GetTransfers().Where(x => x.UserId == userId).OrderBy(x => x.TransferStatusType).ThenByDescending(x => x.OrderId).ToJson()); public string GetTransfersJson() => Session(ctx => ctx.GetTransfers().OrderBy(x => x.TransferStatusType).ThenByDescending(x => x.OrderId).ToJson()); public Transfer? GetTransferById(Guid transferId) => Session(ctx => ctx.GetTransferById(transferId)); public string? GetTransferJsonById(Guid transferId) => Session(ctx => ctx.GetTransferById(transferId)?.ToJson()); diff --git a/TIAM.Services/SignalRTags.cs b/TIAM.Services/SignalRTags.cs index 684bfbd6..c877ae1e 100644 --- a/TIAM.Services/SignalRTags.cs +++ b/TIAM.Services/SignalRTags.cs @@ -4,11 +4,13 @@ namespace TIAM.Services; public class SignalRTags : AcSignalRTags { - public const int None = 0; - - public const int GetTransfer = 3; - public const int GetTransfers = 4; - public const int GetTransfersByContextId = 5; + public const int GetTransfer = 1; + public const int GetTransfers = 2; + public const int GetTransfersByUserId = 3; + public const int GetTransfersByDriverId = 4; + public const int GetTransfersByProductId = 5; + public const int GetTransfersByCompanyId = 6; + public const int UpdateTransfer = 7; public const int AddTransfer = 8; public const int RemoveTransfer = 9; diff --git a/TIAMSharedUI/Pages/User/SysAdmins/AddressDetailGridComponent.razor b/TIAMSharedUI/Pages/User/SysAdmins/AddressDetailGridComponent.razor index 3a092984..1b407469 100644 --- a/TIAMSharedUI/Pages/User/SysAdmins/AddressDetailGridComponent.razor +++ b/TIAMSharedUI/Pages/User/SysAdmins/AddressDetailGridComponent.razor @@ -16,37 +16,37 @@ @using AyCode.Core @inject IServiceProviderDataService serviceProviderDataService @inject IUserDataService userDataService -@inject ITransferDataService transferDataService +@inject ITransferDataService transferDataService @inject IEnumerable LogWriters @inject AdminSignalRClient AdminSignalRClient; + Logger="_logger" + SignalRClient="AdminSignalRClient" + OnGridEditModelSaving="DataItemSaving" + OnGridItemDeleting="DataItemDeleting" + OnGridItemChanged="DataItemChanged" + PageSize="5" + AutoExpandAllGroupRows="true" + KeyboardNavigationEnabled="KeyboardNavigationEnabled" + KeyFieldName="Id" + ValidationEnabled="false" + EditMode="GridEditMode.EditForm" + ColumnResizeMode="GridColumnResizeMode.NextColumn" + ShowFilterRow="false"> - - + + - + @{ Address bleh = (Address)context.EditModel; diff --git a/TIAMSharedUI/Pages/User/SysAdmins/ManageTransfers.razor b/TIAMSharedUI/Pages/User/SysAdmins/ManageTransfers.razor index 2a5d97ec..cfaca2b1 100644 --- a/TIAMSharedUI/Pages/User/SysAdmins/ManageTransfers.razor +++ b/TIAMSharedUI/Pages/User/SysAdmins/ManageTransfers.razor @@ -158,7 +158,7 @@ + ContextIds="new[] {((Transfer)context.DataItem).Id}"> diff --git a/TIAMSharedUI/Pages/User/SysAdmins/ServiceProviderGridComponent.razor b/TIAMSharedUI/Pages/User/SysAdmins/ServiceProviderGridComponent.razor index 54fd580e..8393808a 100644 --- a/TIAMSharedUI/Pages/User/SysAdmins/ServiceProviderGridComponent.razor +++ b/TIAMSharedUI/Pages/User/SysAdmins/ServiceProviderGridComponent.razor @@ -74,7 +74,8 @@ { _logger = new LoggerClient(LogWriters.ToArray()); - _detailGridData = UserModelDtoDetail.ServiceProviders ?? new List(); + // ReSharper disable once NullCoalescingConditionIsAlwaysNotNullAccordingToAPIContract + _detailGridData = UserModelDtoDetail.ServiceProviders ?? []; _availableServices = await ServiceProviderDataService.GetServiceProvidersAsync(); _logger.Info($"DetailGridData: {_detailGridData.Count}"); diff --git a/TIAMSharedUI/Shared/Components/Grids/TiamGrid.cs b/TIAMSharedUI/Shared/Components/Grids/TiamGrid.cs index f36fb4b7..bcc2cad2 100644 --- a/TIAMSharedUI/Shared/Components/Grids/TiamGrid.cs +++ b/TIAMSharedUI/Shared/Components/Grids/TiamGrid.cs @@ -1,4 +1,5 @@ using System.ComponentModel; +using AyCode.Blazor.Components.Services; using AyCode.Core; using AyCode.Core.Enums; using AyCode.Core.Extensions; @@ -27,7 +28,7 @@ namespace TIAMSharedUI.Shared.Components.Grids [Parameter] public LoggerClient Logger { get; set; } [Parameter] public string GridName { get; set; } - [Parameter] public Guid? ContextId { get; set; } + [Parameter] public Guid[]? ContextIds { get; set; } [Parameter] public AcSignalRClientBase SignalRClient { get; set; } [Parameter] public int GetAllMessageTag { get; set; } @@ -80,8 +81,8 @@ namespace TIAMSharedUI.Shared.Components.Grids throw new NullReferenceException($"[{GetType().Name}] SignalRClient == null"); } - var crudTags = new SignalRCrudTags(GetAllMessageTag, SignalRTags.None, AddMessageTag, UpdateMessageTag, RemoveMessageTag); - _dataSource = new SignalRDataSource(SignalRClient, crudTags, ContextId); + var crudTags = new SignalRCrudTags(GetAllMessageTag, GetItemMessageTag, AddMessageTag, UpdateMessageTag, RemoveMessageTag); + _dataSource = new SignalRDataSource(SignalRClient, crudTags, ContextIds); Data = _dataSource; @@ -108,6 +109,7 @@ namespace TIAMSharedUI.Shared.Components.Grids Logger.Debug($"{_gridLogName} OnDataSourceLoaded"); Reload(); + _dataSource.LoadItem(_dataSource.First().Id).Forget(); return OnDataSourceChanged.InvokeAsync(_dataSource); } diff --git a/TIAMSharedUI/Shared/SignalRTransferCrudTags.cs b/TIAMSharedUI/Shared/SignalRTransferCrudTags.cs new file mode 100644 index 00000000..05c50f44 --- /dev/null +++ b/TIAMSharedUI/Shared/SignalRTransferCrudTags.cs @@ -0,0 +1,23 @@ +using AyCode.Services.SignalRs; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using TIAM.Services; + +namespace TIAMSharedUI.Shared +{ + public static class SignalRTiamCrudTags + { + public static SignalRCrudTags CompanyCrudTags { get; } = new SignalRCrudTags(SignalRTags.GetCompanies, SignalRTags.GetCompany, SignalRTags.AddCompany, SignalRTags.UpdateCompany, SignalRTags.RemoveCompany); + + #region Transfers + public static SignalRCrudTags TransferCrudTags { get; } = new SignalRCrudTags(SignalRTags.GetTransfers, SignalRTags.GetTransfer, SignalRTags.AddTransfer, SignalRTags.UpdateTransfer, SignalRTags.RemoveTransfer); + public static SignalRCrudTags TransferByUserCrudTags { get; } = new SignalRCrudTags(SignalRTags.GetTransfersByUserId, SignalRTags.GetTransfer, SignalRTags.AddTransfer, SignalRTags.UpdateTransfer, SignalRTags.RemoveTransfer); + public static SignalRCrudTags TransferByDriverCrudTags { get; } = new SignalRCrudTags(SignalRTags.GetTransfersByDriverId, SignalRTags.GetTransfer, SignalRTags.AddTransfer, SignalRTags.UpdateTransfer, SignalRTags.RemoveTransfer); + public static SignalRCrudTags TransferByProductCrudTags { get; } = new SignalRCrudTags(SignalRTags.GetTransfersByProductId, SignalRTags.GetTransfer, SignalRTags.AddTransfer, SignalRTags.UpdateTransfer, SignalRTags.RemoveTransfer); + public static SignalRCrudTags TransferByCompanyCrudTags { get; } = new SignalRCrudTags(SignalRTags.GetTransfersByCompanyId, SignalRTags.GetTransfer, SignalRTags.AddTransfer, SignalRTags.UpdateTransfer, SignalRTags.RemoveTransfer); + #endregion Transfers + } +} diff --git a/TIAMWebApp/Server/Controllers/ServiceProviderAPIController.cs b/TIAMWebApp/Server/Controllers/ServiceProviderAPIController.cs index f1f8419d..524c48ba 100644 --- a/TIAMWebApp/Server/Controllers/ServiceProviderAPIController.cs +++ b/TIAMWebApp/Server/Controllers/ServiceProviderAPIController.cs @@ -111,6 +111,7 @@ namespace TIAMWebApp.Server.Controllers [AllowAnonymous] [HttpPost] [Route(APIUrls.GetServiceProviderByIdRouteName)] + [SignalR(SignalRTags.GetCompany)] public async Task GetServiceProviderById([FromBody] Guid id) { _logger.Info($@"GetServiceProviderById called with id: {id}"); diff --git a/TIAMWebApp/Server/Controllers/TransferDataAPIController.cs b/TIAMWebApp/Server/Controllers/TransferDataAPIController.cs index 433356f9..7cd44cf0 100644 --- a/TIAMWebApp/Server/Controllers/TransferDataAPIController.cs +++ b/TIAMWebApp/Server/Controllers/TransferDataAPIController.cs @@ -393,17 +393,36 @@ namespace TIAMWebApp.Server.Controllers return result; } + [Authorize] + [HttpGet] + [Route(APIUrls.GetTransfersByUserIdRouteName)] + [SignalR(SignalRTags.GetTransfersByUserId)] + public async Task GetTransfersByUserId(Guid userId) + { + var result = await _adminDal.GetTransfersByUserIdJsonAsync(userId); + return result; + } + + [Authorize] + [HttpGet] + [Route(APIUrls.GetTransfersByDriverRouteName)] + [SignalR(SignalRTags.GetTransfersByDriverId)] + public Task GetDriverTransfers(Guid transferId, Guid userProductMappingId) + { + throw new NotImplementedException(); + //var result = await _adminDal.GetTransfersByUserIdJsonAsync(userId); + //return result; + } + [AllowAnonymous] [HttpPost] [Route(APIUrls.GetTransferByIdRouteName)] - public async Task GetTransferById([FromBody] Guid transferId) + [SignalR(SignalRTags.GetTransfer)] + public string? GetTransferById([FromBody] Guid transferId) { _logger.Info($"Get transfer by id called; transferId: {transferId}"); - var result = _adminDal.GetTransferById(transferId); - - //TODO: Implementálni a Logout-ot kliens és szerver oldalon is! - J. - return Ok(result); + return _adminDal.GetTransferJsonById(transferId); } [AllowAnonymous] diff --git a/TIAMWebApp/Server/Properties/launchSettings.json b/TIAMWebApp/Server/Properties/launchSettings.json index 98c9c5c1..46bf9103 100644 --- a/TIAMWebApp/Server/Properties/launchSettings.json +++ b/TIAMWebApp/Server/Properties/launchSettings.json @@ -1,40 +1,50 @@ { - "iisSettings": { - "windowsAuthentication": false, - "anonymousAuthentication": true, - "iisExpress": { - "applicationUrl": "http://localhost:28749", - "sslPort": 44368 - } + "profiles": { + "http": { + "commandName": "Project", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "dotnetRunMessages": true, + "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}", + "applicationUrl": "http://localhost:5175" }, - "profiles": { - "http": { - "commandName": "Project", - "dotnetRunMessages": true, - "launchBrowser": true, - "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}", - "applicationUrl": "http://localhost:5175", - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" - } + "https": { + "commandName": "Project", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" }, - "https": { - "commandName": "Project", - "dotnetRunMessages": true, - "launchBrowser": true, - "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}", - "applicationUrl": "https://localhost:7116;http://localhost:5175", - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" - } + "dotnetRunMessages": true, + "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}", + "applicationUrl": "https://localhost:7116;http://localhost:5175" + }, + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" }, - "IIS Express": { - "commandName": "IISExpress", - "launchBrowser": true, - "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}", - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" - } - } + "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}" + }, + "WSL": { + "commandName": "WSL2", + "launchBrowser": true, + "launchUrl": "https://localhost:7116", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development", + "ASPNETCORE_URLS": "https://localhost:7116;http://localhost:5175" + }, + "distributionName": "" + } + }, + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:28749", + "sslPort": 44368 } } +} \ No newline at end of file diff --git a/TIAMWebApp/Server/Services/DevAdminSignalRhub.cs b/TIAMWebApp/Server/Services/DevAdminSignalRhub.cs index be9b565f..59bc59df 100644 --- a/TIAMWebApp/Server/Services/DevAdminSignalRhub.cs +++ b/TIAMWebApp/Server/Services/DevAdminSignalRhub.cs @@ -48,10 +48,10 @@ public class MethodInfoModel where TAttribute : TagAttribute var parameters = methodInfo.GetParameters(); - if (parameters.Length > 1) - throw new Exception("MethodInfoModel; parameters.Length > 1"); + //if (parameters.Length > 1) + // throw new Exception("MethodInfoModel; parameters.Length > 1"); - if (parameters.Length == 1) + if (parameters.Length > 0) ParameterType = parameters[0].ParameterType; } } @@ -63,10 +63,12 @@ public class DynamicMethodCallModel where TAttribute : TagAttribute public DynamicMethodCallModel(Type instanceObjectType) : this(instanceObjectType, null!) - { } + { + } public DynamicMethodCallModel(Type instanceObjectType, params object[] constructorParams) : this(Activator.CreateInstance(instanceObjectType, constructorParams)!) - { } + { + } public DynamicMethodCallModel(object instanceObject) { @@ -76,6 +78,9 @@ public class DynamicMethodCallModel where TAttribute : TagAttribute { if (methodInfo.GetCustomAttribute(typeof(TAttribute)) is not TAttribute attribute) continue; + if (MethodsByMessageTag.ContainsKey(attribute.MessageTag)) + throw new Exception($"Multiple SignaRMessageTag! messageTag: {attribute.MessageTag}; methodName: {methodInfo.Name}"); + MethodsByMessageTag[attribute.MessageTag] = new MethodInfoModel(attribute, methodInfo!); } } @@ -146,16 +151,23 @@ public class DevAdminSignalRHub : Hub, IAcSignalRHubServe { _logger.Debug($"{logText}({methodInfoModel.ParameterType.Name})"); - paramValues = new object[1]; + //paramValues = new object[1]; if (methodInfoModel.ParameterType == typeof(Guid) || methodInfoModel.ParameterType == typeof(Guid?)) { var msg = message!.MessagePackTo>(); - if (msg.PostData.Id.IsNullOrEmpty()) throw new NullReferenceException($"PostData.Id.IsNullOrEmpty(); Id: {msg.PostData.Id}"); - paramValues[0] = msg.PostData.Id; + paramValues = new object[msg.PostData.Ids.Count]; + + for (var i = 0; i < msg.PostData.Ids.Count; i++) + { + var id = msg.PostData.Ids[i]; + if (id.IsNullOrEmpty()) throw new NullReferenceException($"PostData.Id.IsNullOrEmpty(); Ids: {msg.PostData.Ids}"); + + paramValues[i] = msg.PostData.Ids[i]; + } } - else paramValues[0] = message!.MessagePackTo>(MessagePackSerializerOptions.Standard).PostDataJson.JsonTo(methodInfoModel.ParameterType)!; + else paramValues = [message!.MessagePackTo>(MessagePackSerializerOptions.Standard).PostDataJson.JsonTo(methodInfoModel.ParameterType)!]; } else _logger.Debug($"{logText}()"); @@ -169,7 +181,7 @@ public class DevAdminSignalRHub : Hub, IAcSignalRHubServe switch (messageTag) { case SignalRTags.GetAddress: - var id = message!.MessagePackTo>().PostData.Id; + var id = message!.MessagePackTo>().PostData.Ids[0]; var address = await _adminDal.GetAddressByIdAsync(id); await ResponseToCaller(messageTag, new SignalResponseJsonMessage(SignalResponseStatus.Success, address), requestId); @@ -177,7 +189,7 @@ public class DevAdminSignalRHub : Hub, IAcSignalRHubServe return; case SignalRTags.GetAddressesByContextId: - id = message!.MessagePackTo>().PostData.Id; + id = message!.MessagePackTo>().PostData.Ids[0]; address = await _adminDal.GetAddressByIdAsync(id); await ResponseToCaller(messageTag, new SignalResponseJsonMessage(SignalResponseStatus.Success, new List
{ address! }), requestId); diff --git a/TIAMWebApp/Server/TIAMWebApp.Server.csproj.user b/TIAMWebApp/Server/TIAMWebApp.Server.csproj.user index ee0ae9a9..3c3d044c 100644 --- a/TIAMWebApp/Server/TIAMWebApp.Server.csproj.user +++ b/TIAMWebApp/Server/TIAMWebApp.Server.csproj.user @@ -4,4 +4,7 @@ https C:\REPOS\AYCODE\source\TourIAm\TIAMWebApp\Server\Properties\PublishProfiles\FolderProfile1.pubxml + + ProjectDebugger + \ No newline at end of file diff --git a/TIAMWebApp/Shared/Models/APIUrls.cs b/TIAMWebApp/Shared/Models/APIUrls.cs index 33a8ac34..f7cbc6bc 100644 --- a/TIAMWebApp/Shared/Models/APIUrls.cs +++ b/TIAMWebApp/Shared/Models/APIUrls.cs @@ -75,41 +75,44 @@ namespace TIAMWebApp.Shared.Application.Models public const string GetTransferDestinationByCoordinates = TransferDataAPI + GetTransferDestinationByCoordinatesRouteName; public const string GetTransferDestinationByAddressRouteName = "GetTransferDestinationByAddress"; - public const string GetTransferDestinationByAddress = TransferDataAPI+GetTransferDestinationByAddressRouteName; + public const string GetTransferDestinationByAddress = TransferDataAPI + GetTransferDestinationByAddressRouteName; public const string CreateTransferDestinationRouteName = "CreateTransferDestination"; - public const string CreateTransferDestination = TransferDataAPI+CreateTransferDestinationRouteName; + public const string CreateTransferDestination = TransferDataAPI + CreateTransferDestinationRouteName; public const string GetTransfersRouteName = "GetTransfers"; - public const string GetTransfers = TransferDataAPI+GetTransfersRouteName; + public const string GetTransfers = TransferDataAPI + GetTransfersRouteName; public const string GetTransfersByUserIdRouteName = "GetTransfersByUserId"; - public const string GetTransfersByUserId = TransferDataAPI+GetTransfersByUserIdRouteName; + public const string GetTransfersByUserId = TransferDataAPI + GetTransfersByUserIdRouteName; + + public const string GetTransfersByDriverRouteName = "GetTransfersByDriverId"; + public const string GetTransfersByDriver = TransferDataAPI + GetTransfersByDriverRouteName; public const string GetTransferByIdRouteName = "GetTransferById"; - public const string GetTransferById = TransferDataAPI+GetTransferByIdRouteName; - + public const string GetTransferById = TransferDataAPI + GetTransferByIdRouteName; + public const string CreateTransferRouteName = "CreateTransfer"; - public const string CreateTransfer = TransferDataAPI+CreateTransferRouteName; + public const string CreateTransfer = TransferDataAPI + CreateTransferRouteName; public const string CreateTransfersRouteName = "CreateTransfers"; - public const string CreateTransfers = TransferDataAPI+CreateTransfersRouteName; + public const string CreateTransfers = TransferDataAPI + CreateTransfersRouteName; public const string UpdateTransferRouteName = "UpdateTransfer"; - public const string UpdateTransfer = TransferDataAPI+UpdateTransferRouteName; + public const string UpdateTransfer = TransferDataAPI + UpdateTransferRouteName; public const string UpdateTransferDestinationRouteName = "UpdateTransferDestintion"; public const string UpdateTransferDestination = TransferDataAPI + UpdateTransferDestinationRouteName; //serviceprovider public const string CreateServiceProviderRouteName = "CreateServiceProvider/"; - public const string CreateServiceProvider = ServiceProviderAPI+CreateServiceProviderRouteName; + public const string CreateServiceProvider = ServiceProviderAPI + CreateServiceProviderRouteName; public const string GetServiceProviderByIdRouteName = "GetServiceProviderById"; - public const string GetServiceProviderById = ServiceProviderAPI+GetServiceProviderByIdRouteName; + public const string GetServiceProviderById = ServiceProviderAPI + GetServiceProviderByIdRouteName; public const string GetServiceProvidersByOwnerIdRouteName = "GetServiceProvidersByOwnerId"; - public const string GetServiceProvidersByOwnerId = ServiceProviderAPI+GetServiceProvidersByOwnerIdRouteName; + public const string GetServiceProvidersByOwnerId = ServiceProviderAPI + GetServiceProvidersByOwnerIdRouteName; public const string UpdateServiceProviderRouteName = "UpdateServiceProvider"; public const string UpdateServiceProviderUrl = ServiceProviderAPI + UpdateServiceProviderRouteName; @@ -120,7 +123,7 @@ namespace TIAMWebApp.Shared.Application.Models public const string GetQrCodeByProductIdRouteName = "GetQRCodeByProductId"; - public const string GetQrCodeByProductId = ServiceProviderAPI+GetQrCodeByProductIdRouteName; + public const string GetQrCodeByProductId = ServiceProviderAPI + GetQrCodeByProductIdRouteName; public const string AddProductRouteName = "AddProduct"; public const string AddProductRouteUrl = ServiceProviderAPI + AddProductRouteName; @@ -167,31 +170,39 @@ namespace TIAMWebApp.Shared.Application.Models //permissions //1 public const string GetPermissionsForContextByContextIdRouteName = "GetPermissionsForContextByContextId"; - public const string GetPermissionsForContextByContextId = ServiceProviderAPI+GetPermissionsForContextByContextIdRouteName; + + public const string GetPermissionsForContextByContextId = ServiceProviderAPI + GetPermissionsForContextByContextIdRouteName; + //2. get the contexts where the user has permission public const string GetPermissionContextByUserIdRouteName = "GetPermissionContextByUserId"; - public const string GetPermissionContextByUserId = ServiceProviderAPI+GetPermissionContextByUserIdRouteName; + + public const string GetPermissionContextByUserId = ServiceProviderAPI + GetPermissionContextByUserIdRouteName; + //12 public const string GetPermissionGroupsForContextByContextIdRouteName = "GetPermissionGroupsForContextByContextId"; - public const string GetPermissionGroupsForContextByContextId = ServiceProviderAPI+GetPermissionGroupsForContextByContextIdRouteName; + public const string GetPermissionGroupsForContextByContextId = ServiceProviderAPI + GetPermissionGroupsForContextByContextIdRouteName; //file upload public const string UploadImageRouteName = "UploadImage"; - public const string UploadImage = FileAPI+UploadImageRouteName; + + public const string UploadImage = FileAPI + UploadImageRouteName; + //get images public const string GetImagesRouteName = "GetAllMedia"; - public const string GetImages = FileAPI+GetImagesRouteName; + + public const string GetImages = FileAPI + GetImagesRouteName; + //get image by name public const string GetImageRouteName = "GetImage"; - public const string GetImage = FileAPI+GetImageRouteName; + public const string GetImage = FileAPI + GetImageRouteName; //email public const string SendEmailRouteName = "SendEmail"; - public const string SendEmail = MessageAPI+SendEmailRouteName; + public const string SendEmail = MessageAPI + SendEmailRouteName; public const string GetAllMessagesRouteName = "GetAllMessages"; - public const string GetAllMessages = MessageAPI+GetAllMessagesRouteName; + public const string GetAllMessages = MessageAPI + GetAllMessagesRouteName; public const string GetMessagesByContextIdRouteName = "GetMessagesByContextId"; - public const string GetMessagesByContextId = MessageAPI+GetMessagesByContextIdRouteName; + public const string GetMessagesByContextId = MessageAPI + GetMessagesByContextIdRouteName; //payment public const string CreatePaymentRouteName = "CreatePayment"; diff --git a/TIAMWebApp/Shared/Services/AcSignalRClientBase.cs b/TIAMWebApp/Shared/Services/AcSignalRClientBase.cs deleted file mode 100644 index d531c604..00000000 --- a/TIAMWebApp/Shared/Services/AcSignalRClientBase.cs +++ /dev/null @@ -1,251 +0,0 @@ -using System.Collections.Concurrent; -using AyCode.Core; -using AyCode.Core.Extensions; -using AyCode.Core.Helpers; -using AyCode.Core.Interfaces; -using AyCode.Services.Loggers; -using AyCode.Services.SignalRs; -using MessagePack.Resolvers; -using Microsoft.AspNetCore.SignalR.Client; -using TIAMWebApp.Shared.Application.Models.ClientSide; -using TIAMWebApp.Shared.Application.Utility; - -namespace TIAMWebApp.Shared.Application.Services -{ - public class AdminSignalRClient(IEnumerable logWriters) : AcSignalRClientBase("DevAdminHub", logWriters); - - public abstract class AcSignalRClientBase : IAcSignalRHubClient - { - private readonly ConcurrentDictionary _responseByRequestId = new(); - - protected readonly HubConnection HubConnection; - protected readonly LoggerClient Logger; - - public event Action OnMessageReceived; - //public event Action OnMessageRequested; - - public int Timeout = 10000; - - protected AcSignalRClientBase(string hubName, IEnumerable logWriters) - { - Logger = new LoggerClient(GetType().Name, logWriters.ToArray()); - - HubConnection = new HubConnectionBuilder() - .WithUrl($"{Setting.BaseUrl}/{hubName}") - //.AddMessagePackProtocol(options => { - // options.SerializerOptions = MessagePackSerializerOptions.Standard - // .WithResolver(MessagePack.Resolvers.StandardResolver.Instance) - // .WithSecurity(MessagePackSecurity.UntrustedData) - // .WithCompression(MessagePackCompression.Lz4Block) - // .WithCompressionMinLength(256);}) - .Build(); - - HubConnection.Closed += HubConnection_Closed; - - _ = HubConnection.On(nameof(IAcSignalRHubClient.OnReceiveMessage), OnReceiveMessage); - //_ = HubConnection.On(nameof(IAcSignalRHubClient.OnRequestMessage), OnRequestMessage); - - HubConnection.StartAsync().Forget(); - - } - - private Task HubConnection_Closed(Exception? arg) - { - if (_responseByRequestId.IsEmpty) Logger.DebugConditional($"Client HubConnection_Closed"); - else Logger.Warning($"Client HubConnection_Closed; {nameof(_responseByRequestId)} count: {_responseByRequestId.Count}"); - - _responseByRequestId.Clear(); - return Task.CompletedTask; - } - - public async Task StartConnection() - { - if (HubConnection.State == HubConnectionState.Disconnected) - await HubConnection.StartAsync(); - - if (HubConnection.State != HubConnectionState.Connected) - await TaskHelper.WaitToAsync(() => HubConnection.State == HubConnectionState.Connected, Timeout, 25); - } - - public async Task StopConnection() - { - await HubConnection.StopAsync(); - await HubConnection.DisposeAsync(); - } - - public virtual Task SendMessageToServerAsync(int messageTag) - => SendMessageToServerAsync(messageTag, null, AcDomain.NextUniqueInt32); - - public virtual async Task SendMessageToServerAsync(int messageTag, ISignalRMessage? message, int? requestId) - { - Logger.DebugConditional($"Client SendMessageToServerAsync; {nameof(messageTag)}: {messageTag}; {nameof(requestId)}: {requestId};"); - - await StartConnection(); - - var msgp = message?.ToMessagePack(ContractlessStandardResolver.Options); - HubConnection.SendAsync(nameof(IAcSignalRHubClient.OnReceiveMessage), messageTag, msgp, requestId).Forget(); - } - - #region CRUD - public virtual Task GetByIdAsync(int messageTag, Guid id) where TResponseData : class - => SendMessageToServerAsync(messageTag, new SignalPostJsonDataMessage(new IdMessage(id)), AcDomain.NextUniqueInt32); - public virtual Task GetByIdAsync(int messageTag, Guid id, Action> responseCallback) - => SendMessageToServerAsync(messageTag, new SignalPostJsonDataMessage(new IdMessage(id)), responseCallback); - - public virtual Task GetAllAsync(int messageTag) where TResponseData : class - => SendMessageToServerAsync(messageTag); - public virtual Task GetAllAsync(int messageTag, Action> responseCallback) - => SendMessageToServerAsync(messageTag, null, responseCallback); - public virtual Task GetAllAsync(int messageTag, Guid? contextId, Action> responseCallback) - => SendMessageToServerAsync(messageTag, (contextId.IsNullOrEmpty() ? null : new SignalPostJsonDataMessage(new IdMessage(contextId.Value))), responseCallback); - - public virtual Task GetAllAsync(int messageTag, Guid? contextId) where TResponseData : class - => SendMessageToServerAsync(messageTag, contextId.IsNullOrEmpty() ? null : new SignalPostJsonDataMessage(new IdMessage(contextId.Value)), AcDomain.NextUniqueInt32); - - public virtual Task PostDataAsync(int messageTag, TPostData postData) where TPostData : class - => SendMessageToServerAsync(messageTag, new SignalPostJsonDataMessage(postData), AcDomain.NextUniqueInt32); - public virtual Task PostDataAsync(int messageTag, TPostData postData, Action> responseCallback) where TPostData : class - => SendMessageToServerAsync(messageTag, new SignalPostJsonDataMessage(postData), responseCallback); - - #endregion CRUD - - public virtual Task SendMessageToServerAsync(int messageTag) where TResponse : class - => SendMessageToServerAsync(messageTag, null, AcDomain.NextUniqueInt32); - - public virtual Task SendMessageToServerAsync(int messageTag, ISignalRMessage? message) where TResponse : class - => SendMessageToServerAsync(messageTag, message, AcDomain.NextUniqueInt32); - - protected virtual async Task SendMessageToServerAsync(int messageTag, ISignalRMessage? message, int requestId) where TResponse : class - { - Logger.DebugConditional($"Client SendMessageToServerAsync; {nameof(messageTag)}: {messageTag}; {nameof(requestId)}: {requestId};"); - - _responseByRequestId[requestId] = null; - await SendMessageToServerAsync(messageTag, message, requestId); - - try - { - if (await TaskHelper.WaitToAsync(() => _responseByRequestId[requestId] != null, Timeout, 25) && - _responseByRequestId.TryRemove(requestId, out var obj) && obj is ISignalResponseMessage responseMessage) - { - if (responseMessage.Status == SignalResponseStatus.Error || responseMessage.ResponseData == null) - { - var errorText = $"Client SendMessageToServerAsync response error; await; tag: {messageTag}; Status: {responseMessage.Status}; requestId: {requestId};"; - - Logger.Error(errorText); - - //TODO: Ideiglenes, majd a ResponseMessage-et kell visszaadni a Status miatt! - J. - throw new Exception(errorText); - //return default; - } - - return responseMessage.ResponseData.JsonTo(); - } - } - catch (Exception ex) - { - Logger.Error($"SendMessageToServerAsync; messageTag: {messageTag}; requestId: {requestId}; {ex.Message}", ex); - } - - _responseByRequestId.TryRemove(requestId, out _); - return default; - } - - public virtual Task SendMessageToServerAsync(int messageTag, Action> responseCallback) - => SendMessageToServerAsync(messageTag, null, responseCallback); - - public virtual Task SendMessageToServerAsync(int messageTag, ISignalRMessage? message, Action> responseCallback) - { - if (messageTag == 0) - Logger.Error($"SendMessageToServerAsync; messageTag == 0"); - - var requestId = AcDomain.NextUniqueInt32; - - _responseByRequestId[requestId] = new Action>(responseMessage => - { - TResponseData? responseData = default; - - if (responseMessage.Status == SignalResponseStatus.Success) - { - responseData = string.IsNullOrEmpty(responseMessage.ResponseData) ? default : responseMessage.ResponseData.JsonTo(); - } - else Logger.Error($"Client SendMessageToServerAsync response error; callback; tag: {messageTag}; Status: {responseMessage.Status}; requestId: {requestId};"); - - responseCallback(new SignalResponseMessage(responseMessage.Status, responseData)); - }); - - return SendMessageToServerAsync(messageTag, message, requestId); - } - - public virtual Task OnReceiveMessage(int messageTag, byte[] message, int? requestId) - { - var logText = $"Client OnReceiveMessage; {nameof(messageTag)}: {messageTag}; {nameof(requestId)}: {requestId};"; - - if (message.Length == 0) Logger.Warning($"message.Length == 0! {logText}"); - else Logger.Info(logText); - - try - { - if (requestId.HasValue && _responseByRequestId.ContainsKey(requestId.Value)) - { - var reqId = requestId.Value; - - var responseMessage = message.MessagePackTo(ContractlessStandardResolver.Options); - - switch (_responseByRequestId[reqId]) - { - case null: - _responseByRequestId[reqId] = responseMessage; - return Task.CompletedTask; - - case Action> messagePackCallback: - _responseByRequestId.TryRemove(reqId, out _); - - messagePackCallback.Invoke(responseMessage); - return Task.CompletedTask; - - //case Action jsonCallback: - // _responseByRequestId.TryRemove(reqId, out _); - - // jsonCallback.Invoke(responseMessage); - // return Task.CompletedTask; - - default: - Logger.Error($"Client OnReceiveMessage switch; unknown message type: {_responseByRequestId[reqId]?.GetType().Name}"); - break; - } - - _responseByRequestId.TryRemove(reqId, out _); - } - - OnMessageReceived(messageTag, message, requestId); - } - catch(Exception ex) - { - if (requestId.HasValue) - _responseByRequestId.TryRemove(requestId.Value, out _); - - Logger.Error($"Client OnReceiveMessage; messageTag: {messageTag}; requestId: {requestId}; {ex.Message}", ex); - throw; - } - - return Task.CompletedTask; - } - //public virtual Task OnRequestMessage(int messageTag, int requestId) - //{ - // Logger.DebugConditional($"Client OnRequestMessage; {nameof(messageTag)}: {messageTag}; {nameof(requestId)}: {requestId};"); - - // try - // { - // OnMessageRequested(messageTag, requestId); - // } - // catch(Exception ex) - // { - // Logger.Error($"Client OnReceiveMessage; {nameof(messageTag)}: {messageTag}; {nameof(requestId)}: {requestId}; {ex.Message}", ex); - // throw; - // } - - // return Task.CompletedTask; - - //} - } -} diff --git a/TIAMWebApp/Shared/Services/AdminSignalRClient.cs b/TIAMWebApp/Shared/Services/AdminSignalRClient.cs new file mode 100644 index 00000000..3873924e --- /dev/null +++ b/TIAMWebApp/Shared/Services/AdminSignalRClient.cs @@ -0,0 +1,17 @@ +using System.Collections.Concurrent; +using AyCode.Blazor.Components.Services; +using AyCode.Core; +using AyCode.Core.Extensions; +using AyCode.Core.Helpers; +using AyCode.Core.Interfaces; +using AyCode.Services.Loggers; +using AyCode.Services.SignalRs; +using MessagePack.Resolvers; +using Microsoft.AspNetCore.SignalR.Client; +using TIAMWebApp.Shared.Application.Models.ClientSide; +using TIAMWebApp.Shared.Application.Utility; + +namespace TIAMWebApp.Shared.Application.Services +{ + public class AdminSignalRClient(IEnumerable logWriters) : AcSignalRClientBase($"{Setting.BaseUrl}/DevAdminHub", new LoggerClient(nameof(AdminSignalRClient), logWriters.ToArray())); +} diff --git a/TIAMWebApp/Shared/Services/ServiceProviderDataService.cs b/TIAMWebApp/Shared/Services/ServiceProviderDataService.cs index 2827e839..528f888b 100644 --- a/TIAMWebApp/Shared/Services/ServiceProviderDataService.cs +++ b/TIAMWebApp/Shared/Services/ServiceProviderDataService.cs @@ -89,7 +89,7 @@ namespace TIAMWebApp.Shared.Application.Services //17. public Task GetPropertiesByOwnerIdAsync(Guid id, Action?> callback) { - return _adminSignalRClient.GetByIdAsync>(SignalRTags.GetPropertiesByOwnerId, id, response => + return _adminSignalRClient.GetByIdAsync>(SignalRTags.GetPropertiesByOwnerId, response => { if (response.Status == SignalResponseStatus.Error) callback.Invoke(null); @@ -97,7 +97,7 @@ namespace TIAMWebApp.Shared.Application.Services _logger.DetailConditional($"companyPropertiesByOwner async: {string.Join("; ", response.ResponseData!.Values)}"); callback.Invoke(response.ResponseData); - }); + }, id); } //17. @@ -140,7 +140,7 @@ namespace TIAMWebApp.Shared.Application.Services var companies = await _adminSignalRClient.GetAllAsync>(SignalRTags.GetCompanies); if (companies != null) _logger.DetailConditional($"companies: {string.Join("; ", companies.Count)}"); - return companies; + return companies ?? []; } //24. diff --git a/TIAMWebApp/Shared/TIAMWebApp.Shared.Application.csproj b/TIAMWebApp/Shared/TIAMWebApp.Shared.Application.csproj index a8a4adcd..ca85dd73 100644 --- a/TIAMWebApp/Shared/TIAMWebApp.Shared.Application.csproj +++ b/TIAMWebApp/Shared/TIAMWebApp.Shared.Application.csproj @@ -33,6 +33,10 @@ + + + + diff --git a/TIAMWebApp/Shared/Utility/SignaRClientLogItemWriter.cs b/TIAMWebApp/Shared/Utility/SignaRClientLogItemWriter.cs index ebe1ff8b..7054d754 100644 --- a/TIAMWebApp/Shared/Utility/SignaRClientLogItemWriter.cs +++ b/TIAMWebApp/Shared/Utility/SignaRClientLogItemWriter.cs @@ -16,7 +16,10 @@ namespace TIAMWebApp.Shared.Application.Utility //.AddMessagePackProtocol(options => options.SerializerOptions = MessagePackSerializerOptions.Standard.WithSecurity(MessagePackSecurity.UntrustedData)) .Build(); - public SignaRClientLogItemWriter() : base(AppType.Web, LogLevel.Detail) + public SignaRClientLogItemWriter() : this(AppType.Web, LogLevel.Detail) + { } + + public SignaRClientLogItemWriter(AppType appType, LogLevel logLevel, string? categoryName = null) : base(appType, logLevel, categoryName) { _hubConnection.StartAsync().Forget(); } diff --git a/TIAMWebApp/Shared/Utility/SignalRDataSource.cs b/TIAMWebApp/Shared/Utility/SignalRDataSource.cs index fc9a14f3..3a2eb0fc 100644 --- a/TIAMWebApp/Shared/Utility/SignalRDataSource.cs +++ b/TIAMWebApp/Shared/Utility/SignalRDataSource.cs @@ -5,1030 +5,18 @@ using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Runtime.Serialization; using System.Runtime.Serialization.Formatters.Binary; +using AyCode.Blazor.Components.Services; using AyCode.Core.Enums; using AyCode.Core.Extensions; using AyCode.Core.Helpers; using AyCode.Core.Interfaces; using AyCode.Services.SignalRs; using TIAM.Services; -using TIAMWebApp.Shared.Application.Services; namespace TIAMWebApp.Shared.Application.Utility { - public class TrackingItem(TrackingState trackingState, T currentValue, T? originalValue = null) where T : class, IId - { - public TrackingState TrackingState { get; internal set; } = trackingState; - public T CurrentValue { get; internal set; } = currentValue; - public T? OriginalValue { get; init; } = originalValue; - - internal TrackingItem UpdateItem(TrackingState trackingState, T newValue) - { - CurrentValue = newValue; - - if (TrackingState != TrackingState.Add) - TrackingState = trackingState; - - return this; - } - } - - - public class ChangeTracking /*: IEnumerable>*/ where T : class, IId - { - private readonly List> _trackingItems = []; //TODO: Dictionary... - J. - - internal TrackingItem? AddTrackingItem(TrackingState trackingState, T newValue, T? originalValue = null) - { - if (newValue.Id.IsNullOrEmpty()) throw new ArgumentNullException(nameof(newValue), $@"currentValue.Id.IsNullOrEmpty()"); - - var itemIndex = _trackingItems.FindIndex(x => x.CurrentValue.Id == newValue.Id); - TrackingItem? trackingItem = null; - - if (itemIndex > -1) - { - trackingItem = _trackingItems[itemIndex]; - - if (trackingState == TrackingState.Remove && trackingItem.TrackingState == TrackingState.Add) - { - _trackingItems.RemoveAt(itemIndex); - return null; - } - - return trackingItem.UpdateItem(trackingState, newValue); - - } - - if (originalValue != null && Equals(newValue, originalValue)) - originalValue = TrackingItemHelpers.JsonClone(originalValue); - - trackingItem = new TrackingItem(trackingState, newValue, originalValue); - _trackingItems.Add(trackingItem); - - return trackingItem; - } - - public int Count => _trackingItems.Count; - internal void Clear() => _trackingItems.Clear(); - public List> ToList() => _trackingItems.ToList(); - - public bool TryGetTrackingItem(Guid id, [NotNullWhen(true)] out TrackingItem? trackingItem) - { - trackingItem = _trackingItems.FirstOrDefault(x => x.CurrentValue.Id == id); - return trackingItem != null; - } - - internal void Remove(TrackingItem trackingItem) => _trackingItems.Remove(trackingItem); - - //public IEnumerator> GetEnumerator() - //{ - // return _trackingItems.GetEnumerator(); - //} - - //IEnumerator IEnumerable.GetEnumerator() - //{ - // return GetEnumerator(); - //} - } - - - [Serializable] [DebuggerDisplay("Count = {Count}")] - public class SignalRDataSource : IList, IList, IReadOnlyList where T : class, IId - { - private readonly object _syncRoot = new(); - - protected readonly List InnerList = []; //TODO: Dictionary??? - J. - protected readonly ChangeTracking TrackingItems = new(); - - protected readonly Guid? ContextId; - public AcSignalRClientBase SignalRClient; - protected readonly SignalRCrudTags SignalRCrudTags; - - public Func, Task>? OnDataSourceItemChanged; - public Func? OnDataSourceLoaded; - - public SignalRDataSource(AcSignalRClientBase signalRClient, SignalRCrudTags signalRCrudTags, Guid? contextId = null) - { - ContextId = contextId; - - SignalRCrudTags = signalRCrudTags; - SignalRClient = signalRClient; - } - - public bool IsSynchronized => true; - public object SyncRoot => _syncRoot; - public bool IsFixedSize => false; - - /// - /// GetAllMessageTag - /// - /// - /// - public async Task LoadDataSource(bool clearChangeTracking = true) - { - if (SignalRCrudTags.GetAllMessageTag == SignalRTags.None) throw new ArgumentException($"SignalRCrudTags.GetAllMessageTag == SignalRTags.None"); - - var resultList = (await SignalRClient.GetAllAsync>(SignalRCrudTags.GetAllMessageTag, ContextId)) ?? throw new NullReferenceException(); - - await LoadDataSource(resultList); - } - - public Task LoadDataSourceAsync(bool clearChangeTracking = true) - { - if (SignalRCrudTags.GetAllMessageTag == SignalRTags.None) throw new ArgumentException($"SignalRCrudTags.GetAllMessageTag == SignalRTags.None"); - - return SignalRClient.GetAllAsync>(SignalRCrudTags.GetAllMessageTag, ContextId, result=> - { - if (result.Status != SignalResponseStatus.Success || result.ResponseData == null) - throw new NullReferenceException($"LoadDataSourceAsync; result.Status != SignalResponseStatus.Success || result.ResponseData == null; Status: {SignalResponseStatus.Success}"); - - LoadDataSource(result.ResponseData).Forget(); - }); - } - - public async Task LoadDataSource(IList fromSource, bool clearChangeTracking = true) - { - Monitor.Enter(_syncRoot); - - try - { - Clear(clearChangeTracking); - - foreach (var item in fromSource) - { - InnerList.Add(item); - - var eventArgs = new ItemChangedEventArgs(item, TrackingState.GetAll); - if (OnDataSourceItemChanged != null) await OnDataSourceItemChanged.Invoke(eventArgs); - } - } - finally - { - Monitor.Exit(_syncRoot); - } - - if (OnDataSourceLoaded != null) await OnDataSourceLoaded.Invoke(); - } - - public async Task LoadItem(Guid id) - { - if (SignalRCrudTags.GetItemMessageTag == SignalRTags.None) throw new ArgumentException($"SignalRCrudTags.GetItemMessageTag == SignalRTags.None"); - - T? resultitem = null; - - Monitor.Enter(_syncRoot); - - try - { - resultitem = await SignalRClient.GetByIdAsync(SignalRCrudTags.GetItemMessageTag, id); - if (resultitem == null) return null; - - if (TryGetIndex(id, out var index)) InnerList[index] = resultitem; - else InnerList.Add(resultitem); - - var eventArgs = new ItemChangedEventArgs(resultitem, TrackingState.Get); - if (OnDataSourceItemChanged != null) await OnDataSourceItemChanged.Invoke(eventArgs); - } - finally - { - Monitor.Exit(_syncRoot); - } - - return resultitem; - } - - /// - /// set: UpdateMessageTag - /// - /// - /// - /// - public T this[int index] - { - get - { - if ((uint)index >= (uint)Count) throw new ArgumentOutOfRangeException(nameof(index)); - - Monitor.Enter(_syncRoot); - try - { - return InnerList[index]; - } - finally - { - Monitor.Exit(_syncRoot); - } - } - set - { - Monitor.Enter(_syncRoot); - try - { - UpdateUnsafe(index, value); - } - finally - { - Monitor.Exit(_syncRoot); - } - - } - } - - public void Add(T newValue) - { - if (newValue.Id.IsNullOrEmpty()) throw new ArgumentNullException(nameof(newValue), @"Add->newValue.Id.IsNullOrEmpty()"); - - Monitor.Enter(_syncRoot); - - try - { - if (Contains(newValue)) - throw new ArgumentException($@"It already contains this Id! Id: {newValue.Id}", nameof(newValue)); - - UnsafeAdd(newValue); - } - finally - { - Monitor.Exit(_syncRoot); - } - } - - /// - /// AddMessageTag - /// - /// - /// - /// - public async Task Add(T newValue, bool autoSave) - { - Monitor.Enter(_syncRoot); - - try - { - Add(newValue); - - return autoSave ? await SaveItem(newValue, TrackingState.Add) : newValue; - } - finally - { - Monitor.Exit(_syncRoot); - } - } - - /// - /// AddMessageTag or UpdateMessageTag - /// - /// - /// - /// - public async Task AddOrUpdate(T newValue, bool autoSave) - { - if (newValue.Id.IsNullOrEmpty()) throw new ArgumentNullException(nameof(newValue), @"AddOrUpdate->newValue.Id.IsNullOrEmpty()"); - - Monitor.Enter(_syncRoot); - - try - { - var index = IndexOf(newValue); - - return index > -1 ? await Update(index, newValue, autoSave) : await Add(newValue, autoSave); - } - finally - { - Monitor.Exit(_syncRoot); - } - - } - - //public void AddRange(IEnumerable collection) - //{ - // lock (_syncRoot) - // { - - // } - //} - - protected void UnsafeAdd(T newValue) - { - TrackingItems.AddTrackingItem(TrackingState.Add, newValue); - InnerList.Add(newValue); - } - - /// - /// AddMessageTag - /// - /// - /// - /// - /// - /// - public void Insert(int index, T newValue) - { - if (newValue.Id.IsNullOrEmpty()) throw new ArgumentNullException(nameof(newValue), @"Insert->newValue.Id.IsNullOrEmpty()"); - - Monitor.Enter(_syncRoot); - - try - { - if (Contains(newValue)) - throw new ArgumentException($@"Insert; It already contains this Id! Id: {newValue.Id}", nameof(newValue)); - - TrackingItems.AddTrackingItem(TrackingState.Add, newValue); - InnerList.Insert(index, newValue); - } - finally - { - Monitor.Exit(_syncRoot); - } - } - - public async Task Insert(int index, T newValue, bool autoSave) - { - Monitor.Enter(_syncRoot); - - try - { - Insert(index, newValue); - - return autoSave ? await SaveItem(newValue, TrackingState.Add) : newValue; - } - finally - { - Monitor.Exit(_syncRoot); - } - } - /// - /// UpdateMessageTag - /// - /// - /// - public Task Update(T newItem, bool autoSave) => Update(IndexOf(newItem), newItem, autoSave); - - /// - /// UpdateMessageTag - /// - /// - /// - /// - /// /// - /// /// - /// - /// - public async Task Update(int index, T newValue, bool autoSave) - { - Monitor.Enter(_syncRoot); - - try - { - UpdateUnsafe(index, newValue); - - return autoSave ? await SaveItem(newValue, TrackingState.Update) : newValue; - } - finally - { - Monitor.Exit(_syncRoot); - } - } - - private void UpdateUnsafe(int index, T newValue) - { - if (default(T) != null && newValue == null) throw new NullReferenceException(nameof(newValue)); - if (newValue.Id.IsNullOrEmpty()) throw new ArgumentNullException(nameof(newValue), @"UpdateUnsafe->newValue.Id.IsNullOrEmpty()"); - if ((uint)index >= (uint)Count) throw new ArgumentOutOfRangeException(nameof(index)); - - Monitor.Enter(_syncRoot); - - try - { - var currentItem = InnerList[index]; - - if (currentItem.Id != newValue.Id) - throw new ArgumentException($@"UpdateUnsafe; currentItem.Id != item.Id! Id: {newValue.Id}", nameof(newValue)); - - TrackingItems.AddTrackingItem(TrackingState.Update, newValue, currentItem); - InnerList[index] = newValue; - } - finally - { - Monitor.Exit(_syncRoot); - } - } - - - /// - /// RemoveMessageTag - /// - /// - /// - public bool Remove(T item) - { - Monitor.Enter(_syncRoot); - - try - { - var index = IndexOf(item); - - if (index < 0) return false; - - RemoveAt(index); - return true; - } - finally - { - Monitor.Exit(_syncRoot); - } - } - - public async Task Remove(T item, bool autoSave) - { - Monitor.Enter(_syncRoot); - - try - { - var result = Remove(item); - - if (!autoSave || !result) return result; - - await SaveItem(item, TrackingState.Remove); - return true; - } - finally - { - Monitor.Exit(_syncRoot); - } - } - /// - /// - /// - /// - /// - /// - public bool TryRemove(Guid id, out T? item) - { - Monitor.Enter(_syncRoot); - - try - { - return TryGetValue(id, out item) && Remove(item); - } - finally - { - Monitor.Exit(_syncRoot); - } - - } - - /// - /// RemoveMessageTag - /// - /// - /// - /// /// - /// - public void RemoveAt(int index) - { - Monitor.Enter(_syncRoot); - - try - { - var currentItem = InnerList[index]; - if (currentItem.Id.IsNullOrEmpty()) throw new ArgumentNullException(nameof(currentItem), $@"RemoveAt->item.Id.IsNullOrEmpty(); index: {index}"); - - TrackingItems.AddTrackingItem(TrackingState.Remove, currentItem, currentItem); - InnerList.RemoveAt(index); - } - finally - { - Monitor.Exit(_syncRoot); - } - } - - public async Task RemoveAt(int index, bool autoSave) - { - Monitor.Enter(_syncRoot); - - try - { - var currentItem = InnerList[index]; - RemoveAt(index); - - if (autoSave) - { - await SaveItem(currentItem, TrackingState.Remove); - } - } - finally - { - Monitor.Exit(_syncRoot); - } - } - /// - /// - /// - /// - public List> GetTrackingItems() - { - Monitor.Enter(_syncRoot); - - try - { - return TrackingItems.ToList(); - } - finally - { - Monitor.Exit(_syncRoot); - } - } - - public void SetTrackingStateToUpdate(T item) - { - Monitor.Enter(_syncRoot); - - try - { - if (TrackingItems.TryGetTrackingItem(item.Id, out var trackingItem)) - { - if (trackingItem.TrackingState != TrackingState.Add) - trackingItem.TrackingState = TrackingState.Update; - - return; - } - - if (!TryGetValue(item.Id, out var originalItem)) return; - TrackingItems.AddTrackingItem(TrackingState.Update, item, originalItem); - } - finally - { - Monitor.Exit(_syncRoot); - } - } - - /// - /// - /// - /// - /// - /// - public bool TryGetTrackingItem(Guid id, [NotNullWhen(true)] out TrackingItem? trackingItem) - { - Monitor.Enter(_syncRoot); - - try - { - return TrackingItems.TryGetTrackingItem(id, out trackingItem); - } - finally - { - Monitor.Exit(_syncRoot); - } - - } - - /// - /// - /// - /// Unsaved items - public async Task>> SaveChanges() - { - Monitor.Enter(_syncRoot); - - try - { - foreach (var trackingItem in TrackingItems.ToList()) - { - try - { - await SaveTrackingItemUnsafe(trackingItem); - } - catch(Exception ex) - { - TryRollbackItem(trackingItem.CurrentValue.Id, out _); - } - } - - return TrackingItems.ToList(); - } - finally - { - Monitor.Exit(_syncRoot); - } - } - - public async Task SaveChangesAsync() - { - Monitor.Enter(_syncRoot); - - try - { - foreach (var trackingItem in TrackingItems.ToList()) - { - try - { - await SaveTrackingItemUnsafeAsync(trackingItem); - } - catch(Exception ex) - { - TryRollbackItem(trackingItem.CurrentValue.Id, out _); - } - } - } - finally - { - Monitor.Exit(_syncRoot); - } - } - - /// - /// - /// - /// - /// - public async Task SaveItem(Guid id) - { - Monitor.Enter(_syncRoot); - - try - { - T resultItem = null!; - - if (TryGetTrackingItem(id, out var trackingItem)) - resultItem = await SaveTrackingItemUnsafe(trackingItem); - - if (resultItem == null) throw new NullReferenceException($"SaveItem; resultItem == null"); - return resultItem; - } - finally - { - Monitor.Exit(_syncRoot); - } - } - - public async Task SaveItem(Guid id, TrackingState trackingState) - { - Monitor.Enter(_syncRoot); - - try - { - T resultItem = null!; - - if (TryGetValue(id, out var item)) - resultItem = await SaveItem(item, trackingState); - - if (resultItem == null) throw new NullReferenceException($"SaveItem; resultItem == null"); - return resultItem; - } - finally - { - Monitor.Exit(_syncRoot); - } - } - - public Task SaveItem(T item, TrackingState trackingState) => SaveItemUnsafe(item, trackingState); - - protected Task SaveTrackingItemUnsafe(TrackingItem trackingItem) - => SaveItemUnsafe(trackingItem.CurrentValue, trackingItem.TrackingState); - - protected Task SaveTrackingItemUnsafeAsync(TrackingItem trackingItem) - => SaveItemUnsafeAsync(trackingItem.CurrentValue, trackingItem.TrackingState); - - protected async Task SaveItemUnsafe(T item, TrackingState trackingState) - { - var messageTag = SignalRCrudTags.GetMessageTagByTrackingState(trackingState); - if (messageTag == SignalRTags.None) throw new ArgumentException($"SaveItemUnsafe; messageTag == SignalRTags.None"); - - var result = await SignalRClient.PostDataAsync(messageTag, item); - if (result == null) throw new NullReferenceException($"SaveItemUnsafe; result == null"); - - await ProcessSavedResponseItem(result, trackingState); - - return result; - } - - protected Task SaveItemUnsafeAsync(T item, TrackingState trackingState) - { - var messageTag = SignalRCrudTags.GetMessageTagByTrackingState(trackingState); - if (messageTag == SignalRTags.None) return Task.CompletedTask; - - return SignalRClient.PostDataAsync(messageTag, item, response => - { - Monitor.Enter(_syncRoot); - - try - { - if (response.Status != SignalResponseStatus.Success || response.ResponseData == null) - { - if (TryRollbackItem(item.Id, out _)) return; - - throw new NullReferenceException($"SaveItemUnsafeAsync; result.Status != SignalResponseStatus.Success || result.ResponseData == null; Status: {SignalResponseStatus.Success}"); - } - - ProcessSavedResponseItem(response.ResponseData, trackingState).Forget(); - } - finally - { - Monitor.Exit(_syncRoot); - } - }); - } - - private async Task ProcessSavedResponseItem(T? resultItem, TrackingState trackingState) - { - if (resultItem == null) return; - - if (TryGetTrackingItem(resultItem.Id, out var trackingItem)) - TrackingItems.Remove(trackingItem); - - if (TryGetIndex(resultItem.Id, out var index)) - InnerList[index] = resultItem; - - var eventArgs = new ItemChangedEventArgs(resultItem, trackingState); - if (OnDataSourceItemChanged != null) await OnDataSourceItemChanged.Invoke(eventArgs); - } - - protected void RollbackItemUnsafe(TrackingItem trackingItem) - { - if (TryGetIndex(trackingItem.CurrentValue.Id, out var index)) - { - if (trackingItem.TrackingState == TrackingState.Add) InnerList.RemoveAt(index); - else InnerList[index] = trackingItem.OriginalValue!; - } - else if (trackingItem.TrackingState != TrackingState.Add) - InnerList.Add(trackingItem.OriginalValue!); - - TrackingItems.Remove(trackingItem); - } - - public bool TryRollbackItem(Guid id, out T? originalValue) - { - Monitor.Enter(_syncRoot); - try - { - if (TryGetTrackingItem(id, out var trackingItem)) - { - originalValue = trackingItem.OriginalValue; - - RollbackItemUnsafe(trackingItem); - return true; - } - - originalValue = null; - return false; - } - finally - { - Monitor.Exit(_syncRoot); - } - } - - public void Rollback() - { - Monitor.Enter(_syncRoot); - try - { - foreach (var trackingItem in TrackingItems.ToList()) - RollbackItemUnsafe(trackingItem); - } - finally - { - Monitor.Exit(_syncRoot); - } - } - - public int Count - { - get - { - Monitor.Enter(_syncRoot); - try - { - return InnerList.Count; - } - finally - { - Monitor.Exit(_syncRoot); - } - - } - } - - public void Clear() => Clear(true); - - public void Clear(bool clearChangeTracking) - { - Monitor.Enter(_syncRoot); - try - { - if (clearChangeTracking) TrackingItems.Clear(); - InnerList.Clear(); - } - finally - { - Monitor.Exit(_syncRoot); - } - } - - public int IndexOf(Guid id) - { - Monitor.Enter(_syncRoot); - try - { - return InnerList.FindIndex(x => x.Id == id); - } - finally - { - Monitor.Exit(_syncRoot); - } - - } - - public int IndexOf(T item) => IndexOf(item.Id); - public bool TryGetIndex(Guid id, out int index) => (index = IndexOf(id)) > -1; - - public bool Contains(T item) => IndexOf(item) > -1; - - public bool TryGetValue(Guid id, [NotNullWhen(true)] out T? item) - { - Monitor.Enter(_syncRoot); - try - { - item = InnerList.FirstOrDefault(x => x.Id == id); - return item != null; - } - finally - { - Monitor.Exit(_syncRoot); - } - } - - public void CopyTo(T[] array) => CopyTo(array, 0); - - public void CopyTo(T[] array, int arrayIndex) - { - Monitor.Enter(_syncRoot); - try - { - InnerList.CopyTo(array, arrayIndex); - } - finally - { - Monitor.Exit(_syncRoot); - } - - } - - public int BinarySearch(int index, int count, T item, IComparer? comparer) - { - throw new NotImplementedException($"BinarySearch"); - if (index < 0) - throw new ArgumentOutOfRangeException(nameof(index)); - if (count < 0) - throw new ArgumentOutOfRangeException(nameof(count)); - if (Count - index < count) - throw new ArgumentException("Invalid length"); - - //Monitor.Enter(_syncRoot); - //try - //{ - // return InnerList.BinarySearch(index, count, item, comparer); - //} - //finally - //{ - // Monitor.Exit(_syncRoot); - //} - } - - public int BinarySearch(T item) => BinarySearch(0, Count, item, null); - public int BinarySearch(T item, IComparer? comparer) => BinarySearch(0, Count, item, comparer); - - public IEnumerator GetEnumerator() - { - Monitor.Enter(_syncRoot); - try - { - //return InnerList.ToList().GetEnumerator(); - return InnerList.GetEnumerator(); - } - finally - { - Monitor.Exit(_syncRoot); - } - - } - - public ReadOnlyCollection AsReadOnly() => new(this); - private static bool IsCompatibleObject(object? value) => (value is T) || (value == null && default(T) == null); - - - #region IList, ICollection - - bool IList.IsReadOnly => false; - - object? IList.this[int index] - { - get => this[index]; - set - { - if (default(T) != null && value == null) throw new NullReferenceException(nameof(value)); - - try - { - this[index] = (T)value!; - } - catch (InvalidCastException) - { - throw new InvalidCastException(nameof(value)); - } - } - } - - int IList.Add(object? item) - { - if (default(T) != null && item == null) throw new NullReferenceException(nameof(item)); - - try - { - Add((T)item!); - } - catch (InvalidCastException) - { - throw new InvalidCastException(nameof(item)); - } - - return Count - 1; - } - - void IList.Clear() => Clear(true); - IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); - bool IList.Contains(object? item) => IsCompatibleObject(item) && Contains((T)item!); - int IList.IndexOf(object? item) => (IsCompatibleObject(item)) ? IndexOf((T)item!) : -1; - - void IList.Insert(int index, object? item) - { - if (default(T) != null && item == null) throw new NullReferenceException(nameof(item)); - - try - { - Insert(index, (T)item!); - } - catch (InvalidCastException) - { - throw new InvalidCastException(nameof(item)); - } - } - - void IList.Remove(object? item) - { - if (IsCompatibleObject(item)) Remove((T)item!); - } - - void ICollection.Clear() => Clear(true); - - void ICollection.CopyTo(Array array, int arrayIndex) - { - if ((array != null) && (array.Rank != 1)) - { - throw new ArgumentException(); - } - - try - { - Monitor.Enter(_syncRoot); - try - { - //TODO: _list.ToArray() - ez nem az igazi... - J. - Array.Copy(InnerList.ToArray(), 0, array!, arrayIndex, InnerList.Count); - } - finally - { - Monitor.Exit(_syncRoot); - } - - } - catch (ArrayTypeMismatchException) - { - throw new ArrayTypeMismatchException(); - } - } - - int ICollection.Count => Count; - int ICollection.Count => Count; - bool ICollection.IsReadOnly => false; - void IList.RemoveAt(int index) => RemoveAt(index); - int IReadOnlyCollection.Count => Count; - - #endregion IList, ICollection - } - - public class ItemChangedEventArgs where T : IId - { - internal ItemChangedEventArgs(T item, TrackingState trackingState) - { - Item = item; - TrackingState = trackingState; - } - - public T Item { get; } - public TrackingState TrackingState { get; } - } + public class SignalRDataSource(AcSignalRClientBase signalRClient, SignalRCrudTags signalRCrudTags, params Guid[]? contextIds) + : AcSignalRDataSource(signalRClient, signalRCrudTags, contextIds) where T : class, IId; } diff --git a/TIAMWebApp/Shared/Utility/SignalRDataSourceAsync.cs b/TIAMWebApp/Shared/Utility/SignalRDataSourceAsync.cs deleted file mode 100644 index d435cb51..00000000 --- a/TIAMWebApp/Shared/Utility/SignalRDataSourceAsync.cs +++ /dev/null @@ -1,104 +0,0 @@ -using System.Diagnostics; -using AyCode.Core.Enums; -using AyCode.Core.Helpers; -using AyCode.Core.Interfaces; -using AyCode.Services.SignalRs; -using TIAM.Services; -using TIAMWebApp.Shared.Application.Services; - -namespace TIAMWebApp.Shared.Application.Utility; - -[Serializable] -[DebuggerDisplay("Count = {Count}")] -public class SignalRDataSourceAsync : SignalRDataSource where T : class, IId -{ - public Action>? OnItemChanged; - public Action>? OnDataSourceLoaded; - - public SignalRDataSourceAsync(AcSignalRClientBase signalRClient, SignalRCrudTags signalRCrudTags, Guid? contextId = null, Action>? onDataSourceLoaded = null, bool autoLoadDataSource = false) - : base(signalRClient, signalRCrudTags, contextId) - { - OnDataSourceLoaded = onDataSourceLoaded; - - if (autoLoadDataSource) LoadDataSourceAsync(); - } - - public void LoadDataSourceAsync(bool clearChangeTracking = true) - { - if (SignalRCrudTags.GetAllMessageTag == SignalRTags.None) throw new ArgumentException($"_signalRCrudTags.GetAllMessageTag == SignalRTags.None;"); - - //Monitor.Exit(SyncRoot); //Exception test - J. - - //Monitor.Enter(SyncRoot); - //try - //{ - // SignalRClient.GetAllAsync>(SignalRCrudTags.GetAllMessageTag, ContextId, response => - // { - // try - // { - // if (response.Status == SignalResponseStatus.Error) throw new Exception($"LoadDataSourceAsync; response.Status == SignalResponseStatus.Error"); - // if (response.ResponseData == null) throw new NullReferenceException($"response.ResponseData == null"); - - // Clear(clearChangeTracking); - // InnerList.AddRange(response.ResponseData); - // } - // finally - // { - // Monitor.Exit(SyncRoot); - // } - - // OnDataSourceLoaded?.Invoke(this); - // }).Forget(); - //} - //catch (Exception) - //{ - // Monitor.Exit(SyncRoot); - // throw; - //} - } - - - //public T Add(T item, int messageTag) => PostDataToServerAsync(item, messageTag, TrackingState.Add).GetAwaiter().GetResult(); - //public Task AddAsync(T item, int messageTag) => PostDataToServerAsync(item, messageTag, TrackingState.Add); - - - //public Task UpdateAsync(T item, int messageTag) => PostDataToServerAsync(item, messageTag, TrackingState.Update); - - //public Task RemoveAsync(T item, int messageTag) => PostDataToServerAsync(item, messageTag, TrackingState.Remove); - - //public Task RemoveAsync(Guid id, int messageTag) - //{ - // var item = _list.FirstOrDefault(x => x.Id == id); - - // return item == null ? Task.CompletedTask : RemoveAsync(item, messageTag); - //} - - //protected virtual Task PostDataToServerAsync(T item, int messageTag, TrackingState trackingState) - //{ - // if (messageTag == 0) return Task.CompletedTask; - - // logger.Info($"{_listLogName} PostDataToServerAsync called; transferId " + item.Id); - - // if (item.Id.IsNullOrEmpty()) item.Id = Guid.NewGuid(); - - // _list.UpdateCollection(item, trackingState == TrackingState.Remove); //egyből látszódik a változás a grid-ben, nem csak a callback lefutásakor! felhasználóbarátabb... - J. - - // await _signalRClient.PostDataAsync(messageTag, item, async repsonse => - // { - // if (repsonse.Status != SignalResponseStatus.Success || repsonse.ResponseData == null) - // { - // RefreshDataSourceAsync().Forget(); - // return; - // } - - // _list.UpdateCollection(repsonse.ResponseData, trackingState == TrackingState.Remove); - - // var eventArgs = new ItemChangedEventArgs(repsonse.ResponseData, trackingState); - // OnItemChanged.Invoke(eventArgs); - // }); - - // //transfer = await devAdminSignalClient.PostDataAsync(SignalRTags.UpdateTransferAsync, transfer); - - // return Task.CompletedTask; - //} -} \ No newline at end of file diff --git a/TIAMWebApp/Shared/Utility/TrackingItemHelpers.cs b/TIAMWebApp/Shared/Utility/TrackingItemHelpers.cs deleted file mode 100644 index 34b5eadc..00000000 --- a/TIAMWebApp/Shared/Utility/TrackingItemHelpers.cs +++ /dev/null @@ -1,47 +0,0 @@ -using System.Reflection; -using System.Text.Json; -using AyCode.Core.Extensions; - -namespace TIAMWebApp.Shared.Application.Utility; - -public static class TrackingItemHelpers -{ - public static T JsonClone(T source) => source.ToJson().JsonTo()!; - - public static T ReflectionClone(T source) - { - var type = source!.GetType(); - - if (type.IsPrimitive || typeof(string) == type) - return source; - - if (type.IsArray) - { - var elementType = Type.GetType(type.FullName!.Replace("[]", string.Empty))!; - var array = (source as Array)!; - var cloned = Array.CreateInstance(elementType, array.Length); - - for (var i = 0; i < array.Length; i++) - cloned.SetValue(ReflectionClone(array.GetValue(i)), i); - - return (T)Convert.ChangeType(cloned, type); - } - - var clone = Activator.CreateInstance(type); - - while (type != null && type != typeof(object)) - { - foreach (var field in type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)) - { - var fieldValue = field.GetValue(source); - if (fieldValue == null) continue; - - field.SetValue(clone, ReflectionClone(fieldValue)); - } - - type = type.BaseType; - } - - return (T)clone!; - } -} \ No newline at end of file diff --git a/Tiam.Services.Client.Tests/SignalRClientTest.cs b/Tiam.Services.Client.Tests/SignalRClientTest.cs new file mode 100644 index 00000000..c45a099e --- /dev/null +++ b/Tiam.Services.Client.Tests/SignalRClientTest.cs @@ -0,0 +1,88 @@ +using AyCode.Core.Enums; +using AyCode.Core.Helpers; +using AyCode.Core.Loggers; +using AyCode.Services.Loggers; +using AyCode.Services.SignalRs; +using Azure; +using TIAM.Core.Loggers; +using TIAM.Entities.ServiceProviders; +using TIAM.Services; +using TIAMWebApp.Shared.Application.Services; +using TIAMWebApp.Shared.Application.Utility; + +namespace Tiam.Services.Client.Tests +{ + [TestClass] + public class SignalRClientTest //: TestModelBase + { + private const string CompanyIdString = "3587F169-683C-4EEE-BCB5-E8D57F8C6DCE"; + + private readonly AdminSignalRClient _signalRClient = new(new List { new SignaRClientLogItemWriter(AppType.TestUnit, LogLevel.Detail, nameof(SignalRClientTest)) }); + + [TestInitialize] + public void TestInitialize() + { } + + [TestCleanup] + public void TearDown() + { } + + [DataTestMethod] + [DataRow(CompanyIdString)] + public async Task GetCompanyTest_ReturnCompany_WhenHasCompany(string companyIdString) + { + var companyId = Guid.Parse(companyIdString); + var company = await _signalRClient.GetByIdAsync(SignalRTags.GetCompany, companyId); + + Assert.IsNotNull(company); + } + + [DataTestMethod] + [DataRow(CompanyIdString)] + public async Task GetCompanyAsyncTest_ReturnCompany_WhenHasCompany(string companyIdString) + { + Company? company = null; + var companyId = Guid.Parse(companyIdString); + + await _signalRClient.GetByIdAsync(SignalRTags.GetCompany, response => + { + Assert.IsNotNull(response.ResponseData); + Assert.IsTrue(response.Status == SignalResponseStatus.Success); + + company = response.ResponseData; + }, companyId); + + await TaskHelper.WaitToAsync(() => company != null, 5000, 50); + + Assert.IsNotNull(company); + } + + [TestMethod] + public async Task GetAllCompanyTest_ReturnCompanies_WhenHasCompanies() + { + var companies = await _signalRClient.GetAllAsync>(SignalRTags.GetCompanies); + + Assert.IsNotNull(companies); + Assert.IsTrue(companies.Count > 0); + } + + [TestMethod] + public async Task GetAllCompanyAsyncTest_ReturnCompanies_WhenHasCompanies() + { + List? companies = null; + + await _signalRClient.GetAllAsync>(SignalRTags.GetCompanies, response => + { + Assert.IsNotNull(response.ResponseData); + Assert.IsTrue(response.Status == SignalResponseStatus.Success); + + companies = response.ResponseData; + }); + + await TaskHelper.WaitToAsync(() => companies != null, 5000, 50); + + Assert.IsNotNull(companies); + Assert.IsTrue(companies.Count > 0); + } + } +} \ No newline at end of file diff --git a/Tiam.Services.Client.Tests/SignalRDataSourceTest.cs b/Tiam.Services.Client.Tests/SignalRDataSourceTest.cs new file mode 100644 index 00000000..ee39a418 --- /dev/null +++ b/Tiam.Services.Client.Tests/SignalRDataSourceTest.cs @@ -0,0 +1,104 @@ +using System.Linq.Expressions; +using AyCode.Core.Enums; +using AyCode.Core.Extensions; +using AyCode.Core.Helpers; +using AyCode.Core.Loggers; +using AyCode.Services.Loggers; +using AyCode.Services.SignalRs; +using Azure; +using DevExpress.DashboardBlazor; +using DevExpress.Data.Filtering; +using DevExpress.Data.Linq; +using DevExpress.Data.Linq.Helpers; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using TIAM.Core.Loggers; +using TIAM.Database.DataLayers.Admins; +using TIAM.Entities.ServiceProviders; +using TIAM.Entities.Transfers; +using TIAM.Services; +using TIAMSharedUI.Shared; +using TIAMWebApp.Shared.Application.Services; +using TIAMWebApp.Shared.Application.Utility; + +namespace Tiam.Services.Client.Tests +{ + [TestClass] + public class SignalRDataSourceTest //: TestModelBase + { + private const string UserIdString = "540271F6-C604-4C16-8160-D5A7CAFEDF00"; + private const string CompanyIdString = "3587F169-683C-4EEE-BCB5-E8D57F8C6DCE"; + private const string TransferIdString = "108E5A63-AA9E-47BE-ACFA-00306FFC5215"; + + private readonly SignalRDataSource _signalRDataSource = new(new AdminSignalRClient(new List { new SignaRClientLogItemWriter(AppType.TestUnit, LogLevel.Detail, nameof(SignalRDataSourceTest)) }), + SignalRTiamCrudTags.TransferByUserCrudTags, Guid.Parse(UserIdString)); + + + [TestInitialize] + public async Task TestInitialize() + { + var userId = Guid.Parse(UserIdString); + await _signalRDataSource.LoadDataSource(); + + Assert.IsTrue(_signalRDataSource.Count > 0); + Assert.IsTrue(_signalRDataSource.All(x => x.UserId == userId)); + } + + [TestCleanup] + public void TearDown() + { + } + + [DataTestMethod] + [DataRow(TransferIdString)] + public void GetTransferTest_ReturnTransfer_WhenHasTransfer(string transferIdString) + { + var transferId = Guid.Parse(transferIdString); + _signalRDataSource.TryGetValue(transferId, out var transfer); + + Assert.IsNotNull(transfer); + } + + [DataTestMethod] + [DataRow(TransferIdString)] + public async Task UpdateTransferLuggageTest_ReturnTransfer_WhenDbTransferEquals(string transferIdString) + { + var transferId = Guid.Parse(transferIdString); + _signalRDataSource.TryGetValue(transferId, out var transfer); + + Assert.IsNotNull(transfer); + + var luggageCount = (byte)(new Random().Next(0, 5)); + transfer.LuggageCount = luggageCount; + + await _signalRDataSource.SaveItem(transferId, TrackingState.Update); + Assert.IsTrue(transfer.LuggageCount == luggageCount); + + var dbTransfer = await _signalRDataSource.SignalRClient.GetByIdAsync(SignalRTags.GetTransfer, transferId); + + Assert.IsNotNull(dbTransfer); + Assert.IsTrue(dbTransfer.LuggageCount == luggageCount); + } + + [DataTestMethod] + public void FilterExpressionTest_WhenTransfersFiletered() + { + var converter = new CriteriaToExpressionConverter(); + //CriteriaOperator critOps = CriteriaOperator.Parse(tdashboard.EmployeeFilter); + var criteriaString = CriteriaOperator.FromLambda(x => x.LuggageCount == 1).ToString(); + + //var json = criteria.AsQueryable().Expression.ToJson(); + //criteria = JsonConvert.DeserializeObject(json); + var criteria = CriteriaOperator.Parse(criteriaString); + + //_signalRDataSource.AsQueryable().Expression. + var filteredData = _signalRDataSource.AsQueryable().AppendWhere(converter, criteria) as IQueryable; + + Assert.IsNotNull(filteredData); + var filteredTransfers = _signalRDataSource.AsQueryable().Provider.CreateQuery(filteredData.Expression).ToList(); + + Assert.IsNotNull(filteredTransfers); + Assert.IsTrue(filteredTransfers.All(x => x.LuggageCount == 1)); + } + } +} \ No newline at end of file diff --git a/Tiam.Services.Client.Tests/Tiam.Services.Client.Tests.csproj b/Tiam.Services.Client.Tests/Tiam.Services.Client.Tests.csproj new file mode 100644 index 00000000..050f7d60 --- /dev/null +++ b/Tiam.Services.Client.Tests/Tiam.Services.Client.Tests.csproj @@ -0,0 +1,57 @@ + + + + net8.0 + enable + enable + + false + true + + + + + + + + + + + + + + + + + + + + + + + + + ..\..\AyCode.Core\AyCode.Services.Server\bin\Debug\net8.0\AyCode.Core.dll + + + ..\..\AyCode.Core\AyCode.Services.Server\bin\Debug\net8.0\AyCode.Entities.dll + + + ..\..\AyCode.Core\AyCode.Services.Server\bin\Debug\net8.0\AyCode.Interfaces.dll + + + ..\..\AyCode.Core\AyCode.Services.Server\bin\Debug\net8.0\AyCode.Models.dll + + + ..\..\AyCode.Core\AyCode.Services.Server\bin\Debug\net8.0\AyCode.Services.dll + + + ..\..\AyCode.Core\AyCode.Services.Server\bin\Debug\net8.0\AyCode.Utils.dll + + + + + + + + diff --git a/TourIAmProject.sln b/TourIAmProject.sln index 51b220c4..cce08d4f 100644 --- a/TourIAmProject.sln +++ b/TourIAmProject.sln @@ -50,6 +50,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TIAM.Services.Server.Tests" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TIAM.Models.Server", "TIAM.Models.Server\TIAM.Models.Server.csproj", "{D21032B0-B25F-495E-B784-1D3166FE720C}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tiam.Services.Client.Tests", "Tiam.Services.Client.Tests\Tiam.Services.Client.Tests.csproj", "{EF40BC68-945A-47ED-8739-2D0BCD415019}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -142,6 +144,10 @@ Global {D21032B0-B25F-495E-B784-1D3166FE720C}.Debug|Any CPU.Build.0 = Debug|Any CPU {D21032B0-B25F-495E-B784-1D3166FE720C}.Release|Any CPU.ActiveCfg = Release|Any CPU {D21032B0-B25F-495E-B784-1D3166FE720C}.Release|Any CPU.Build.0 = Release|Any CPU + {EF40BC68-945A-47ED-8739-2D0BCD415019}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EF40BC68-945A-47ED-8739-2D0BCD415019}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EF40BC68-945A-47ED-8739-2D0BCD415019}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EF40BC68-945A-47ED-8739-2D0BCD415019}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE