From 1a15ab4128ee8ab7af4f90d93522a198051d59c2 Mon Sep 17 00:00:00 2001
From: "jozsef.b@aycode.com" <9Rj@D}fVwBaN>
Date: Tue, 4 Jun 2024 15:32:58 +0200
Subject: [PATCH 1/5] improvements, fixes
---
.../Pages/User/MyServiceProviders.razor | 8 ++++-
.../AddressDetailGridComponent.razor | 12 +++----
.../User/SysAdmins/AddressGridComponent.razor | 9 ++---
.../SysAdmins/ManageServiceProviders.razor | 17 +++++-----
.../User/SysAdmins/ManageTransfers.razor | 25 +++++++-------
.../User/SysAdmins/ProfileGridComponent.razor | 3 +-
.../ServiceProviderGridComponent.razor | 5 +--
.../TransferToDriverGridComponent.razor | 3 +-
.../UserProductMappingGridComponent.razor | 3 +-
.../Shared/Components/Grids/TiamGrid.cs | 34 +++++++++++++++----
.../Server/Services/DevAdminSignalRhub.cs | 13 +++++--
11 files changed, 87 insertions(+), 45 deletions(-)
diff --git a/TIAMSharedUI/Pages/User/MyServiceProviders.razor b/TIAMSharedUI/Pages/User/MyServiceProviders.razor
index fd04f340..87e89e70 100644
--- a/TIAMSharedUI/Pages/User/MyServiceProviders.razor
+++ b/TIAMSharedUI/Pages/User/MyServiceProviders.razor
@@ -68,7 +68,8 @@
PageSize="12"
KeyFieldName="Id"
- ValidationEnabled="false"
+ ValidationEnabled="false"
+ DetailRowDisplayMode="GridDetailRowDisplayMode.Always"
CustomizeEditModel="Grid_CustomizeEditModel"
EditMode="GridEditMode.EditRow"
KeyboardNavigationEnabled="true">
@@ -83,6 +84,11 @@
+
+ @{
+ @(((Company)context.DataItem).Profile.Address.AddressText)
+ }
+
diff --git a/TIAMSharedUI/Pages/User/SysAdmins/AddressDetailGridComponent.razor b/TIAMSharedUI/Pages/User/SysAdmins/AddressDetailGridComponent.razor
index 2d99bc54..68cfa3c5 100644
--- a/TIAMSharedUI/Pages/User/SysAdmins/AddressDetailGridComponent.razor
+++ b/TIAMSharedUI/Pages/User/SysAdmins/AddressDetailGridComponent.razor
@@ -13,6 +13,7 @@
@using TIAMSharedUI.Pages.Components.EditComponents
@using TIAMWebApp.Shared.Application.Services
@using AyCode.Interfaces.Addresses
+@using AyCode.Core
@inject IServiceProviderDataService serviceProviderDataService
@inject IUserDataService userDataService
@inject ITransferDataService transferDataService
@@ -37,15 +38,14 @@
ColumnResizeMode="GridColumnResizeMode.NextColumn"
ShowFilterRow="false">
-
-
+
+
-
-
+
+
-
-
+
@{
diff --git a/TIAMSharedUI/Pages/User/SysAdmins/AddressGridComponent.razor b/TIAMSharedUI/Pages/User/SysAdmins/AddressGridComponent.razor
index 0168bab4..532c8c49 100644
--- a/TIAMSharedUI/Pages/User/SysAdmins/AddressGridComponent.razor
+++ b/TIAMSharedUI/Pages/User/SysAdmins/AddressGridComponent.razor
@@ -11,6 +11,7 @@
@using TIAM.Entities.Addresses
@using TIAMSharedUI.Shared.Components.Grids
@using TIAMSharedUI.Pages.Components.EditComponents
+@using AyCode.Core
@inject IServiceProviderDataService serviceProviderDataService
@inject IUserDataService userDataService
@inject ITransferDataService transferDataService
@@ -30,11 +31,11 @@
ColumnResizeMode="GridColumnResizeMode.NextColumn"
ShowFilterRow="true">
-
-
+
+
-
-
+
+
diff --git a/TIAMSharedUI/Pages/User/SysAdmins/ManageServiceProviders.razor b/TIAMSharedUI/Pages/User/SysAdmins/ManageServiceProviders.razor
index ab7f7ea7..18247ea6 100644
--- a/TIAMSharedUI/Pages/User/SysAdmins/ManageServiceProviders.razor
+++ b/TIAMSharedUI/Pages/User/SysAdmins/ManageServiceProviders.razor
@@ -12,6 +12,7 @@
@using AyCode.Core.Extensions;
@using TIAM.Entities.Addresses
@using TIAMSharedUI.Shared.Components.Grids
+@using AyCode.Core
@layout AdminLayout
@inject IEnumerable LogWriters
@inject IStringLocalizer localizer
@@ -92,29 +93,29 @@
KeyFieldName="Id">
-
-
+
+
-
+
@{
var keyField = context.Value as Guid?;
- var keyItem = (Company)context.DataItem;
if (keyField.IsNullOrEmpty())
{
-
+
}
else
{
- @keyField
+ @keyField.Value.ToString("N")
}
}
-
+
-
+
+
@*
*@
diff --git a/TIAMSharedUI/Pages/User/SysAdmins/ManageTransfers.razor b/TIAMSharedUI/Pages/User/SysAdmins/ManageTransfers.razor
index 842507d3..6401fa80 100644
--- a/TIAMSharedUI/Pages/User/SysAdmins/ManageTransfers.razor
+++ b/TIAMSharedUI/Pages/User/SysAdmins/ManageTransfers.razor
@@ -104,22 +104,22 @@
KeyFieldName="Id">
-
-
+
+
@{
- var idKeyField = ((Transfer)context.DataItem).Id as Guid?;
- var editUri = $"mytransfers/{idKeyField}";
+ var idKeyField = ((Transfer)context.DataItem).Id;
+ var editUri = $"mytransfers/{idKeyField:N}";
- @context.Value
+ @context.Value
}
-
+
-
+
@@ -139,7 +139,7 @@
TransferStatusModel keyField = Statuses.FirstOrDefault(x => x.StatusValue == Convert.ToInt16(context.Value));
string transferStatusText = keyField.StatusName;
- @transferStatusText
+ @transferStatusText
}
@@ -156,16 +156,15 @@
+ ContextId="((Transfer)context.DataItem).Id">
-
-
+
+
-
+
diff --git a/TIAMSharedUI/Pages/User/SysAdmins/ProfileGridComponent.razor b/TIAMSharedUI/Pages/User/SysAdmins/ProfileGridComponent.razor
index 7fe56619..9250f1d7 100644
--- a/TIAMSharedUI/Pages/User/SysAdmins/ProfileGridComponent.razor
+++ b/TIAMSharedUI/Pages/User/SysAdmins/ProfileGridComponent.razor
@@ -5,6 +5,7 @@
@using TIAMWebApp.Shared.Application.Utility
@using AyCode.Services.Loggers
@using TIAM.Core.Loggers
+@using AyCode.Core
@inject IServiceProviderDataService serviceProviderDataService
@inject IUserDataService userDataService
@inject IEnumerable LogWriters
@@ -26,7 +27,7 @@
ShowFilterRow="true">
-
+
diff --git a/TIAMSharedUI/Pages/User/SysAdmins/ServiceProviderGridComponent.razor b/TIAMSharedUI/Pages/User/SysAdmins/ServiceProviderGridComponent.razor
index f3c1a5e1..54fd580e 100644
--- a/TIAMSharedUI/Pages/User/SysAdmins/ServiceProviderGridComponent.razor
+++ b/TIAMSharedUI/Pages/User/SysAdmins/ServiceProviderGridComponent.razor
@@ -8,6 +8,7 @@
@using TIAMWebApp.Shared.Application.Utility
@using AyCode.Services.Loggers
@using TIAM.Core.Loggers
+@using AyCode.Core
@inject IServiceProviderDataService ServiceProviderDataService
@inject IEnumerable LogWriters
@@ -27,8 +28,8 @@
ColumnResizeMode="GridColumnResizeMode.NextColumn"
ShowFilterRow="true">
-
-
+
+
diff --git a/TIAMSharedUI/Pages/User/SysAdmins/TransferToDriverGridComponent.razor b/TIAMSharedUI/Pages/User/SysAdmins/TransferToDriverGridComponent.razor
index 030b7790..4984cf08 100644
--- a/TIAMSharedUI/Pages/User/SysAdmins/TransferToDriverGridComponent.razor
+++ b/TIAMSharedUI/Pages/User/SysAdmins/TransferToDriverGridComponent.razor
@@ -10,6 +10,7 @@
@using TIAMWebApp.Shared.Application.Services
@using AyCode.Core.Enums
@using AyCode.Core.Extensions
+@using AyCode.Core
@inject IUserDataService UserDataService
@inject IEnumerable LogWriters
@inject AdminSignalRClient AdminSignalRClient;
@@ -34,7 +35,7 @@
ShowFilterRow="false">
-
+
diff --git a/TIAMSharedUI/Pages/User/SysAdmins/UserProductMappingGridComponent.razor b/TIAMSharedUI/Pages/User/SysAdmins/UserProductMappingGridComponent.razor
index 66afd837..82e3b586 100644
--- a/TIAMSharedUI/Pages/User/SysAdmins/UserProductMappingGridComponent.razor
+++ b/TIAMSharedUI/Pages/User/SysAdmins/UserProductMappingGridComponent.razor
@@ -8,6 +8,7 @@
@using TIAM.Core.Loggers
@using AyCode.Core.Loggers
@using AyCode.Services.Loggers
+@using AyCode.Core
@inject IServiceProviderDataService ServiceProviderDataService
@inject IEnumerable LogWriters
@@ -26,7 +27,7 @@
ShowFilterRow="true">
-
+
diff --git a/TIAMSharedUI/Shared/Components/Grids/TiamGrid.cs b/TIAMSharedUI/Shared/Components/Grids/TiamGrid.cs
index d159ee18..0dbdf208 100644
--- a/TIAMSharedUI/Shared/Components/Grids/TiamGrid.cs
+++ b/TIAMSharedUI/Shared/Components/Grids/TiamGrid.cs
@@ -4,10 +4,12 @@ using AyCode.Core.Enums;
using AyCode.Core.Extensions;
using AyCode.Core.Helpers;
using AyCode.Core.Interfaces;
+using AyCode.Interfaces.Entities;
using AyCode.Services.SignalRs;
using AyCode.Utils.Extensions;
using DevExpress.Blazor;
using Microsoft.AspNetCore.Components;
+using Microsoft.AspNetCore.Components.Web;
using TIAMWebApp.Shared.Application.Services;
using TIAMWebApp.Shared.Application.Utility;
@@ -16,7 +18,8 @@ namespace TIAMSharedUI.Shared.Components.Grids
public class GridDataItemChangingEventArgs : GridDataItemChangedEventArgs where TDataItem : class, IId
{
internal GridDataItemChangingEventArgs(TiamGrid grid, TDataItem dataItem, DataChangeMode dataChangeMode) : base(grid, dataItem, dataChangeMode)
- { }
+ {
+ }
public bool IsCanceled { get; set; }
}
@@ -42,7 +45,8 @@ namespace TIAMSharedUI.Shared.Components.Grids
private string _gridLogName;
public TiamGrid() : base()
- { }
+ {
+ }
[Parameter] public LoggerClient Logger { get; set; }
[Parameter] public string GridName { get; set; }
@@ -56,7 +60,7 @@ namespace TIAMSharedUI.Shared.Components.Grids
[Parameter] public int RemoveMessageTag { get; set; }
protected new EventCallback DataItemDeleting { get; set; }
- [Parameter] public EventCallback OnDataItemDeleting{ get; set; }
+ [Parameter] public EventCallback OnDataItemDeleting { get; set; }
protected new EventCallback EditModelSaving { get; set; }
[Parameter] public EventCallback OnEditModelSaving { get; set; }
@@ -111,6 +115,8 @@ namespace TIAMSharedUI.Shared.Components.Grids
if (firstRender)
{
if (_dataSource == null || _dataSource.Count == 0) RefreshDataSourceAsync().Forget();
+
+ //AutoFitColumnWidths();
}
}
@@ -124,6 +130,7 @@ namespace TIAMSharedUI.Shared.Components.Grids
public Task RemoveDataItem(TDataItem dataItem, int messageTag) => PostDataToServerAsync(dataItem, messageTag, DataChangeMode.Remove);
public Task RemoveDataItem(Guid id) => RemoveDataItem(id, RemoveMessageTag);
+
public Task RemoveDataItem(Guid id, int messageTag)
{
var dataItem = _dataSource.FirstOrDefault(x => x.Id == id);
@@ -161,7 +168,7 @@ namespace TIAMSharedUI.Shared.Components.Grids
Logger.Debug($"{_gridLogName} OnItemDeleting canceled");
return;
}
-
+
var dataItem = (e.DataItem as TDataItem)!;
await RemoveDataItem(dataItem);
}
@@ -221,13 +228,28 @@ namespace TIAMSharedUI.Shared.Components.Grids
//transfer = await devAdminSignalClient.PostDataAsync(SignalRTags.UpdateTransferAsync, transfer);
}
+
+ private void OnCustomizeElement(GridCustomizeElementEventArgs e)
+ {
+ if (e.ElementType == GridElementType.DetailCell)
+ {
+ e.Style = "padding: 0.5rem; opacity: 0.75";
+ }
+ else if (false && e.ElementType == GridElementType.DataCell && e.Column.Name == nameof(IId.Id))
+ {
+ e.Column.Visible = AcDomain.IsDeveloperVersion;
+ e.Column.ShowInColumnChooser = AcDomain.IsDeveloperVersion;
+ }
+ }
+
protected override Task SetParametersAsyncCore(ParameterView parameters)
{
if (!IsFirstInitializeParameters)
{
base.DataItemDeleting = EventCallback.Factory.Create(this, OnItemDeleting);
base.EditModelSaving = EventCallback.Factory.Create(this, OnItemSaving);
-
+ CustomizeElement += OnCustomizeElement;
+
//ShowFilterRow = true;
//PageSize = 4;
//ShowGroupPanel = true;
@@ -235,7 +257,6 @@ namespace TIAMSharedUI.Shared.Components.Grids
TextWrapEnabled = false;
- //var columns = GetColumns();
//var dataColumns = GetDataColumns();
//var idColumn = dataColumns.FirstOrDefault(x => x.FieldName == nameof(IId.Id));
@@ -251,6 +272,7 @@ namespace TIAMSharedUI.Shared.Components.Grids
return base.SetParametersAsyncCore(parameters);
}
+
protected override void OnParametersSet()
{
base.OnParametersSet();
diff --git a/TIAMWebApp/Server/Services/DevAdminSignalRhub.cs b/TIAMWebApp/Server/Services/DevAdminSignalRhub.cs
index 07d738f7..be9b565f 100644
--- a/TIAMWebApp/Server/Services/DevAdminSignalRhub.cs
+++ b/TIAMWebApp/Server/Services/DevAdminSignalRhub.cs
@@ -14,6 +14,10 @@ using System.Runtime.CompilerServices;
using MessagePack;
using TIAM.Entities.Addresses;
using TIAM.Entities.Profiles;
+using Microsoft.AspNetCore.Hosting;
+using System.Collections.Generic;
+using TIAM.Entities.Emails;
+using TIAM.Services.Server;
namespace TIAMWebApp.Server.Services;
@@ -57,7 +61,11 @@ public class DynamicMethodCallModel where TAttribute : TagAttribute
public object InstanceObject { get; init; }
public ConcurrentDictionary> MethodsByMessageTag { get; init; } = new();
- public DynamicMethodCallModel(Type instanceObjectType) : this(Activator.CreateInstance(instanceObjectType)!)
+
+ public DynamicMethodCallModel(Type instanceObjectType) : this(instanceObjectType, null!)
+ { }
+
+ public DynamicMethodCallModel(Type instanceObjectType, params object[] constructorParams) : this(Activator.CreateInstance(instanceObjectType, constructorParams)!)
{ }
public DynamicMethodCallModel(object instanceObject)
@@ -75,7 +83,7 @@ public class DynamicMethodCallModel where TAttribute : TagAttribute
public class DevAdminSignalRHub : Hub, IAcSignalRHubServer
{
- private readonly List> _dynamicMethodCallModels = new();
+ private readonly List> _dynamicMethodCallModels = [];
private readonly TIAM.Core.Loggers.Logger _logger;
private readonly AdminDal _adminDal;
@@ -93,6 +101,7 @@ public class DevAdminSignalRHub : Hub, IAcSignalRHubServe
_dynamicMethodCallModels.Add(new DynamicMethodCallModel(serviceProviderApiController));
_dynamicMethodCallModels.Add(new DynamicMethodCallModel(transferDataApiController));
_dynamicMethodCallModels.Add(new DynamicMethodCallModel(messageApiController));
+ //_dynamicMethodCallModels.Add(new DynamicMethodCallModel(typeof(AdminDal)));
}
From 4f97dcec4cee8bfcc402f2eedcdf8da50031f6e9 Mon Sep 17 00:00:00 2001
From: "jozsef.b@aycode.com" <9Rj@D}fVwBaN>
Date: Wed, 5 Jun 2024 16:00:02 +0200
Subject: [PATCH 2/5] Add SignalRDataSource, SignalRDataSourceAsync
---
TIAM.Services/SignalRTags.cs | 2 +
.../Shared/Components/Grids/TiamGrid.cs | 16 +-
.../Shared/Services/AcSignalRClientBase.cs | 7 +-
.../Shared/Utility/SignalRDataSource.cs | 380 ++++++++++++++++++
.../Shared/Utility/SignalRDataSourceAsync.cs | 117 ++++++
5 files changed, 513 insertions(+), 9 deletions(-)
create mode 100644 TIAMWebApp/Shared/Utility/SignalRDataSource.cs
create mode 100644 TIAMWebApp/Shared/Utility/SignalRDataSourceAsync.cs
diff --git a/TIAM.Services/SignalRTags.cs b/TIAM.Services/SignalRTags.cs
index 398b13a0..684bfbd6 100644
--- a/TIAM.Services/SignalRTags.cs
+++ b/TIAM.Services/SignalRTags.cs
@@ -4,6 +4,8 @@ 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;
diff --git a/TIAMSharedUI/Shared/Components/Grids/TiamGrid.cs b/TIAMSharedUI/Shared/Components/Grids/TiamGrid.cs
index 0dbdf208..356e92f0 100644
--- a/TIAMSharedUI/Shared/Components/Grids/TiamGrid.cs
+++ b/TIAMSharedUI/Shared/Components/Grids/TiamGrid.cs
@@ -194,10 +194,10 @@ namespace TIAMSharedUI.Shared.Components.Grids
protected virtual async Task PostDataToServerAsync(TDataItem dataItem, int messageTag, DataChangeMode dataChangeMode)
{
- var eventArgs = new GridDataItemChangingEventArgs(this, dataItem, dataChangeMode);
- await OnDataItemChanging.InvokeAsync(eventArgs);
+ var changingEventArgs = new GridDataItemChangingEventArgs(this, dataItem, dataChangeMode);
+ await OnDataItemChanging.InvokeAsync(changingEventArgs);
- if (eventArgs.IsCanceled)
+ if (changingEventArgs.IsCanceled)
{
Logger.Debug($"{_gridLogName} OnDataItemChanging canceled");
return;
@@ -211,17 +211,19 @@ namespace TIAMSharedUI.Shared.Components.Grids
_dataSource.UpdateCollection(dataItem, dataChangeMode == DataChangeMode.Remove); //egyből látszódik a változás a grid-ben, nem csak a callback lefutásakor! felhasználóbarátabb... - J.
- SignalRClient.PostDataAsync(messageTag, dataItem, async repsonse =>
+ SignalRClient.PostDataAsync(messageTag, dataItem, async response =>
{
- if (repsonse.Status != SignalResponseStatus.Success || repsonse.ResponseData == null)
+ if (response.Status != SignalResponseStatus.Success || response.ResponseData == null)
{
RefreshDataSourceAsync().Forget();
return;
}
- _dataSource.UpdateCollection(repsonse.ResponseData, dataChangeMode == DataChangeMode.Remove);
+ _dataSource.UpdateCollection(response.ResponseData, dataChangeMode == DataChangeMode.Remove);
+
+ var changedEventArgs = new GridDataItemChangedEventArgs(this, response.ResponseData, dataChangeMode);
+ await OnDataItemChanged.InvokeAsync(changedEventArgs);
- await OnDataItemChanged.InvokeAsync(eventArgs);
InvokeAsync(StateHasChanged).Forget();
}).Forget();
diff --git a/TIAMWebApp/Shared/Services/AcSignalRClientBase.cs b/TIAMWebApp/Shared/Services/AcSignalRClientBase.cs
index cefac36e..b9200d75 100644
--- a/TIAMWebApp/Shared/Services/AcSignalRClientBase.cs
+++ b/TIAMWebApp/Shared/Services/AcSignalRClientBase.cs
@@ -94,13 +94,16 @@ namespace TIAMWebApp.Shared.Application.Services
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 TResponse : class
- => SendMessageToServerAsync(messageTag);
+ 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
diff --git a/TIAMWebApp/Shared/Utility/SignalRDataSource.cs b/TIAMWebApp/Shared/Utility/SignalRDataSource.cs
new file mode 100644
index 00000000..37780551
--- /dev/null
+++ b/TIAMWebApp/Shared/Utility/SignalRDataSource.cs
@@ -0,0 +1,380 @@
+using System.Collections;
+using System.Collections.ObjectModel;
+using System.Diagnostics;
+using AyCode.Core.Enums;
+using AyCode.Core.Extensions;
+using AyCode.Core.Interfaces;
+using AyCode.Services.SignalRs;
+using TIAM.Services;
+using TIAMWebApp.Shared.Application.Services;
+
+namespace TIAMWebApp.Shared.Application.Utility
+{
+ public class ChangeTracking(DataChangeMode dataChangeMode, T newItem, T originalItem = default(T))where T: class, IId
+ {
+ public DataChangeMode DataChangeMode { get; init; } = dataChangeMode;
+ public T NewItem { get; init; } = newItem;
+ public T OriginalItem { get; init; } = originalItem;
+ }
+
+ [Serializable]
+ [DebuggerDisplay("Count = {Count}")]
+ public class SignalRDataSource : IList, IList, IReadOnlyList where T: class, IId
+ {
+ protected readonly List InnerList = [];
+ private readonly object _syncRoot = new();
+
+ protected Guid? ContextId;
+ protected AcSignalRClientBase SignalRClient;
+ protected readonly SignalRCrudTags SignalRCrudTags;
+
+ public SignalRDataSource(AcSignalRClientBase signalRClient, SignalRCrudTags signalRCrudTags, Guid? contextId = null, bool autoLoadDataSource = true)
+ {
+ ContextId = contextId;
+
+ SignalRCrudTags = signalRCrudTags;
+ SignalRClient = signalRClient;
+
+ if (autoLoadDataSource) LoadDataSource();
+ }
+
+ public bool IsSynchronized => true;
+ public object SyncRoot => _syncRoot;
+ public bool IsFixedSize => false;
+
+ ///
+ /// GetAllMessageTag
+ ///
+ ///
+ ///
+ public void LoadDataSource()
+ {
+ if (SignalRCrudTags.GetAllMessageTag == SignalRTags.None) throw new ArgumentException($"_signalRCrudTags.GetAllMessageTag == SignalRTags.None;");
+
+ lock (_syncRoot)
+ {
+ var resultList = SignalRClient.GetAllAsync>(SignalRCrudTags.GetAllMessageTag, ContextId).GetAwaiter().GetResult() ?? throw new NullReferenceException();
+
+ Clear();
+ InnerList.AddRange(resultList);
+ }
+ }
+
+ ///
+ /// set: UpdateMessageTag
+ ///
+ ///
+ ///
+ ///
+ public T this[int index]
+ {
+ get
+ {
+ if ((uint)index >= (uint)Count) throw new ArgumentOutOfRangeException(nameof(index));
+
+ lock (_syncRoot)
+ {
+ return InnerList[index];
+ }
+ }
+ set
+ {
+ lock (_syncRoot)
+ {
+ Update(index, value);
+ }
+ }
+ }
+
+ public int Count
+ {
+ get
+ {
+ lock (_syncRoot) return InnerList.Count;
+ }
+ }
+
+ ///
+ /// AddMessageTag
+ ///
+ ///
+ ///
+ public void Add(T item)
+ {
+ lock (_syncRoot)
+ {
+ if (Contains(item))
+ throw new ArgumentException($@"It already contains this Id! Id: {item.Id}", nameof(item));
+
+ UnsafeAdd(item);
+ }
+ }
+
+ ///
+ /// AddMessageTag or UpdateMessageTag
+ ///
+ ///
+ ///
+ public T AddOrUpdate(T item)
+ {
+ lock (_syncRoot)
+ {
+ var index = IndexOf(item);
+
+ return index > -1 ? Update(index, item) : UnsafeAdd(item);
+ }
+ }
+
+ //public void AddRange(IEnumerable collection)
+ //{
+ // lock (_syncRoot)
+ // {
+
+ // }
+ //}
+
+ private T UnsafeAdd(T item)
+ {
+ if (SignalRCrudTags.AddMessageTag == SignalRTags.None) throw new ArgumentException($"_signalRCrudTags.AddMessageTag == SignalRTags.None;");
+
+ var result = SignalRClient.PostDataAsync(SignalRCrudTags.AddMessageTag, item).GetAwaiter().GetResult() ?? throw new NullReferenceException();
+ InnerList.Add(result);
+
+ return result;
+ }
+
+ ///
+ /// AddMessageTag
+ ///
+ ///
+ ///
+ ///
+ ///
+ public void Insert(int index, T item)
+ {
+ if (SignalRCrudTags.AddMessageTag == SignalRTags.None) throw new ArgumentException($"_signalRCrudTags.AddMessageTag == SignalRTags.None;");
+
+ lock (_syncRoot)
+ {
+ if (Contains(item))
+ throw new ArgumentException($@"It already contains this Id! Id: {item.Id}", nameof(item));
+
+ var result = SignalRClient.PostDataAsync(SignalRCrudTags.AddMessageTag, item).GetAwaiter().GetResult() ?? throw new NullReferenceException();
+ InnerList.Insert(index, result);
+ }
+ }
+
+ ///
+ /// UpdateMessageTag
+ ///
+ ///
+ public T Update(T item) => Update(IndexOf(item), item);
+
+ ///
+ /// UpdateMessageTag
+ ///
+ ///
+ ///
+ /// ///
+ /// ///
+ ///
+ ///
+ public T Update(int index, T item)
+ {
+ if (SignalRCrudTags.UpdateMessageTag == SignalRTags.None) throw new ArgumentException($"_signalRCrudTags.UpdateMessageTag == SignalRTags.None;");
+
+ if (default(T) != null && item == null) throw new NullReferenceException(nameof(item));
+ if (item.Id.IsNullOrEmpty()) throw new ArgumentNullException(nameof(item), "Update->item.Id.IsNullOrEmpty()");
+ if ((uint)index >= (uint)Count) throw new ArgumentOutOfRangeException(nameof(index));
+
+ lock (_syncRoot)
+ {
+ if (InnerList[index].Id != item.Id)
+ throw new ArgumentException($@"_list[index].Id != item.Id! Id: {item.Id}", nameof(item));
+
+ var result = SignalRClient.PostDataAsync(SignalRCrudTags.UpdateMessageTag, item).GetAwaiter().GetResult() ?? throw new NullReferenceException();
+
+ InnerList[index] = result;
+ return result;
+ }
+ }
+
+ ///
+ /// RemoveMessageTag
+ ///
+ ///
+ ///
+ public bool Remove(T item)
+ {
+ lock (_syncRoot)
+ {
+ var index = IndexOf(item);
+
+ if (index < 0) return false;
+
+ RemoveAt(index);
+ return true;
+ }
+ }
+
+ ///
+ /// RemoveMessageTag
+ ///
+ ///
+ ///
+ /// ///
+ ///
+ public void RemoveAt(int index)
+ {
+ if (SignalRCrudTags.RemoveMessageTag == SignalRTags.None) throw new ArgumentException($"_signalRCrudTags.RemoveMessageTag == SignalRTags.None;");
+
+ lock (_syncRoot)
+ {
+ var item = InnerList[index];
+ if (item.Id.IsNullOrEmpty()) throw new ArgumentNullException(nameof(item), $@"RemoveAt->item.Id.IsNullOrEmpty(); index: {index}");
+
+ var result = SignalRClient.PostDataAsync(SignalRCrudTags.RemoveMessageTag, item).GetAwaiter().GetResult() ?? throw new NullReferenceException();
+
+ InnerList.RemoveAt(index);
+ }
+ }
+
+ public void Clear()
+ {
+ lock (_syncRoot) InnerList.Clear();
+ }
+
+ public int IndexOf(T item)
+ {
+ lock (_syncRoot)
+ return InnerList.FindIndex(x => x.Id == item.Id);
+ }
+
+ public bool Contains(T item)
+ {
+ lock (_syncRoot)
+ return IndexOf(item) > -1;
+ }
+
+ public void CopyTo(T[] array) => CopyTo(array, 0);
+
+ public void CopyTo(T[] array, int arrayIndex)
+ {
+ lock (_syncRoot) InnerList.CopyTo(array, arrayIndex);
+ }
+
+ public int BinarySearch(int index, int count, T item, IComparer? comparer)
+ {
+ 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");
+
+ lock (_syncRoot)
+ return InnerList.BinarySearch(index, count, item, comparer);
+ }
+
+ 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()
+ {
+ lock (_syncRoot)
+ return InnerList.ToList().GetEnumerator();
+ }
+
+ 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();
+ 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();
+
+ void ICollection.CopyTo(Array array, int arrayIndex)
+ {
+ if ((array != null) && (array.Rank != 1))
+ {
+ throw new ArgumentException();
+ }
+
+ try
+ {
+ //TODO: _list.ToArray() - ez nem az igazi... - J.
+ Array.Copy(InnerList.ToArray(), 0, array!, arrayIndex, InnerList.Count);
+ }
+ 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
+ }
+}
diff --git a/TIAMWebApp/Shared/Utility/SignalRDataSourceAsync.cs b/TIAMWebApp/Shared/Utility/SignalRDataSourceAsync.cs
new file mode 100644
index 00000000..f46ff930
--- /dev/null
+++ b/TIAMWebApp/Shared/Utility/SignalRDataSourceAsync.cs
@@ -0,0 +1,117 @@
+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, false)
+ {
+ OnDataSourceLoaded = onDataSourceLoaded;
+
+ if (autoLoadDataSource) LoadDataSourceAsync();
+ }
+
+ public void LoadDataSourceAsync()
+ {
+ 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();
+ 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, DataChangeMode.Add).GetAwaiter().GetResult();
+ //public Task AddAsync(T item, int messageTag) => PostDataToServerAsync(item, messageTag, DataChangeMode.Add);
+
+
+ //public Task UpdateAsync(T item, int messageTag) => PostDataToServerAsync(item, messageTag, DataChangeMode.Update);
+
+ //public Task RemoveAsync(T item, int messageTag) => PostDataToServerAsync(item, messageTag, DataChangeMode.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, DataChangeMode dataChangeMode)
+ //{
+ // 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, dataChangeMode == DataChangeMode.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, dataChangeMode == DataChangeMode.Remove);
+
+ // var eventArgs = new ItemChangedEventArgs(repsonse.ResponseData, dataChangeMode);
+ // OnItemChanged.Invoke(eventArgs);
+ // });
+
+ // //transfer = await devAdminSignalClient.PostDataAsync(SignalRTags.UpdateTransferAsync, transfer);
+
+ // return Task.CompletedTask;
+ //}
+
+ public class ItemChangedEventArgs where T : IId
+ {
+ internal ItemChangedEventArgs(T item, DataChangeMode dataChangeMode)
+ {
+ Item = item;
+ DataChangeMode = dataChangeMode;
+ }
+
+ public T Item { get; }
+ public DataChangeMode DataChangeMode { get; }
+ }
+
+}
\ No newline at end of file
From b454c51c7b250c880732093005c9858a5408168e Mon Sep 17 00:00:00 2001
From: Loretta
Date: Fri, 7 Jun 2024 06:08:49 +0200
Subject: [PATCH 3/5] Improvements SignalRDataSource; Clone obejct; etc...
---
.../User/SysAdmins/ManageTransfers.razor | 2 +-
.../TransferToDriverGridComponent.razor | 2 +-
.../Shared/Components/Grids/TiamGrid.cs | 24 +-
.../ServiceProviderAPIController.cs | 40 +-
.../Shared/Services/AcSignalRClientBase.cs | 10 +-
.../Shared/Utility/SignalRDataSource.cs | 415 ++++++++++++++----
.../Shared/Utility/SignalRDataSourceAsync.cs | 26 +-
.../Shared/Utility/TrackingItemHelpers.cs | 47 ++
8 files changed, 436 insertions(+), 130 deletions(-)
create mode 100644 TIAMWebApp/Shared/Utility/TrackingItemHelpers.cs
diff --git a/TIAMSharedUI/Pages/User/SysAdmins/ManageTransfers.razor b/TIAMSharedUI/Pages/User/SysAdmins/ManageTransfers.razor
index 6401fa80..8cb19deb 100644
--- a/TIAMSharedUI/Pages/User/SysAdmins/ManageTransfers.razor
+++ b/TIAMSharedUI/Pages/User/SysAdmins/ManageTransfers.razor
@@ -396,7 +396,7 @@
{
_logger.Info("DataSourceItemChanged called");
- AppointmentModels.UpdateCollection(CreateAppointmentModel(args.DataItem), args.DataChangeMode == DataChangeMode.Remove);
+ AppointmentModels.UpdateCollection(CreateAppointmentModel(args.DataItem), args.TrackingState == TrackingState.Remove);
}
private void DataItemSaving(GridEditModelSavingEventArgs e)
diff --git a/TIAMSharedUI/Pages/User/SysAdmins/TransferToDriverGridComponent.razor b/TIAMSharedUI/Pages/User/SysAdmins/TransferToDriverGridComponent.razor
index 4984cf08..83b676ac 100644
--- a/TIAMSharedUI/Pages/User/SysAdmins/TransferToDriverGridComponent.razor
+++ b/TIAMSharedUI/Pages/User/SysAdmins/TransferToDriverGridComponent.razor
@@ -59,7 +59,7 @@
private void DataItemChanged(GridDataItemChangedEventArgs args)
{
- ParentData.TransferToDrivers.UpdateCollection(args.DataItem, args.DataChangeMode == DataChangeMode.Remove);
+ ParentData.TransferToDrivers.UpdateCollection(args.DataItem, args.TrackingState == TrackingState.Remove);
OnTransferToDriverChanged.InvokeAsync(args.DataItem);
}
diff --git a/TIAMSharedUI/Shared/Components/Grids/TiamGrid.cs b/TIAMSharedUI/Shared/Components/Grids/TiamGrid.cs
index 356e92f0..0fc18741 100644
--- a/TIAMSharedUI/Shared/Components/Grids/TiamGrid.cs
+++ b/TIAMSharedUI/Shared/Components/Grids/TiamGrid.cs
@@ -17,7 +17,7 @@ namespace TIAMSharedUI.Shared.Components.Grids
{
public class GridDataItemChangingEventArgs : GridDataItemChangedEventArgs where TDataItem : class, IId
{
- internal GridDataItemChangingEventArgs(TiamGrid grid, TDataItem dataItem, DataChangeMode dataChangeMode) : base(grid, dataItem, dataChangeMode)
+ internal GridDataItemChangingEventArgs(TiamGrid grid, TDataItem dataItem, TrackingState trackingState) : base(grid, dataItem, trackingState)
{
}
@@ -26,16 +26,16 @@ namespace TIAMSharedUI.Shared.Components.Grids
public class GridDataItemChangedEventArgs where TDataItem : class, IId
{
- internal GridDataItemChangedEventArgs(TiamGrid grid, TDataItem dataItem, DataChangeMode dataChangeMode)
+ internal GridDataItemChangedEventArgs(TiamGrid grid, TDataItem dataItem, TrackingState trackingState)
{
Grid = grid;
DataItem = dataItem;
- DataChangeMode = dataChangeMode;
+ TrackingState = trackingState;
}
public TiamGrid Grid { get; }
public TDataItem DataItem { get; }
- public DataChangeMode DataChangeMode { get; }
+ public TrackingState TrackingState { get; }
}
public class TiamGrid : DxGrid where TDataItem : class, IId
@@ -121,13 +121,13 @@ namespace TIAMSharedUI.Shared.Components.Grids
}
public Task AddDataItem(TDataItem dataItem) => AddDataItem(dataItem, AddMessageTag);
- public Task AddDataItem(TDataItem dataItem, int messageTag) => PostDataToServerAsync(dataItem, messageTag, DataChangeMode.Add);
+ public Task AddDataItem(TDataItem dataItem, int messageTag) => PostDataToServerAsync(dataItem, messageTag, TrackingState.Add);
public Task UpdateDataItem(TDataItem dataItem) => UpdateDataItem(dataItem, UpdateMessageTag);
- public Task UpdateDataItem(TDataItem dataItem, int messageTag) => PostDataToServerAsync(dataItem, messageTag, DataChangeMode.Update);
+ public Task UpdateDataItem(TDataItem dataItem, int messageTag) => PostDataToServerAsync(dataItem, messageTag, TrackingState.Update);
public Task RemoveDataItem(TDataItem dataItem) => RemoveDataItem(dataItem, RemoveMessageTag);
- public Task RemoveDataItem(TDataItem dataItem, int messageTag) => PostDataToServerAsync(dataItem, messageTag, DataChangeMode.Remove);
+ public Task RemoveDataItem(TDataItem dataItem, int messageTag) => PostDataToServerAsync(dataItem, messageTag, TrackingState.Remove);
public Task RemoveDataItem(Guid id) => RemoveDataItem(id, RemoveMessageTag);
@@ -192,9 +192,9 @@ namespace TIAMSharedUI.Shared.Components.Grids
});
}
- protected virtual async Task PostDataToServerAsync(TDataItem dataItem, int messageTag, DataChangeMode dataChangeMode)
+ protected virtual async Task PostDataToServerAsync(TDataItem dataItem, int messageTag, TrackingState trackingState)
{
- var changingEventArgs = new GridDataItemChangingEventArgs(this, dataItem, dataChangeMode);
+ var changingEventArgs = new GridDataItemChangingEventArgs(this, dataItem, trackingState);
await OnDataItemChanging.InvokeAsync(changingEventArgs);
if (changingEventArgs.IsCanceled)
@@ -209,7 +209,7 @@ namespace TIAMSharedUI.Shared.Components.Grids
if (dataItem.Id.IsNullOrEmpty()) dataItem.Id = Guid.NewGuid();
- _dataSource.UpdateCollection(dataItem, dataChangeMode == DataChangeMode.Remove); //egyből látszódik a változás a grid-ben, nem csak a callback lefutásakor! felhasználóbarátabb... - J.
+ _dataSource.UpdateCollection(dataItem, 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.
SignalRClient.PostDataAsync(messageTag, dataItem, async response =>
{
@@ -219,9 +219,9 @@ namespace TIAMSharedUI.Shared.Components.Grids
return;
}
- _dataSource.UpdateCollection(response.ResponseData, dataChangeMode == DataChangeMode.Remove);
+ _dataSource.UpdateCollection(response.ResponseData, trackingState == TrackingState.Remove);
- var changedEventArgs = new GridDataItemChangedEventArgs(this, response.ResponseData, dataChangeMode);
+ var changedEventArgs = new GridDataItemChangedEventArgs(this, response.ResponseData, trackingState);
await OnDataItemChanged.InvokeAsync(changedEventArgs);
InvokeAsync(StateHasChanged).Forget();
diff --git a/TIAMWebApp/Server/Controllers/ServiceProviderAPIController.cs b/TIAMWebApp/Server/Controllers/ServiceProviderAPIController.cs
index bc7ee8b3..f1f8419d 100644
--- a/TIAMWebApp/Server/Controllers/ServiceProviderAPIController.cs
+++ b/TIAMWebApp/Server/Controllers/ServiceProviderAPIController.cs
@@ -30,9 +30,9 @@ namespace TIAMWebApp.Server.Controllers
[NonAction]
[ApiExplorerSettings(IgnoreApi = true)]
- private async Task CompanyDataChanging(Company company, DataChangeMode dataChangeMode)
+ private async Task CompanyDataChanging(Company company, TrackingState trackingState)
{
- var logText = $"[{dataChangeMode.ToString().ToUpper()}] CompanyDataChanging called; Id: {company.Id}; OwnerId: {company.OwnerId}; Name: {company.Name}";
+ var logText = $"[{trackingState.ToString().ToUpper()}] CompanyDataChanging called; Id: {company.Id}; OwnerId: {company.OwnerId}; Name: {company.Name}";
if (company.Name.IsNullOrEmpty())
{
@@ -42,9 +42,9 @@ namespace TIAMWebApp.Server.Controllers
_logger.Info(logText);
- switch (dataChangeMode)
+ switch (trackingState)
{
- case DataChangeMode.Add:
+ case TrackingState.Add:
if (company.Id.IsNullOrEmpty()) company.Id = Guid.NewGuid();
//if (company.OwnerId.IsNullOrEmpty()) company.OwnerId = Guid.Parse("540271F6-C604-4C16-8160-D5A7CAFEDF00"); //TESZT - J.
@@ -54,13 +54,13 @@ namespace TIAMWebApp.Server.Controllers
return await adminDal.CreateServiceProviderAsync(company);
- case DataChangeMode.Update:
+ case TrackingState.Update:
return await adminDal.UpdateCompanyAsync(company);
- case DataChangeMode.Remove:
+ case TrackingState.Remove:
return await adminDal.RemoveCompanyAsync(company);
default:
- throw new ArgumentOutOfRangeException(nameof(dataChangeMode), dataChangeMode, null);
+ throw new ArgumentOutOfRangeException(nameof(trackingState), trackingState, null);
}
}
@@ -68,21 +68,21 @@ namespace TIAMWebApp.Server.Controllers
[ApiExplorerSettings(IgnoreApi = true)]
[SignalR(SignalRTags.AddCompany)]
public async Task AddCompanyAsync(Company company)
- => await CompanyDataChanging(company, DataChangeMode.Add) ? company.ToJson() : string.Empty;
+ => await CompanyDataChanging(company, TrackingState.Add) ? company.ToJson() : string.Empty;
[AllowAnonymous]
[HttpPost]
[Route(APIUrls.UpdateServiceProviderRouteName)]
[SignalR(SignalRTags.UpdateCompany)]
public async Task UpdateServiceProvider(Company company)
- => await CompanyDataChanging(company, DataChangeMode.Update) ? company.ToJson() : string.Empty;
+ => await CompanyDataChanging(company, TrackingState.Update) ? company.ToJson() : string.Empty;
[AllowAnonymous]
[HttpPost]
[Route(APIUrls.RemoveServiceProviderRouteName)]
[SignalR(SignalRTags.RemoveCompany)]
public async Task RemoveServiceProvider(Company company)
- => await CompanyDataChanging(company, DataChangeMode.Remove) ? company.ToJson() : string.Empty;
+ => await CompanyDataChanging(company, TrackingState.Remove) ? company.ToJson() : string.Empty;
//15.
[AllowAnonymous]
@@ -220,9 +220,9 @@ namespace TIAMWebApp.Server.Controllers
[NonAction]
[ApiExplorerSettings(IgnoreApi = true)]
- private async Task CarDataChanging(Car car, DataChangeMode dataChangeMode)
+ private async Task CarDataChanging(Car car, TrackingState trackingState)
{
- var logText = $"[{dataChangeMode.ToString().ToUpper()}] CarDataChanging called; Id: {car.Id}; OwnerId: {car.UserProductMappingId}; LicensePlate: {car.LicencePlate}";
+ var logText = $"[{trackingState.ToString().ToUpper()}] CarDataChanging called; Id: {car.Id}; OwnerId: {car.UserProductMappingId}; LicensePlate: {car.LicencePlate}";
if (car.UserProductMappingId.IsNullOrEmpty() || car.LicencePlate.IsNullOrWhiteSpace())
{
@@ -232,19 +232,19 @@ namespace TIAMWebApp.Server.Controllers
_logger.Info(logText);
- switch (dataChangeMode)
+ switch (trackingState)
{
- case DataChangeMode.Add:
+ case TrackingState.Add:
if (car.Id.IsNullOrEmpty()) car.Id = Guid.NewGuid();
return await adminDal.AddCarAsync(car);
- case DataChangeMode.Update:
+ case TrackingState.Update:
return await adminDal.UpdateCarAsync(car);
- case DataChangeMode.Remove:
+ case TrackingState.Remove:
return await adminDal.RemoveCarAsync(car);
default:
- throw new ArgumentOutOfRangeException(nameof(dataChangeMode), dataChangeMode, null);
+ throw new ArgumentOutOfRangeException(nameof(trackingState), trackingState, null);
}
}
@@ -255,7 +255,7 @@ namespace TIAMWebApp.Server.Controllers
[EndpointSummary("Create car")]
[SignalR(SignalRTags.CreateCar)]
public async Task CreateCar(Car car)
- => await CarDataChanging(car, DataChangeMode.Add) ? Ok(car) : BadRequest("Invalid request");
+ => await CarDataChanging(car, TrackingState.Add) ? Ok(car) : BadRequest("Invalid request");
[AllowAnonymous]
[HttpPost]
@@ -264,7 +264,7 @@ namespace TIAMWebApp.Server.Controllers
[EndpointSummary("Update car")]
[SignalR(SignalRTags.UpdateCar)]
public async Task UpdateCar(Car car)
- => await CarDataChanging(car, DataChangeMode.Update) ? Ok(car) : BadRequest("Invalid request");
+ => await CarDataChanging(car, TrackingState.Update) ? Ok(car) : BadRequest("Invalid request");
[AllowAnonymous]
[HttpPost]
@@ -273,7 +273,7 @@ namespace TIAMWebApp.Server.Controllers
[EndpointSummary("Delete car")]
[SignalR(SignalRTags.DeleteCar)]
public async Task DeleteCar(Car car)
- => await CarDataChanging(car, DataChangeMode.Remove) ? Ok(car) : BadRequest("Invalid request");
+ => await CarDataChanging(car, TrackingState.Remove) ? Ok(car) : BadRequest("Invalid request");
[HttpPost]
[Route(APIUrls.AddProductRouteName)]
diff --git a/TIAMWebApp/Shared/Services/AcSignalRClientBase.cs b/TIAMWebApp/Shared/Services/AcSignalRClientBase.cs
index b9200d75..d531c604 100644
--- a/TIAMWebApp/Shared/Services/AcSignalRClientBase.cs
+++ b/TIAMWebApp/Shared/Services/AcSignalRClientBase.cs
@@ -2,6 +2,7 @@
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;
@@ -75,9 +76,6 @@ namespace TIAMWebApp.Shared.Application.Services
public virtual Task SendMessageToServerAsync(int messageTag)
=> SendMessageToServerAsync(messageTag, null, AcDomain.NextUniqueInt32);
- public virtual Task SendMessageToServerAsync(int messageTag, int requestId)
- => SendMessageToServerAsync(messageTag, null, requestId);
-
public virtual async Task SendMessageToServerAsync(int messageTag, ISignalRMessage? message, int? requestId)
{
Logger.DebugConditional($"Client SendMessageToServerAsync; {nameof(messageTag)}: {messageTag}; {nameof(requestId)}: {requestId};");
@@ -89,8 +87,8 @@ namespace TIAMWebApp.Shared.Application.Services
}
#region CRUD
- public virtual Task GetByIdAsync(int messageTag, Guid id) where TResponse : class
- => SendMessageToServerAsync(messageTag, new SignalPostJsonDataMessage(new IdMessage(id)), AcDomain.NextUniqueInt32);
+ 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);
@@ -117,7 +115,7 @@ namespace TIAMWebApp.Shared.Application.Services
public virtual Task SendMessageToServerAsync(int messageTag, ISignalRMessage? message) where TResponse : class
=> SendMessageToServerAsync(messageTag, message, AcDomain.NextUniqueInt32);
- public virtual async Task SendMessageToServerAsync(int messageTag, ISignalRMessage? message, int requestId) where TResponse : class
+ protected virtual async Task SendMessageToServerAsync(int messageTag, ISignalRMessage? message, int requestId) where TResponse : class
{
Logger.DebugConditional($"Client SendMessageToServerAsync; {nameof(messageTag)}: {messageTag}; {nameof(requestId)}: {requestId};");
diff --git a/TIAMWebApp/Shared/Utility/SignalRDataSource.cs b/TIAMWebApp/Shared/Utility/SignalRDataSource.cs
index 37780551..19b2c826 100644
--- a/TIAMWebApp/Shared/Utility/SignalRDataSource.cs
+++ b/TIAMWebApp/Shared/Utility/SignalRDataSource.cs
@@ -1,6 +1,10 @@
using System.Collections;
+using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Runtime.Serialization;
+using System.Runtime.Serialization.Formatters.Binary;
using AyCode.Core.Enums;
using AyCode.Core.Extensions;
using AyCode.Core.Interfaces;
@@ -10,22 +14,84 @@ using TIAMWebApp.Shared.Application.Services;
namespace TIAMWebApp.Shared.Application.Utility
{
- public class ChangeTracking(DataChangeMode dataChangeMode, T newItem, T originalItem = default(T))where T: class, IId
+ public class TrackingItem(TrackingState trackingState, T currentValue, T? originalValue = null) where T : class, IId
{
- public DataChangeMode DataChangeMode { get; init; } = dataChangeMode;
- public T NewItem { get; init; } = newItem;
- public T OriginalItem { get; init; } = originalItem;
+ public TrackingState TrackingState { get; internal set; } = trackingState;
+ public T CurrentValue { get; internal set; } = currentValue;
+ public T? OriginalValue { get; init; } = originalValue; //originalValue == null ? null : TrackingItemHelpers.Clone(originalValue);
+
+ internal TrackingItem UpdateItem(TrackingState trackingState, T newValue)
+ {
+ CurrentValue = newValue;
+
+ if (TrackingState != TrackingState.Add)
+ TrackingState = trackingState;
+
+ return this;
+ }
}
+
+ public class ChangeTracking 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.ReflectionClone(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);
+ }
+
+
+
[Serializable]
[DebuggerDisplay("Count = {Count}")]
- public class SignalRDataSource : IList, IList, IReadOnlyList where T: class, IId
+ public class SignalRDataSource : IList, IList, IReadOnlyList where T : class, IId
{
- protected readonly List InnerList = [];
private readonly object _syncRoot = new();
- protected Guid? ContextId;
- protected AcSignalRClientBase SignalRClient;
+ protected readonly List InnerList = []; //TODO: Dictionary??? - J.
+ protected readonly ChangeTracking TrackingItems = new();
+
+ protected readonly Guid? ContextId;
+ protected readonly AcSignalRClientBase SignalRClient;
protected readonly SignalRCrudTags SignalRCrudTags;
public SignalRDataSource(AcSignalRClientBase signalRClient, SignalRCrudTags signalRCrudTags, Guid? contextId = null, bool autoLoadDataSource = true)
@@ -35,7 +101,7 @@ namespace TIAMWebApp.Shared.Application.Utility
SignalRCrudTags = signalRCrudTags;
SignalRClient = signalRClient;
- if (autoLoadDataSource) LoadDataSource();
+ if (autoLoadDataSource) LoadDataSource(false);
}
public bool IsSynchronized => true;
@@ -47,19 +113,38 @@ namespace TIAMWebApp.Shared.Application.Utility
///
///
///
- public void LoadDataSource()
+ public void LoadDataSource(bool clearChangeTracking = true)
{
- if (SignalRCrudTags.GetAllMessageTag == SignalRTags.None) throw new ArgumentException($"_signalRCrudTags.GetAllMessageTag == SignalRTags.None;");
+ if (SignalRCrudTags.GetAllMessageTag == SignalRTags.None) throw new ArgumentException($"SignalRCrudTags.GetAllMessageTag == SignalRTags.None");
lock (_syncRoot)
{
var resultList = SignalRClient.GetAllAsync>(SignalRCrudTags.GetAllMessageTag, ContextId).GetAwaiter().GetResult() ?? throw new NullReferenceException();
- Clear();
+ Clear(clearChangeTracking);
InnerList.AddRange(resultList);
}
}
+ public T? LoadItem(Guid id)
+ {
+ if (SignalRCrudTags.GetItemMessageTag == SignalRTags.None) throw new ArgumentException($"SignalRCrudTags.GetItemMessageTag == SignalRTags.None");
+
+ T? resultitem = null;
+
+ lock (_syncRoot)
+ {
+ resultitem = SignalRClient.GetByIdAsync(SignalRCrudTags.GetItemMessageTag, id).GetAwaiter().GetResult();
+ if (resultitem == null) return null;
+
+ if (TryGetIndex(id, out var index)) InnerList[index] = resultitem;
+ else InnerList.Add(resultitem);
+ }
+
+ return resultitem;
+ }
+
+
///
/// set: UpdateMessageTag
///
@@ -86,42 +171,38 @@ namespace TIAMWebApp.Shared.Application.Utility
}
}
- public int Count
- {
- get
- {
- lock (_syncRoot) return InnerList.Count;
- }
- }
-
///
/// AddMessageTag
///
- ///
+ ///
///
- public void Add(T item)
+ public void Add(T newValue)
{
+ if (newValue.Id.IsNullOrEmpty()) throw new ArgumentNullException(nameof(newValue), @"Add->newValue.Id.IsNullOrEmpty()");
+
lock (_syncRoot)
{
- if (Contains(item))
- throw new ArgumentException($@"It already contains this Id! Id: {item.Id}", nameof(item));
+ if (Contains(newValue))
+ throw new ArgumentException($@"It already contains this Id! Id: {newValue.Id}", nameof(newValue));
- UnsafeAdd(item);
+ UnsafeAdd(newValue);
}
}
///
/// AddMessageTag or UpdateMessageTag
///
- ///
+ ///
///
- public T AddOrUpdate(T item)
+ public T AddOrUpdate(T newValue)
{
+ if (newValue.Id.IsNullOrEmpty()) throw new ArgumentNullException(nameof(newValue), @"AddOrUpdate->newValue.Id.IsNullOrEmpty()");
+
lock (_syncRoot)
{
- var index = IndexOf(item);
+ var index = IndexOf(newValue);
- return index > -1 ? Update(index, item) : UnsafeAdd(item);
+ return index > -1 ? Update(index, newValue) : UnsafeAdd(newValue);
}
}
@@ -133,69 +214,67 @@ namespace TIAMWebApp.Shared.Application.Utility
// }
//}
- private T UnsafeAdd(T item)
+ protected T UnsafeAdd(T newValue)
{
- if (SignalRCrudTags.AddMessageTag == SignalRTags.None) throw new ArgumentException($"_signalRCrudTags.AddMessageTag == SignalRTags.None;");
+ TrackingItems.AddTrackingItem(TrackingState.Add, newValue);
+ InnerList.Add(newValue);
- var result = SignalRClient.PostDataAsync(SignalRCrudTags.AddMessageTag, item).GetAwaiter().GetResult() ?? throw new NullReferenceException();
- InnerList.Add(result);
-
- return result;
+ return newValue;
}
///
/// AddMessageTag
///
///
- ///
+ ///
///
///
- public void Insert(int index, T item)
+ public void Insert(int index, T newValue)
{
- if (SignalRCrudTags.AddMessageTag == SignalRTags.None) throw new ArgumentException($"_signalRCrudTags.AddMessageTag == SignalRTags.None;");
+ if (newValue.Id.IsNullOrEmpty()) throw new ArgumentNullException(nameof(newValue), @"Insert->newValue.Id.IsNullOrEmpty()");
lock (_syncRoot)
{
- if (Contains(item))
- throw new ArgumentException($@"It already contains this Id! Id: {item.Id}", nameof(item));
+ if (Contains(newValue))
+ throw new ArgumentException($@"It already contains this Id! Id: {newValue.Id}", nameof(newValue));
- var result = SignalRClient.PostDataAsync(SignalRCrudTags.AddMessageTag, item).GetAwaiter().GetResult() ?? throw new NullReferenceException();
- InnerList.Insert(index, result);
+ TrackingItems.AddTrackingItem(TrackingState.Add, newValue);
+ InnerList.Insert(index, newValue);
}
}
///
/// UpdateMessageTag
///
- ///
- public T Update(T item) => Update(IndexOf(item), item);
+ ///
+ public T Update(T newItem) => Update(IndexOf(newItem), newItem);
///
/// UpdateMessageTag
///
///
- ///
+ ///
/// ///
/// ///
///
///
- public T Update(int index, T item)
+ public T Update(int index, T newValue)
{
- if (SignalRCrudTags.UpdateMessageTag == SignalRTags.None) throw new ArgumentException($"_signalRCrudTags.UpdateMessageTag == SignalRTags.None;");
-
- if (default(T) != null && item == null) throw new NullReferenceException(nameof(item));
- if (item.Id.IsNullOrEmpty()) throw new ArgumentNullException(nameof(item), "Update->item.Id.IsNullOrEmpty()");
+ if (default(T) != null && newValue == null) throw new NullReferenceException(nameof(newValue));
+ if (newValue.Id.IsNullOrEmpty()) throw new ArgumentNullException(nameof(newValue), @"Update->newValue.Id.IsNullOrEmpty()");
if ((uint)index >= (uint)Count) throw new ArgumentOutOfRangeException(nameof(index));
lock (_syncRoot)
{
- if (InnerList[index].Id != item.Id)
- throw new ArgumentException($@"_list[index].Id != item.Id! Id: {item.Id}", nameof(item));
+ var currentItem = InnerList[index];
- var result = SignalRClient.PostDataAsync(SignalRCrudTags.UpdateMessageTag, item).GetAwaiter().GetResult() ?? throw new NullReferenceException();
-
- InnerList[index] = result;
- return result;
+ if (currentItem.Id != newValue.Id)
+ throw new ArgumentException($@"currentItem.Id != item.Id! Id: {newValue.Id}", nameof(newValue));
+
+ TrackingItems.AddTrackingItem(TrackingState.Update, newValue, currentItem);
+ InnerList[index] = newValue;
+
+ return newValue;
}
}
@@ -217,6 +296,20 @@ namespace TIAMWebApp.Shared.Application.Utility
}
}
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public bool TryRemove(Guid id, out T? item)
+ {
+ lock (_syncRoot)
+ {
+ return TryGetValue(id, out item) && Remove(item);
+ }
+ }
+
///
/// RemoveMessageTag
///
@@ -226,34 +319,197 @@ namespace TIAMWebApp.Shared.Application.Utility
///
public void RemoveAt(int index)
{
- if (SignalRCrudTags.RemoveMessageTag == SignalRTags.None) throw new ArgumentException($"_signalRCrudTags.RemoveMessageTag == SignalRTags.None;");
-
lock (_syncRoot)
{
- var item = InnerList[index];
- if (item.Id.IsNullOrEmpty()) throw new ArgumentNullException(nameof(item), $@"RemoveAt->item.Id.IsNullOrEmpty(); index: {index}");
-
- var result = SignalRClient.PostDataAsync(SignalRCrudTags.RemoveMessageTag, item).GetAwaiter().GetResult() ?? throw new NullReferenceException();
+ 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);
}
}
- public void Clear()
- {
- lock (_syncRoot) InnerList.Clear();
- }
-
- public int IndexOf(T item)
+ ///
+ ///
+ ///
+ ///
+ public List> GetTrackingItems()
{
lock (_syncRoot)
- return InnerList.FindIndex(x => x.Id == item.Id);
+ return TrackingItems.ToList();
}
- public bool Contains(T item)
+ public void SetTrackingStateToUpdate(T item)
{
- lock (_syncRoot)
- return IndexOf(item) > -1;
+ if (TrackingItems.TryGetTrackingItem(item.Id, out var trackingItem))
+ {
+ if (trackingItem.TrackingState != TrackingState.Add)
+ trackingItem.TrackingState = TrackingState.Update;
+
+ return;
+ }
+
+ TrackingItems.AddTrackingItem(TrackingState.Update, item, item);
+ }
+
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public bool TryGetTrackingItem(Guid id, [NotNullWhen(true)] out TrackingItem? trackingItem)
+ {
+ lock (_syncRoot)
+ return TrackingItems.TryGetTrackingItem(id, out trackingItem);
+ }
+
+ ///
+ ///
+ ///
+ /// Unsaved items
+ public bool SaveChanges(out List> unsavedItems)
+ {
+ lock (_syncRoot)
+ {
+ foreach (var trackingItem in TrackingItems.ToList())
+ {
+ try
+ {
+ SaveTrackingItemUnsafe(trackingItem);
+ }
+ catch
+ {
+ // ignored
+ }
+ }
+
+ unsavedItems = TrackingItems.ToList();
+ return unsavedItems.Count == 0;
+ }
+ }
+
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public bool TrySaveItem(Guid id, [NotNullWhen(true)] out T? resultItem)
+ {
+ resultItem = null;
+
+ if (TryGetTrackingItem(id, out var trackingItem))
+ resultItem = SaveTrackingItemUnsafe(trackingItem);
+
+ return resultItem != null;
+ }
+
+ public bool TrySaveItem(Guid id, TrackingState trackingState, [NotNullWhen(true)] out T? resultItem)
+ => TryGetValue(id, out resultItem) && TrySaveItem(resultItem, trackingState, out resultItem);
+
+ public bool TrySaveItem(T item, TrackingState trackingState, [NotNullWhen(true)] out T? resultItem)
+ {
+ resultItem = SaveItemUnsafe(item, trackingState);
+ return resultItem != null;
+ }
+
+ protected T? SaveTrackingItemUnsafe(TrackingItem trackingItem)
+ => SaveItemUnsafe(trackingItem.CurrentValue, trackingItem.TrackingState);
+
+ protected T? SaveItemUnsafe(T item, TrackingState trackingState)
+ {
+ var messageTag = SignalRCrudTags.GetMessageTagByTrackingState(trackingState);
+ if (messageTag == SignalRTags.None) return null; //throw new ArgumentException($"messageTag == SignalRTags.None");
+
+ var result = SignalRClient.PostDataAsync(messageTag, item).GetAwaiter().GetResult();
+ if (result == null) return null; //throw new NullReferenceException($"result == null");
+
+ if (TryGetTrackingItem(item.Id, out var trackingItem))
+ TrackingItems.Remove(trackingItem);
+
+ if (TryGetIndex(result.Id, out var index))
+ InnerList[index] = result;
+
+ return result;
+ }
+
+ 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)
+ {
+ lock (_syncRoot)
+ {
+ if (TryGetTrackingItem(id, out var trackingItem))
+ {
+ originalValue = trackingItem.OriginalValue;
+
+ RollbackItemUnsafe(trackingItem);
+ return true;
+ }
+
+ originalValue = null;
+ return false;
+ }
+ }
+
+ public void Rollback()
+ {
+ lock (_syncRoot)
+ {
+ foreach (var trackingItem in TrackingItems.ToList())
+ RollbackItemUnsafe(trackingItem);
+ }
+ }
+
+ public int Count
+ {
+ get
+ {
+ lock (_syncRoot) return InnerList.Count;
+ }
+ }
+
+ public void Clear() => Clear(true);
+
+ public void Clear(bool clearChangeTracking)
+ {
+ lock (_syncRoot)
+ {
+ if (clearChangeTracking) TrackingItems.Clear();
+ InnerList.Clear();
+ }
+ }
+
+ public int IndexOf(Guid id)
+ {
+ lock (_syncRoot)
+ return InnerList.FindIndex(x => x.Id == id);
+ }
+
+ 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)
+ {
+ lock (_syncRoot)
+ {
+ item = InnerList.FirstOrDefault(x => x.Id == id);
+ return item != null;
+ }
}
public void CopyTo(T[] array) => CopyTo(array, 0);
@@ -290,6 +546,7 @@ namespace TIAMWebApp.Shared.Application.Utility
#region IList, ICollection
+
bool IList.IsReadOnly => false;
object? IList.this[int index]
@@ -326,11 +583,11 @@ namespace TIAMWebApp.Shared.Application.Utility
return Count - 1;
}
- void IList.Clear() => Clear();
+ 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));
@@ -350,7 +607,7 @@ namespace TIAMWebApp.Shared.Application.Utility
if (IsCompatibleObject(item)) Remove((T)item!);
}
- void ICollection.Clear() => Clear();
+ void ICollection.Clear() => Clear(true);
void ICollection.CopyTo(Array array, int arrayIndex)
{
@@ -361,8 +618,11 @@ namespace TIAMWebApp.Shared.Application.Utility
try
{
- //TODO: _list.ToArray() - ez nem az igazi... - J.
- Array.Copy(InnerList.ToArray(), 0, array!, arrayIndex, InnerList.Count);
+ lock (_syncRoot)
+ {
+ //TODO: _list.ToArray() - ez nem az igazi... - J.
+ Array.Copy(InnerList.ToArray(), 0, array!, arrayIndex, InnerList.Count);
+ }
}
catch (ArrayTypeMismatchException)
{
@@ -375,6 +635,7 @@ namespace TIAMWebApp.Shared.Application.Utility
bool ICollection.IsReadOnly => false;
void IList.RemoveAt(int index) => RemoveAt(index);
int IReadOnlyCollection.Count => Count;
+
#endregion IList, ICollection
}
}
diff --git a/TIAMWebApp/Shared/Utility/SignalRDataSourceAsync.cs b/TIAMWebApp/Shared/Utility/SignalRDataSourceAsync.cs
index f46ff930..e6361fa2 100644
--- a/TIAMWebApp/Shared/Utility/SignalRDataSourceAsync.cs
+++ b/TIAMWebApp/Shared/Utility/SignalRDataSourceAsync.cs
@@ -23,7 +23,7 @@ public class SignalRDataSourceAsync : SignalRDataSource where T : class, I
if (autoLoadDataSource) LoadDataSourceAsync();
}
- public void LoadDataSourceAsync()
+ public void LoadDataSourceAsync(bool clearChangeTracking = true)
{
if (SignalRCrudTags.GetAllMessageTag == SignalRTags.None) throw new ArgumentException($"_signalRCrudTags.GetAllMessageTag == SignalRTags.None;");
@@ -39,7 +39,7 @@ public class SignalRDataSourceAsync : SignalRDataSource where T : class, I
if (response.Status == SignalResponseStatus.Error) throw new Exception($"LoadDataSourceAsync; response.Status == SignalResponseStatus.Error");
if (response.ResponseData == null) throw new NullReferenceException($"response.ResponseData == null");
- Clear();
+ Clear(clearChangeTracking);
InnerList.AddRange(response.ResponseData);
}
finally
@@ -58,13 +58,13 @@ public class SignalRDataSourceAsync : SignalRDataSource where T : class, I
}
- //public T Add(T item, int messageTag) => PostDataToServerAsync(item, messageTag, DataChangeMode.Add).GetAwaiter().GetResult();
- //public Task AddAsync(T item, int messageTag) => PostDataToServerAsync(item, messageTag, DataChangeMode.Add);
+ //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, DataChangeMode.Update);
+ //public Task UpdateAsync(T item, int messageTag) => PostDataToServerAsync(item, messageTag, TrackingState.Update);
- //public Task RemoveAsync(T item, int messageTag) => PostDataToServerAsync(item, messageTag, DataChangeMode.Remove);
+ //public Task RemoveAsync(T item, int messageTag) => PostDataToServerAsync(item, messageTag, TrackingState.Remove);
//public Task RemoveAsync(Guid id, int messageTag)
//{
@@ -73,7 +73,7 @@ public class SignalRDataSourceAsync : SignalRDataSource where T : class, I
// return item == null ? Task.CompletedTask : RemoveAsync(item, messageTag);
//}
- //protected virtual Task PostDataToServerAsync(T item, int messageTag, DataChangeMode dataChangeMode)
+ //protected virtual Task PostDataToServerAsync(T item, int messageTag, TrackingState trackingState)
//{
// if (messageTag == 0) return Task.CompletedTask;
@@ -81,7 +81,7 @@ public class SignalRDataSourceAsync : SignalRDataSource where T : class, I
// if (item.Id.IsNullOrEmpty()) item.Id = Guid.NewGuid();
- // _list.UpdateCollection(item, dataChangeMode == DataChangeMode.Remove); //egyből látszódik a változás a grid-ben, nem csak a callback lefutásakor! felhasználóbarátabb... - J.
+ // _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 =>
// {
@@ -91,9 +91,9 @@ public class SignalRDataSourceAsync : SignalRDataSource where T : class, I
// return;
// }
- // _list.UpdateCollection(repsonse.ResponseData, dataChangeMode == DataChangeMode.Remove);
+ // _list.UpdateCollection(repsonse.ResponseData, trackingState == TrackingState.Remove);
- // var eventArgs = new ItemChangedEventArgs(repsonse.ResponseData, dataChangeMode);
+ // var eventArgs = new ItemChangedEventArgs(repsonse.ResponseData, trackingState);
// OnItemChanged.Invoke(eventArgs);
// });
@@ -104,14 +104,14 @@ public class SignalRDataSourceAsync : SignalRDataSource where T : class, I
public class ItemChangedEventArgs where T : IId
{
- internal ItemChangedEventArgs(T item, DataChangeMode dataChangeMode)
+ internal ItemChangedEventArgs(T item, TrackingState trackingState)
{
Item = item;
- DataChangeMode = dataChangeMode;
+ TrackingState = trackingState;
}
public T Item { get; }
- public DataChangeMode DataChangeMode { get; }
+ public TrackingState TrackingState { get; }
}
}
\ No newline at end of file
diff --git a/TIAMWebApp/Shared/Utility/TrackingItemHelpers.cs b/TIAMWebApp/Shared/Utility/TrackingItemHelpers.cs
new file mode 100644
index 00000000..34b5eadc
--- /dev/null
+++ b/TIAMWebApp/Shared/Utility/TrackingItemHelpers.cs
@@ -0,0 +1,47 @@
+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
From 96ccf6d86f5748c6e11efcf0767ca3c39e19033b Mon Sep 17 00:00:00 2001
From: Loretta
Date: Sun, 9 Jun 2024 11:13:55 +0200
Subject: [PATCH 4/5] SignalRDataSource, TiamGrid imrpovements, fixes...
---
.../Pages/User/MyServiceProviders.razor | 11 +-
.../AddressDetailGridComponent.razor | 6 +-
.../User/SysAdmins/ManageTransfers.razor | 23 +-
.../TransferToDriverGridComponent.razor | 6 +-
.../Shared/Components/Grids/TiamGrid.cs | 163 +++++---
.../Shared/Utility/SignalRDataSource.cs | 388 +++++++++++++++---
.../Shared/Utility/SignalRDataSourceAsync.cs | 65 ++-
7 files changed, 483 insertions(+), 179 deletions(-)
diff --git a/TIAMSharedUI/Pages/User/MyServiceProviders.razor b/TIAMSharedUI/Pages/User/MyServiceProviders.razor
index 87e89e70..d3ecd46e 100644
--- a/TIAMSharedUI/Pages/User/MyServiceProviders.razor
+++ b/TIAMSharedUI/Pages/User/MyServiceProviders.razor
@@ -82,7 +82,8 @@
-
+
+
@{
@@ -147,19 +148,13 @@
}
- protected override async Task OnAfterRenderAsync(bool firstRender)
- {
- if (firstRender)
- await _gridCompany.StartEditRowAsync(0);
- }
-
void Grid_CustomizeEditModel(GridCustomizeEditModelEventArgs e)
{
if (e.IsNew)
{
var newEmployee = (Company)e.EditModel;
newEmployee.Name = "John";
- newEmployee.OwnerId = Guid.NewGuid();
+ newEmployee.AffiliateId = Guid.NewGuid();
}
}
diff --git a/TIAMSharedUI/Pages/User/SysAdmins/AddressDetailGridComponent.razor b/TIAMSharedUI/Pages/User/SysAdmins/AddressDetailGridComponent.razor
index 68cfa3c5..3a092984 100644
--- a/TIAMSharedUI/Pages/User/SysAdmins/AddressDetailGridComponent.razor
+++ b/TIAMSharedUI/Pages/User/SysAdmins/AddressDetailGridComponent.razor
@@ -26,9 +26,9 @@
DataSource="DataSource"
Logger="_logger"
SignalRClient="AdminSignalRClient"
- OnEditModelSaving="DataItemSaving"
- OnDataItemDeleting="DataItemDeleting"
- OnDataItemChanged="DataItemChanged"
+ OnGridEditModelSaving="DataItemSaving"
+ OnGridItemDeleting="DataItemDeleting"
+ OnGridItemChanged="DataItemChanged"
PageSize="5"
AutoExpandAllGroupRows="true"
KeyboardNavigationEnabled="KeyboardNavigationEnabled"
diff --git a/TIAMSharedUI/Pages/User/SysAdmins/ManageTransfers.razor b/TIAMSharedUI/Pages/User/SysAdmins/ManageTransfers.razor
index 8cb19deb..2a5d97ec 100644
--- a/TIAMSharedUI/Pages/User/SysAdmins/ManageTransfers.razor
+++ b/TIAMSharedUI/Pages/User/SysAdmins/ManageTransfers.razor
@@ -17,6 +17,8 @@
@using AyCode.Core.Extensions
@using AyCode.Core.Consts
@using AyCode.Core
+@using AyCode.Core.Helpers
+@using TIAM.Entities.Emails
@layout AdminLayout
@inject IEnumerable LogWriters
@inject IStringLocalizer localizer
@@ -89,10 +91,10 @@
Logger="_logger"
SignalRClient="AdminSignalRClient"
OnDataSourceChanged="DataSourceChanged"
- OnDataItemChanging="DataSourceItemChanging"
- OnDataItemChanged="DataSourceItemChanged"
- OnDataItemDeleting="DataItemDeleting"
- OnEditModelSaving="DataItemSaving"
+ OnGridItemChanging="DataSourceItemChanging"
+ OnGridItemChanged="DataSourceItemChanged"
+ OnGridItemDeleting="DataItemDeleting"
+ OnGridEditModelSaving="DataItemSaving"
CustomizeElement="Grid_CustomizeElement"
CustomizeEditModel="Grid_CustomizeEditModel"
@@ -163,7 +165,18 @@
-
+
+
+ @System.Text.RegularExpressions.Regex.Replace((displayTextContext.Value as string)!, "<(.|\n)*?>", string.Empty)
+
+
+
+ @{
+ var value = ((EmailMessage)editTextContext.EditModel).Text;
+
+ }
+
+
diff --git a/TIAMSharedUI/Pages/User/SysAdmins/TransferToDriverGridComponent.razor b/TIAMSharedUI/Pages/User/SysAdmins/TransferToDriverGridComponent.razor
index 83b676ac..9744e98a 100644
--- a/TIAMSharedUI/Pages/User/SysAdmins/TransferToDriverGridComponent.razor
+++ b/TIAMSharedUI/Pages/User/SysAdmins/TransferToDriverGridComponent.razor
@@ -21,9 +21,9 @@
DataSource="ParentData.TransferToDrivers"
Logger="_logger"
SignalRClient="AdminSignalRClient"
- OnEditModelSaving="DataItemSaving"
- OnDataItemDeleting="DataItemDeleting"
- OnDataItemChanged="DataItemChanged"
+ OnGridEditModelSaving="DataItemSaving"
+ OnGridItemDeleting="DataItemDeleting"
+ OnGridItemChanged="DataItemChanged"
PageSize="5"
AutoExpandAllGroupRows="true"
KeyboardNavigationEnabled="KeyboardNavigationEnabled"
diff --git a/TIAMSharedUI/Shared/Components/Grids/TiamGrid.cs b/TIAMSharedUI/Shared/Components/Grids/TiamGrid.cs
index 0fc18741..545fddc3 100644
--- a/TIAMSharedUI/Shared/Components/Grids/TiamGrid.cs
+++ b/TIAMSharedUI/Shared/Components/Grids/TiamGrid.cs
@@ -1,4 +1,5 @@
using System.ComponentModel;
+using System.Data.Common;
using AyCode.Core;
using AyCode.Core.Enums;
using AyCode.Core.Extensions;
@@ -8,8 +9,10 @@ using AyCode.Interfaces.Entities;
using AyCode.Services.SignalRs;
using AyCode.Utils.Extensions;
using DevExpress.Blazor;
+using DevExpress.Blazor.Internal;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Web;
+using TIAM.Services;
using TIAMWebApp.Shared.Application.Services;
using TIAMWebApp.Shared.Application.Utility;
@@ -41,7 +44,8 @@ namespace TIAMSharedUI.Shared.Components.Grids
public class TiamGrid : DxGrid where TDataItem : class, IId
{
protected bool IsFirstInitializeParameters;
- private IList _dataSource = null!;
+ private SignalRDataSource _dataSource = null!;
+ private IList _dataSourceParam = [];
private string _gridLogName;
public TiamGrid() : base()
@@ -60,14 +64,17 @@ namespace TIAMSharedUI.Shared.Components.Grids
[Parameter] public int RemoveMessageTag { get; set; }
protected new EventCallback DataItemDeleting { get; set; }
- [Parameter] public EventCallback OnDataItemDeleting { get; set; }
+ [Parameter] public EventCallback OnGridItemDeleting { get; set; }
protected new EventCallback EditModelSaving { get; set; }
- [Parameter] public EventCallback OnEditModelSaving { get; set; }
+ [Parameter] public EventCallback OnGridEditModelSaving { get; set; }
[Parameter] public EventCallback> OnDataSourceChanged { get; set; }
- [Parameter] public EventCallback> OnDataItemChanging { get; set; }
- [Parameter] public EventCallback> OnDataItemChanged { get; set; }
+ [Parameter] public EventCallback> OnGridItemChanging { get; set; }
+ ///
+ /// After server response!
+ ///
+ [Parameter] public EventCallback> OnGridItemChanged { get; set; }
[Parameter]
[DefaultValue(null)]
@@ -86,26 +93,65 @@ namespace TIAMSharedUI.Shared.Components.Grids
}
set
{
- if (value == null) throw new ArgumentNullException(nameof(value));
+ if (value == null) return;
+ _dataSourceParam = value;
- var equals = Equals(_dataSource, value);
+ //bool equals;
- _dataSource = value;
- Data = _dataSource;
+ //if ((equals = Equals(_dataSource, value)) == false)
+ //{
+ // if (value is SignalRDataSource dataSource)
+ // _dataSource = dataSource;
+ // else
+ // {
+ // var crudTags = new SignalRCrudTags(GetAllMessageTag, SignalRTags.None, AddMessageTag, UpdateMessageTag, RemoveMessageTag);
+ // _dataSource = new SignalRDataSource(value, SignalRClient, crudTags, ContextId);
+ // }
+ //}
- if (!equals) OnDataSourceChanged.InvokeAsync(_dataSource);
+ //Data = _dataSource;
+ //if (!equals) OnDataSourceChanged.InvokeAsync(_dataSource);
}
}
- protected override void OnInitialized()
+ protected override async Task OnInitializedAsync()
{
if (Logger == null)
throw new NullReferenceException($"[{GetType().Name}] Logger == null");
if (SignalRClient == null)
+ {
Logger.Error($"[{GetType().Name}] SignalRClient == null");
+ throw new NullReferenceException($"[{GetType().Name}] SignalRClient == null");
+ }
- base.OnInitialized();
+ var crudTags = new SignalRCrudTags(GetAllMessageTag, SignalRTags.None, AddMessageTag, UpdateMessageTag, RemoveMessageTag);
+ _dataSource = new SignalRDataSource(SignalRClient, crudTags, ContextId);
+
+ Data = _dataSource;
+
+ _dataSource.OnDataSourceLoaded += OnDataSourceLoaded;
+ _dataSource.OnDataSourceItemChanged += OnDataSourceItemChanged;
+
+ await base.OnInitializedAsync();
+ }
+
+ private Task OnDataSourceItemChanged(ItemChangedEventArgs args)
+ {
+ if (args.TrackingState is TrackingState.GetAll or TrackingState.None) return Task.CompletedTask;
+
+ Logger.Info($"{_gridLogName} OnItemLoaded; trackingState: {args.TrackingState}");
+
+ var changedEventArgs = new GridDataItemChangedEventArgs(this, args.Item, args.TrackingState);
+ return OnGridItemChanged.InvokeAsync(changedEventArgs);
+ }
+
+ private Task OnDataSourceLoaded()
+ {
+ Logger.Info($"{_gridLogName} OnDataSourceLoaded");
+
+ Reload();
+ return OnDataSourceChanged.InvokeAsync(_dataSource);
}
protected override async Task OnAfterRenderAsync(bool firstRender)
@@ -114,9 +160,8 @@ namespace TIAMSharedUI.Shared.Components.Grids
if (firstRender)
{
- if (_dataSource == null || _dataSource.Count == 0) RefreshDataSourceAsync().Forget();
-
- //AutoFitColumnWidths();
+ if (_dataSourceParam.Count > 0) await _dataSource.LoadDataSource(_dataSourceParam);
+ else _dataSource.LoadDataSourceAsync(true).Forget();
}
}
@@ -131,21 +176,29 @@ namespace TIAMSharedUI.Shared.Components.Grids
public Task RemoveDataItem(Guid id) => RemoveDataItem(id, RemoveMessageTag);
- public Task RemoveDataItem(Guid id, int messageTag)
+ public async Task RemoveDataItem(Guid id, int messageTag)
{
var dataItem = _dataSource.FirstOrDefault(x => x.Id == id);
+ if (dataItem != null)
+ {
+ _dataSource.Remove(dataItem);
+ await _dataSource.SaveChanges();
+ //await RemoveDataItem(dataItem);
+ }
- return dataItem == null ? Task.CompletedTask : RemoveDataItem(dataItem);
+ await InvokeAsync(StateHasChanged);
}
private async Task OnItemSaving(GridEditModelSavingEventArgs e)
{
var dataItem = (e.EditModel as TDataItem)!;
+ if (e.IsNew && dataItem.Id.IsNullOrEmpty()) dataItem.Id = Guid.NewGuid();
+
var logText = e.IsNew ? "add" : "update";
Logger.Info($"{_gridLogName} OnItemSaving {logText}; Id: {dataItem.Id}");
- await OnEditModelSaving.InvokeAsync(e);
+ await OnGridEditModelSaving.InvokeAsync(e);
if (e.Cancel)
{
@@ -153,15 +206,31 @@ namespace TIAMSharedUI.Shared.Components.Grids
return;
}
- if (e.IsNew) await AddDataItem(dataItem);
- else await UpdateDataItem(dataItem);
+ if (!e.IsNew) _dataSource.SetTrackingStateToUpdate(dataItem);
+ else
+ {
+ if (dataItem.Id.IsNullOrEmpty()) dataItem.Id = Guid.NewGuid();
+ _dataSource.Add(dataItem);
+ }
+
+ try
+ {
+ var unsavedItems = await _dataSource.SaveChanges();
+
+ if (unsavedItems.Count > 0)
+ Logger.Error($"OnItemSaving->TrySaveChanges error! unsavedCount: {unsavedItems.Count}");
+ }
+ catch (Exception ex)
+ {
+ Logger.Error($"{_gridLogName} OnItemSaving", ex);
+ }
}
private async Task OnItemDeleting(GridDataItemDeletingEventArgs e)
{
Logger.Info($"{_gridLogName} OnItemDeleting");
- await OnDataItemDeleting.InvokeAsync(e);
+ await OnGridItemDeleting.InvokeAsync(e);
if (e.Cancel)
{
@@ -170,32 +239,19 @@ namespace TIAMSharedUI.Shared.Components.Grids
}
var dataItem = (e.DataItem as TDataItem)!;
- await RemoveDataItem(dataItem);
- }
+ _dataSource.Remove(dataItem);
- public virtual Task RefreshDataSourceAsync()
- {
- if (GetAllMessageTag == 0) return Task.CompletedTask;
-
- Logger.Info($"{_gridLogName} RefreshDataSourceAsync called");
-
- return SignalRClient.GetAllAsync>(GetAllMessageTag, ContextId, response =>
- {
- if (response.Status == SignalResponseStatus.Error)
- return;
-
- BeginUpdate();
- DataSource = response.ResponseData ?? [];
- EndUpdate();
-
- InvokeAsync(StateHasChanged).Forget();
- });
+ var unsavedItems = await _dataSource.SaveChanges();
+ if (unsavedItems.Count > 0)
+ Logger.Error($"OnItemDeleting->TrySaveChanges error! unsavedCount: {unsavedItems.Count}");
}
protected virtual async Task PostDataToServerAsync(TDataItem dataItem, int messageTag, TrackingState trackingState)
{
+ return;
+
var changingEventArgs = new GridDataItemChangingEventArgs(this, dataItem, trackingState);
- await OnDataItemChanging.InvokeAsync(changingEventArgs);
+ await OnGridItemChanging.InvokeAsync(changingEventArgs);
if (changingEventArgs.IsCanceled)
{
@@ -211,21 +267,21 @@ namespace TIAMSharedUI.Shared.Components.Grids
_dataSource.UpdateCollection(dataItem, 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.
- SignalRClient.PostDataAsync(messageTag, dataItem, async response =>
- {
- if (response.Status != SignalResponseStatus.Success || response.ResponseData == null)
- {
- RefreshDataSourceAsync().Forget();
- return;
- }
+ //SignalRClient.PostDataAsync(messageTag, dataItem, async response =>
+ //{
+ // if (response.Status != SignalResponseStatus.Success || response.ResponseData == null)
+ // {
+ // RefreshDataSourceAsync().Forget();
+ // return;
+ // }
- _dataSource.UpdateCollection(response.ResponseData, trackingState == TrackingState.Remove);
+ // _dataSource.UpdateCollection(response.ResponseData, trackingState == TrackingState.Remove);
- var changedEventArgs = new GridDataItemChangedEventArgs(this, response.ResponseData, trackingState);
- await OnDataItemChanged.InvokeAsync(changedEventArgs);
+ // var changedEventArgs = new GridDataItemChangedEventArgs(this, response.ResponseData, trackingState);
+ // await OnDataItemChanged.InvokeAsync(changedEventArgs);
- InvokeAsync(StateHasChanged).Forget();
- }).Forget();
+ // InvokeAsync(StateHasChanged).Forget();
+ //}).Forget();
//transfer = await devAdminSignalClient.PostDataAsync(SignalRTags.UpdateTransferAsync, transfer);
}
@@ -250,6 +306,7 @@ namespace TIAMSharedUI.Shared.Components.Grids
{
base.DataItemDeleting = EventCallback.Factory.Create(this, OnItemDeleting);
base.EditModelSaving = EventCallback.Factory.Create(this, OnItemSaving);
+
CustomizeElement += OnCustomizeElement;
//ShowFilterRow = true;
diff --git a/TIAMWebApp/Shared/Utility/SignalRDataSource.cs b/TIAMWebApp/Shared/Utility/SignalRDataSource.cs
index 19b2c826..1a6ce0d3 100644
--- a/TIAMWebApp/Shared/Utility/SignalRDataSource.cs
+++ b/TIAMWebApp/Shared/Utility/SignalRDataSource.cs
@@ -7,6 +7,7 @@ using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using AyCode.Core.Enums;
using AyCode.Core.Extensions;
+using AyCode.Core.Helpers;
using AyCode.Core.Interfaces;
using AyCode.Services.SignalRs;
using TIAM.Services;
@@ -18,7 +19,7 @@ namespace TIAMWebApp.Shared.Application.Utility
{
public TrackingState TrackingState { get; internal set; } = trackingState;
public T CurrentValue { get; internal set; } = currentValue;
- public T? OriginalValue { get; init; } = originalValue; //originalValue == null ? null : TrackingItemHelpers.Clone(originalValue);
+ public T? OriginalValue { get; init; } = originalValue;
internal TrackingItem UpdateItem(TrackingState trackingState, T newValue)
{
@@ -32,7 +33,7 @@ namespace TIAMWebApp.Shared.Application.Utility
}
- public class ChangeTracking where T : class, IId
+ public class ChangeTracking /*: IEnumerable>*/ where T : class, IId
{
private readonly List> _trackingItems = []; //TODO: Dictionary... - J.
@@ -58,7 +59,7 @@ namespace TIAMWebApp.Shared.Application.Utility
}
if (originalValue != null && Equals(newValue, originalValue))
- originalValue = TrackingItemHelpers.ReflectionClone(originalValue);
+ originalValue = TrackingItemHelpers.JsonClone(originalValue);
trackingItem = new TrackingItem(trackingState, newValue, originalValue);
_trackingItems.Add(trackingItem);
@@ -77,6 +78,16 @@ namespace TIAMWebApp.Shared.Application.Utility
}
internal void Remove(TrackingItem trackingItem) => _trackingItems.Remove(trackingItem);
+
+ //public IEnumerator> GetEnumerator()
+ //{
+ // return _trackingItems.GetEnumerator();
+ //}
+
+ //IEnumerator IEnumerable.GetEnumerator()
+ //{
+ // return GetEnumerator();
+ //}
}
@@ -91,17 +102,18 @@ namespace TIAMWebApp.Shared.Application.Utility
protected readonly ChangeTracking TrackingItems = new();
protected readonly Guid? ContextId;
- protected readonly AcSignalRClientBase SignalRClient;
+ public AcSignalRClientBase SignalRClient;
protected readonly SignalRCrudTags SignalRCrudTags;
- public SignalRDataSource(AcSignalRClientBase signalRClient, SignalRCrudTags signalRCrudTags, Guid? contextId = null, bool autoLoadDataSource = true)
+ public Func, Task>? OnDataSourceItemChanged;
+ public Func? OnDataSourceLoaded;
+
+ public SignalRDataSource(AcSignalRClientBase signalRClient, SignalRCrudTags signalRCrudTags, Guid? contextId = null)
{
ContextId = contextId;
SignalRCrudTags = signalRCrudTags;
SignalRClient = signalRClient;
-
- if (autoLoadDataSource) LoadDataSource(false);
}
public bool IsSynchronized => true;
@@ -113,38 +125,79 @@ namespace TIAMWebApp.Shared.Application.Utility
///
///
///
- public void LoadDataSource(bool clearChangeTracking = true)
+ public async Task LoadDataSource(bool clearChangeTracking = true)
{
if (SignalRCrudTags.GetAllMessageTag == SignalRTags.None) throw new ArgumentException($"SignalRCrudTags.GetAllMessageTag == SignalRTags.None");
- lock (_syncRoot)
- {
- var resultList = SignalRClient.GetAllAsync>(SignalRCrudTags.GetAllMessageTag, ContextId).GetAwaiter().GetResult() ?? throw new NullReferenceException();
+ var resultList = (await SignalRClient.GetAllAsync>(SignalRCrudTags.GetAllMessageTag, ContextId)) ?? throw new NullReferenceException();
- Clear(clearChangeTracking);
- InnerList.AddRange(resultList);
- }
+ LoadDataSource(resultList);
}
- public T? LoadItem(Guid id)
+ 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($"result.Status != SignalResponseStatus.Success || result.ResponseData == null; Status: {SignalResponseStatus.Success}");
+
+ LoadDataSource(result.ResponseData);
+ });
+ }
+
+ 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;
- lock (_syncRoot)
+ Monitor.Enter(_syncRoot);
+
+ try
{
- resultitem = SignalRClient.GetByIdAsync(SignalRCrudTags.GetItemMessageTag, id).GetAwaiter().GetResult();
+ 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
///
@@ -157,17 +210,28 @@ namespace TIAMWebApp.Shared.Application.Utility
{
if ((uint)index >= (uint)Count) throw new ArgumentOutOfRangeException(nameof(index));
- lock (_syncRoot)
+ Monitor.Enter(_syncRoot);
+ try
{
return InnerList[index];
}
+ finally
+ {
+ Monitor.Exit(_syncRoot);
+ }
}
set
{
- lock (_syncRoot)
+ Monitor.Enter(_syncRoot);
+ try
{
Update(index, value);
}
+ finally
+ {
+ Monitor.Exit(_syncRoot);
+ }
+
}
}
@@ -180,13 +244,20 @@ namespace TIAMWebApp.Shared.Application.Utility
{
if (newValue.Id.IsNullOrEmpty()) throw new ArgumentNullException(nameof(newValue), @"Add->newValue.Id.IsNullOrEmpty()");
- lock (_syncRoot)
+ 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);
+ }
+
}
///
@@ -198,12 +269,19 @@ namespace TIAMWebApp.Shared.Application.Utility
{
if (newValue.Id.IsNullOrEmpty()) throw new ArgumentNullException(nameof(newValue), @"AddOrUpdate->newValue.Id.IsNullOrEmpty()");
- lock (_syncRoot)
+ Monitor.Enter(_syncRoot);
+
+ try
{
var index = IndexOf(newValue);
return index > -1 ? Update(index, newValue) : UnsafeAdd(newValue);
}
+ finally
+ {
+ Monitor.Exit(_syncRoot);
+ }
+
}
//public void AddRange(IEnumerable collection)
@@ -233,7 +311,9 @@ namespace TIAMWebApp.Shared.Application.Utility
{
if (newValue.Id.IsNullOrEmpty()) throw new ArgumentNullException(nameof(newValue), @"Insert->newValue.Id.IsNullOrEmpty()");
- lock (_syncRoot)
+ Monitor.Enter(_syncRoot);
+
+ try
{
if (Contains(newValue))
throw new ArgumentException($@"It already contains this Id! Id: {newValue.Id}", nameof(newValue));
@@ -241,6 +321,11 @@ namespace TIAMWebApp.Shared.Application.Utility
TrackingItems.AddTrackingItem(TrackingState.Add, newValue);
InnerList.Insert(index, newValue);
}
+ finally
+ {
+ Monitor.Exit(_syncRoot);
+ }
+
}
///
@@ -264,7 +349,9 @@ namespace TIAMWebApp.Shared.Application.Utility
if (newValue.Id.IsNullOrEmpty()) throw new ArgumentNullException(nameof(newValue), @"Update->newValue.Id.IsNullOrEmpty()");
if ((uint)index >= (uint)Count) throw new ArgumentOutOfRangeException(nameof(index));
- lock (_syncRoot)
+ Monitor.Enter(_syncRoot);
+
+ try
{
var currentItem = InnerList[index];
@@ -276,6 +363,11 @@ namespace TIAMWebApp.Shared.Application.Utility
return newValue;
}
+ finally
+ {
+ Monitor.Exit(_syncRoot);
+ }
+
}
///
@@ -285,7 +377,9 @@ namespace TIAMWebApp.Shared.Application.Utility
///
public bool Remove(T item)
{
- lock (_syncRoot)
+ Monitor.Enter(_syncRoot);
+
+ try
{
var index = IndexOf(item);
@@ -294,6 +388,11 @@ namespace TIAMWebApp.Shared.Application.Utility
RemoveAt(index);
return true;
}
+ finally
+ {
+ Monitor.Exit(_syncRoot);
+ }
+
}
///
@@ -304,10 +403,17 @@ namespace TIAMWebApp.Shared.Application.Utility
///
public bool TryRemove(Guid id, out T? item)
{
- lock (_syncRoot)
+ Monitor.Enter(_syncRoot);
+
+ try
{
return TryGetValue(id, out item) && Remove(item);
}
+ finally
+ {
+ Monitor.Exit(_syncRoot);
+ }
+
}
///
@@ -319,7 +425,9 @@ namespace TIAMWebApp.Shared.Application.Utility
///
public void RemoveAt(int index)
{
- lock (_syncRoot)
+ Monitor.Enter(_syncRoot);
+
+ try
{
var currentItem = InnerList[index];
if (currentItem.Id.IsNullOrEmpty()) throw new ArgumentNullException(nameof(currentItem), $@"RemoveAt->item.Id.IsNullOrEmpty(); index: {index}");
@@ -327,6 +435,11 @@ namespace TIAMWebApp.Shared.Application.Utility
TrackingItems.AddTrackingItem(TrackingState.Remove, currentItem, currentItem);
InnerList.RemoveAt(index);
}
+ finally
+ {
+ Monitor.Exit(_syncRoot);
+ }
+
}
///
@@ -335,21 +448,39 @@ namespace TIAMWebApp.Shared.Application.Utility
///
public List> GetTrackingItems()
{
- lock (_syncRoot)
+ Monitor.Enter(_syncRoot);
+
+ try
+ {
return TrackingItems.ToList();
+ }
+ finally
+ {
+ Monitor.Exit(_syncRoot);
+ }
}
public void SetTrackingStateToUpdate(T item)
{
- if (TrackingItems.TryGetTrackingItem(item.Id, out var trackingItem))
+ Monitor.Enter(_syncRoot);
+
+ try
{
- if (trackingItem.TrackingState != TrackingState.Add)
- trackingItem.TrackingState = TrackingState.Update;
+ if (TrackingItems.TryGetTrackingItem(item.Id, out var trackingItem))
+ {
+ if (trackingItem.TrackingState != TrackingState.Add)
+ trackingItem.TrackingState = TrackingState.Update;
- return;
+ return;
+ }
+
+ if (!TryGetValue(item.Id, out var originalItem)) return;
+ TrackingItems.AddTrackingItem(TrackingState.Update, item, originalItem);
+ }
+ finally
+ {
+ Monitor.Exit(_syncRoot);
}
-
- TrackingItems.AddTrackingItem(TrackingState.Update, item, item);
}
///
@@ -360,33 +491,49 @@ namespace TIAMWebApp.Shared.Application.Utility
///
public bool TryGetTrackingItem(Guid id, [NotNullWhen(true)] out TrackingItem? trackingItem)
{
- lock (_syncRoot)
+ Monitor.Enter(_syncRoot);
+
+ try
+ {
return TrackingItems.TryGetTrackingItem(id, out trackingItem);
+ }
+ finally
+ {
+ Monitor.Exit(_syncRoot);
+ }
+
}
///
///
///
/// Unsaved items
- public bool SaveChanges(out List> unsavedItems)
+ public async Task>> SaveChanges()
{
- lock (_syncRoot)
+ Monitor.Enter(_syncRoot);
+
+ try
{
foreach (var trackingItem in TrackingItems.ToList())
{
try
{
- SaveTrackingItemUnsafe(trackingItem);
+ //throw new Exception();
+ await SaveTrackingItemUnsafe(trackingItem);
}
- catch
+ catch(Exception ex)
{
- // ignored
+ TryRollbackItem(trackingItem.CurrentValue.Id, out _);
}
}
- unsavedItems = TrackingItems.ToList();
- return unsavedItems.Count == 0;
+ return TrackingItems.ToList();
}
+ finally
+ {
+ Monitor.Exit(_syncRoot);
+ }
+
}
///
@@ -395,34 +542,55 @@ namespace TIAMWebApp.Shared.Application.Utility
///
///
///
- public bool TrySaveItem(Guid id, [NotNullWhen(true)] out T? resultItem)
+ public async Task SaveItem(Guid id)
{
- resultItem = null;
+ Monitor.Enter(_syncRoot);
- if (TryGetTrackingItem(id, out var trackingItem))
- resultItem = SaveTrackingItemUnsafe(trackingItem);
+ try
+ {
+ T? resultItem = null;
- return resultItem != null;
+ if (TryGetTrackingItem(id, out var trackingItem))
+ resultItem = await SaveTrackingItemUnsafe(trackingItem);
+
+ return resultItem;
+ }
+ finally
+ {
+ Monitor.Exit(_syncRoot);
+ }
}
- public bool TrySaveItem(Guid id, TrackingState trackingState, [NotNullWhen(true)] out T? resultItem)
- => TryGetValue(id, out resultItem) && TrySaveItem(resultItem, trackingState, out resultItem);
-
- public bool TrySaveItem(T item, TrackingState trackingState, [NotNullWhen(true)] out T? resultItem)
+ public async Task SaveItem(Guid id, TrackingState trackingState)
{
- resultItem = SaveItemUnsafe(item, trackingState);
- return resultItem != null;
+ Monitor.Enter(_syncRoot);
+
+ try
+ {
+ T? resultItem = null;
+
+ if (TryGetValue(id, out var item))
+ resultItem = await SaveItem(item, trackingState);
+
+ return resultItem;
+ }
+ finally
+ {
+ Monitor.Exit(_syncRoot);
+ }
}
- protected T? SaveTrackingItemUnsafe(TrackingItem trackingItem)
+ public Task SaveItem(T item, TrackingState trackingState) => SaveItemUnsafe(item, trackingState);
+
+ protected Task SaveTrackingItemUnsafe(TrackingItem trackingItem)
=> SaveItemUnsafe(trackingItem.CurrentValue, trackingItem.TrackingState);
- protected T? SaveItemUnsafe(T item, TrackingState trackingState)
+ protected async Task SaveItemUnsafe(T item, TrackingState trackingState)
{
var messageTag = SignalRCrudTags.GetMessageTagByTrackingState(trackingState);
if (messageTag == SignalRTags.None) return null; //throw new ArgumentException($"messageTag == SignalRTags.None");
- var result = SignalRClient.PostDataAsync(messageTag, item).GetAwaiter().GetResult();
+ var result = await SignalRClient.PostDataAsync(messageTag, item);
if (result == null) return null; //throw new NullReferenceException($"result == null");
if (TryGetTrackingItem(item.Id, out var trackingItem))
@@ -431,6 +599,9 @@ namespace TIAMWebApp.Shared.Application.Utility
if (TryGetIndex(result.Id, out var index))
InnerList[index] = result;
+ var eventArgs = new ItemChangedEventArgs(result, trackingState);
+ if (OnDataSourceItemChanged != null) await OnDataSourceItemChanged.Invoke(eventArgs);
+
return result;
}
@@ -449,7 +620,8 @@ namespace TIAMWebApp.Shared.Application.Utility
public bool TryRollbackItem(Guid id, out T? originalValue)
{
- lock (_syncRoot)
+ Monitor.Enter(_syncRoot);
+ try
{
if (TryGetTrackingItem(id, out var trackingItem))
{
@@ -462,22 +634,40 @@ namespace TIAMWebApp.Shared.Application.Utility
originalValue = null;
return false;
}
+ finally
+ {
+ Monitor.Exit(_syncRoot);
+ }
}
public void Rollback()
{
- lock (_syncRoot)
+ Monitor.Enter(_syncRoot);
+ try
{
foreach (var trackingItem in TrackingItems.ToList())
RollbackItemUnsafe(trackingItem);
}
+ finally
+ {
+ Monitor.Exit(_syncRoot);
+ }
}
public int Count
{
get
{
- lock (_syncRoot) return InnerList.Count;
+ Monitor.Enter(_syncRoot);
+ try
+ {
+ return InnerList.Count;
+ }
+ finally
+ {
+ Monitor.Exit(_syncRoot);
+ }
+
}
}
@@ -485,17 +675,30 @@ namespace TIAMWebApp.Shared.Application.Utility
public void Clear(bool clearChangeTracking)
{
- lock (_syncRoot)
+ Monitor.Enter(_syncRoot);
+ try
{
if (clearChangeTracking) TrackingItems.Clear();
InnerList.Clear();
}
+ finally
+ {
+ Monitor.Exit(_syncRoot);
+ }
}
public int IndexOf(Guid id)
{
- lock (_syncRoot)
+ Monitor.Enter(_syncRoot);
+ try
+ {
return InnerList.FindIndex(x => x.Id == id);
+ }
+ finally
+ {
+ Monitor.Exit(_syncRoot);
+ }
+
}
public int IndexOf(T item) => IndexOf(item.Id);
@@ -505,22 +708,37 @@ namespace TIAMWebApp.Shared.Application.Utility
public bool TryGetValue(Guid id, [NotNullWhen(true)] out T? item)
{
- lock (_syncRoot)
+ 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)
{
- lock (_syncRoot) InnerList.CopyTo(array, 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)
@@ -528,8 +746,15 @@ namespace TIAMWebApp.Shared.Application.Utility
if (Count - index < count)
throw new ArgumentException("Invalid length");
- lock (_syncRoot)
- return InnerList.BinarySearch(index, count, item, comparer);
+ //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);
@@ -537,8 +762,17 @@ namespace TIAMWebApp.Shared.Application.Utility
public IEnumerator GetEnumerator()
{
- lock (_syncRoot)
- return InnerList.ToList().GetEnumerator();
+ Monitor.Enter(_syncRoot);
+ try
+ {
+ //return InnerList.ToList().GetEnumerator();
+ return InnerList.GetEnumerator();
+ }
+ finally
+ {
+ Monitor.Exit(_syncRoot);
+ }
+
}
public ReadOnlyCollection AsReadOnly() => new(this);
@@ -618,11 +852,17 @@ namespace TIAMWebApp.Shared.Application.Utility
try
{
- lock (_syncRoot)
+ 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)
{
@@ -638,4 +878,16 @@ namespace TIAMWebApp.Shared.Application.Utility
#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; }
+ }
}
diff --git a/TIAMWebApp/Shared/Utility/SignalRDataSourceAsync.cs b/TIAMWebApp/Shared/Utility/SignalRDataSourceAsync.cs
index e6361fa2..d435cb51 100644
--- a/TIAMWebApp/Shared/Utility/SignalRDataSourceAsync.cs
+++ b/TIAMWebApp/Shared/Utility/SignalRDataSourceAsync.cs
@@ -16,7 +16,7 @@ public class SignalRDataSourceAsync : SignalRDataSource where T : class, I
public Action>? OnDataSourceLoaded;
public SignalRDataSourceAsync(AcSignalRClientBase signalRClient, SignalRCrudTags signalRCrudTags, Guid? contextId = null, Action>? onDataSourceLoaded = null, bool autoLoadDataSource = false)
- : base(signalRClient, signalRCrudTags, contextId, false)
+ : base(signalRClient, signalRCrudTags, contextId)
{
OnDataSourceLoaded = onDataSourceLoaded;
@@ -27,34 +27,34 @@ public class SignalRDataSourceAsync : SignalRDataSource where T : class, I
{
if (SignalRCrudTags.GetAllMessageTag == SignalRTags.None) throw new ArgumentException($"_signalRCrudTags.GetAllMessageTag == SignalRTags.None;");
- Monitor.Exit(SyncRoot); //Exception test - J.
+ //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");
+ //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);
- }
+ // Clear(clearChangeTracking);
+ // InnerList.AddRange(response.ResponseData);
+ // }
+ // finally
+ // {
+ // Monitor.Exit(SyncRoot);
+ // }
- OnDataSourceLoaded?.Invoke(this);
- }).Forget();
- }
- catch (Exception)
- {
- Monitor.Exit(SyncRoot);
- throw;
- }
+ // OnDataSourceLoaded?.Invoke(this);
+ // }).Forget();
+ //}
+ //catch (Exception)
+ //{
+ // Monitor.Exit(SyncRoot);
+ // throw;
+ //}
}
@@ -101,17 +101,4 @@ public class SignalRDataSourceAsync : SignalRDataSource where T : class, I
// return Task.CompletedTask;
//}
-
- public class ItemChangedEventArgs where T : IId
- {
- internal ItemChangedEventArgs(T item, TrackingState trackingState)
- {
- Item = item;
- TrackingState = trackingState;
- }
-
- public T Item { get; }
- public TrackingState TrackingState { get; }
- }
-
}
\ No newline at end of file
From c349c3c43270e774bb10e1012fca5071e05cd94d Mon Sep 17 00:00:00 2001
From: Loretta
Date: Mon, 10 Jun 2024 19:29:25 +0200
Subject: [PATCH 5/5] TiamGrid, SignalRDataSource fixes, improvement;
---
.../Shared/Components/Grids/TiamGrid.cs | 230 ++++++++----------
.../Shared/Utility/SignalRDataSource.cs | 229 +++++++++++++----
2 files changed, 284 insertions(+), 175 deletions(-)
diff --git a/TIAMSharedUI/Shared/Components/Grids/TiamGrid.cs b/TIAMSharedUI/Shared/Components/Grids/TiamGrid.cs
index 545fddc3..f36fb4b7 100644
--- a/TIAMSharedUI/Shared/Components/Grids/TiamGrid.cs
+++ b/TIAMSharedUI/Shared/Components/Grids/TiamGrid.cs
@@ -1,46 +1,19 @@
using System.ComponentModel;
-using System.Data.Common;
using AyCode.Core;
using AyCode.Core.Enums;
using AyCode.Core.Extensions;
using AyCode.Core.Helpers;
using AyCode.Core.Interfaces;
-using AyCode.Interfaces.Entities;
using AyCode.Services.SignalRs;
using AyCode.Utils.Extensions;
using DevExpress.Blazor;
-using DevExpress.Blazor.Internal;
using Microsoft.AspNetCore.Components;
-using Microsoft.AspNetCore.Components.Web;
using TIAM.Services;
using TIAMWebApp.Shared.Application.Services;
using TIAMWebApp.Shared.Application.Utility;
namespace TIAMSharedUI.Shared.Components.Grids
{
- public class GridDataItemChangingEventArgs : GridDataItemChangedEventArgs where TDataItem : class, IId
- {
- internal GridDataItemChangingEventArgs(TiamGrid grid, TDataItem dataItem, TrackingState trackingState) : base(grid, dataItem, trackingState)
- {
- }
-
- public bool IsCanceled { get; set; }
- }
-
- public class GridDataItemChangedEventArgs where TDataItem : class, IId
- {
- internal GridDataItemChangedEventArgs(TiamGrid grid, TDataItem dataItem, TrackingState trackingState)
- {
- Grid = grid;
- DataItem = dataItem;
- TrackingState = trackingState;
- }
-
- public TiamGrid Grid { get; }
- public TDataItem DataItem { get; }
- public TrackingState TrackingState { get; }
- }
-
public class TiamGrid : DxGrid where TDataItem : class, IId
{
protected bool IsFirstInitializeParameters;
@@ -71,10 +44,12 @@ namespace TIAMSharedUI.Shared.Components.Grids
[Parameter] public EventCallback> OnDataSourceChanged { get; set; }
[Parameter] public EventCallback> OnGridItemChanging { get; set; }
+
///
- /// After server response!
+ /// After the server has responded!
///
- [Parameter] public EventCallback> OnGridItemChanged { get; set; }
+ [Parameter]
+ public EventCallback> OnGridItemChanged { get; set; }
[Parameter]
[DefaultValue(null)]
@@ -91,27 +66,7 @@ namespace TIAMSharedUI.Shared.Components.Grids
return _dataSource!;
}
- set
- {
- if (value == null) return;
- _dataSourceParam = value;
-
- //bool equals;
-
- //if ((equals = Equals(_dataSource, value)) == false)
- //{
- // if (value is SignalRDataSource dataSource)
- // _dataSource = dataSource;
- // else
- // {
- // var crudTags = new SignalRCrudTags(GetAllMessageTag, SignalRTags.None, AddMessageTag, UpdateMessageTag, RemoveMessageTag);
- // _dataSource = new SignalRDataSource(value, SignalRClient, crudTags, ContextId);
- // }
- //}
-
- //Data = _dataSource;
- //if (!equals) OnDataSourceChanged.InvokeAsync(_dataSource);
- }
+ set => _dataSourceParam = value;
}
protected override async Task OnInitializedAsync()
@@ -127,7 +82,7 @@ namespace TIAMSharedUI.Shared.Components.Grids
var crudTags = new SignalRCrudTags(GetAllMessageTag, SignalRTags.None, AddMessageTag, UpdateMessageTag, RemoveMessageTag);
_dataSource = new SignalRDataSource(SignalRClient, crudTags, ContextId);
-
+
Data = _dataSource;
_dataSource.OnDataSourceLoaded += OnDataSourceLoaded;
@@ -136,20 +91,22 @@ namespace TIAMSharedUI.Shared.Components.Grids
await base.OnInitializedAsync();
}
- private Task OnDataSourceItemChanged(ItemChangedEventArgs args)
+ private async Task OnDataSourceItemChanged(ItemChangedEventArgs args)
{
- if (args.TrackingState is TrackingState.GetAll or TrackingState.None) return Task.CompletedTask;
+ if (args.TrackingState is TrackingState.GetAll or TrackingState.None) return;
- Logger.Info($"{_gridLogName} OnItemLoaded; trackingState: {args.TrackingState}");
+ Logger.Debug($"{_gridLogName} OnDataSourceItemChanged; trackingState: {args.TrackingState}");
var changedEventArgs = new GridDataItemChangedEventArgs(this, args.Item, args.TrackingState);
- return OnGridItemChanged.InvokeAsync(changedEventArgs);
+ await OnGridItemChanged.InvokeAsync(changedEventArgs);
+
+ await InvokeAsync(StateHasChanged);
}
private Task OnDataSourceLoaded()
{
- Logger.Info($"{_gridLogName} OnDataSourceLoaded");
-
+ Logger.Debug($"{_gridLogName} OnDataSourceLoaded");
+
Reload();
return OnDataSourceChanged.InvokeAsync(_dataSource);
}
@@ -165,28 +122,18 @@ namespace TIAMSharedUI.Shared.Components.Grids
}
}
- public Task AddDataItem(TDataItem dataItem) => AddDataItem(dataItem, AddMessageTag);
- public Task AddDataItem(TDataItem dataItem, int messageTag) => PostDataToServerAsync(dataItem, messageTag, TrackingState.Add);
-
- public Task UpdateDataItem(TDataItem dataItem) => UpdateDataItem(dataItem, UpdateMessageTag);
- public Task UpdateDataItem(TDataItem dataItem, int messageTag) => PostDataToServerAsync(dataItem, messageTag, TrackingState.Update);
-
- public Task RemoveDataItem(TDataItem dataItem) => RemoveDataItem(dataItem, RemoveMessageTag);
- public Task RemoveDataItem(TDataItem dataItem, int messageTag) => PostDataToServerAsync(dataItem, messageTag, TrackingState.Remove);
-
- public Task RemoveDataItem(Guid id) => RemoveDataItem(id, RemoveMessageTag);
-
- public async Task RemoveDataItem(Guid id, int messageTag)
+ public Task AddDataItem(TDataItem dataItem)
{
- var dataItem = _dataSource.FirstOrDefault(x => x.Id == id);
- if (dataItem != null)
- {
- _dataSource.Remove(dataItem);
- await _dataSource.SaveChanges();
- //await RemoveDataItem(dataItem);
- }
+ if (dataItem.Id.IsNullOrEmpty()) dataItem.Id = Guid.NewGuid();
+ return _dataSource.Add(dataItem, true);
+ }
- await InvokeAsync(StateHasChanged);
+ public Task AddDataItemAsync(TDataItem dataItem)
+ {
+ if (dataItem.Id.IsNullOrEmpty()) dataItem.Id = Guid.NewGuid();
+ _dataSource.Add(dataItem);
+
+ return SaveChangesToServerAsync();
}
private async Task OnItemSaving(GridEditModelSavingEventArgs e)
@@ -196,7 +143,7 @@ namespace TIAMSharedUI.Shared.Components.Grids
if (e.IsNew && dataItem.Id.IsNullOrEmpty()) dataItem.Id = Guid.NewGuid();
var logText = e.IsNew ? "add" : "update";
- Logger.Info($"{_gridLogName} OnItemSaving {logText}; Id: {dataItem.Id}");
+ Logger.Debug($"{_gridLogName} OnItemSaving {logText}; Id: {dataItem.Id}");
await OnGridEditModelSaving.InvokeAsync(e);
@@ -206,29 +153,46 @@ namespace TIAMSharedUI.Shared.Components.Grids
return;
}
- if (!e.IsNew) _dataSource.SetTrackingStateToUpdate(dataItem);
- else
+ if (e.IsNew) await AddDataItemAsync(dataItem);
+ else await UpdateDataItemAsync(dataItem);
+ }
+
+ private Task SaveChangesToServerAsync()
+ {
+ try
{
- if (dataItem.Id.IsNullOrEmpty()) dataItem.Id = Guid.NewGuid();
- _dataSource.Add(dataItem);
+ return _dataSource.SaveChangesAsync();
}
+ catch (Exception ex)
+ {
+ Logger.Error($"{_gridLogName} SaveChangesToServerAsync->SaveChangesAsync error!", ex);
+ }
+
+ return Task.CompletedTask;
+ }
+
+ private async Task SaveChangesToServer()
+ {
+ var result = false;
try
{
var unsavedItems = await _dataSource.SaveChanges();
- if (unsavedItems.Count > 0)
- Logger.Error($"OnItemSaving->TrySaveChanges error! unsavedCount: {unsavedItems.Count}");
+ if ((result = unsavedItems.Count == 0) == false)
+ Logger.Error($"{_gridLogName} SaveChangesToServer->SaveChanges error! unsavedCount: {unsavedItems.Count}");
}
catch (Exception ex)
{
Logger.Error($"{_gridLogName} OnItemSaving", ex);
}
+
+ return result;
}
private async Task OnItemDeleting(GridDataItemDeletingEventArgs e)
{
- Logger.Info($"{_gridLogName} OnItemDeleting");
+ Logger.Debug($"{_gridLogName} OnItemDeleting");
await OnGridItemDeleting.InvokeAsync(e);
@@ -239,54 +203,9 @@ namespace TIAMSharedUI.Shared.Components.Grids
}
var dataItem = (e.DataItem as TDataItem)!;
- _dataSource.Remove(dataItem);
-
- var unsavedItems = await _dataSource.SaveChanges();
- if (unsavedItems.Count > 0)
- Logger.Error($"OnItemDeleting->TrySaveChanges error! unsavedCount: {unsavedItems.Count}");
+ await RemoveDataItem(dataItem);
}
- protected virtual async Task PostDataToServerAsync(TDataItem dataItem, int messageTag, TrackingState trackingState)
- {
- return;
-
- var changingEventArgs = new GridDataItemChangingEventArgs(this, dataItem, trackingState);
- await OnGridItemChanging.InvokeAsync(changingEventArgs);
-
- if (changingEventArgs.IsCanceled)
- {
- Logger.Debug($"{_gridLogName} OnDataItemChanging canceled");
- return;
- }
-
- if (messageTag == 0) return;
-
- Logger.Info($"{_gridLogName} PostDataToServerAsync called; transferId " + dataItem.Id);
-
- if (dataItem.Id.IsNullOrEmpty()) dataItem.Id = Guid.NewGuid();
-
- _dataSource.UpdateCollection(dataItem, 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.
-
- //SignalRClient.PostDataAsync(messageTag, dataItem, async response =>
- //{
- // if (response.Status != SignalResponseStatus.Success || response.ResponseData == null)
- // {
- // RefreshDataSourceAsync().Forget();
- // return;
- // }
-
- // _dataSource.UpdateCollection(response.ResponseData, trackingState == TrackingState.Remove);
-
- // var changedEventArgs = new GridDataItemChangedEventArgs(this, response.ResponseData, trackingState);
- // await OnDataItemChanged.InvokeAsync(changedEventArgs);
-
- // InvokeAsync(StateHasChanged).Forget();
- //}).Forget();
-
- //transfer = await devAdminSignalClient.PostDataAsync(SignalRTags.UpdateTransferAsync, transfer);
- }
-
-
private void OnCustomizeElement(GridCustomizeElementEventArgs e)
{
if (e.ElementType == GridElementType.DetailCell)
@@ -341,5 +260,54 @@ namespace TIAMSharedUI.Shared.Components.Grids
_gridLogName = $"[{GridName}]";
}
+
+ //public Task AddDataItem(TDataItem dataItem, int messageTag) => PostDataToServerAsync(dataItem, messageTag, TrackingState.Add);
+
+ public Task UpdateDataItem(TDataItem dataItem) => _dataSource.Update(dataItem, true);
+
+ public Task UpdateDataItemAsync(TDataItem dataItem)
+ {
+ _dataSource.Update(dataItem, false);
+ return SaveChangesToServerAsync();
+ }
+ //public Task UpdateDataItem(TDataItem dataItem, int messageTag) => PostDataToServerAsync(dataItem, messageTag, TrackingState.Update);
+
+ public Task AddOrUpdateDataItem(TDataItem dataItem) => _dataSource.AddOrUpdate(dataItem, true);
+
+ public Task RemoveDataItem(TDataItem dataItem) => _dataSource.Remove(dataItem, true);
+ //public Task RemoveDataItem(TDataItem dataItem, int messageTag) => PostDataToServerAsync(dataItem, messageTag, TrackingState.Remove);
+
+ public Task RemoveDataItem(Guid id) => RemoveDataItem(id, RemoveMessageTag);
+
+ public Task RemoveDataItem(Guid id, int messageTag)
+ {
+ var dataItem = _dataSource.FirstOrDefault(x => x.Id == id);
+ if (dataItem == null) return Task.CompletedTask;
+
+ return _dataSource.Remove(dataItem, true);
+ }
+ }
+
+ public class GridDataItemChangingEventArgs : GridDataItemChangedEventArgs where TDataItem : class, IId
+ {
+ internal GridDataItemChangingEventArgs(TiamGrid grid, TDataItem dataItem, TrackingState trackingState) : base(grid, dataItem, trackingState)
+ {
+ }
+
+ public bool IsCanceled { get; set; }
+ }
+
+ public class GridDataItemChangedEventArgs where TDataItem : class, IId
+ {
+ internal GridDataItemChangedEventArgs(TiamGrid grid, TDataItem dataItem, TrackingState trackingState)
+ {
+ Grid = grid;
+ DataItem = dataItem;
+ TrackingState = trackingState;
+ }
+
+ public TiamGrid Grid { get; }
+ public TDataItem DataItem { get; }
+ public TrackingState TrackingState { get; }
}
}
diff --git a/TIAMWebApp/Shared/Utility/SignalRDataSource.cs b/TIAMWebApp/Shared/Utility/SignalRDataSource.cs
index 1a6ce0d3..fc9a14f3 100644
--- a/TIAMWebApp/Shared/Utility/SignalRDataSource.cs
+++ b/TIAMWebApp/Shared/Utility/SignalRDataSource.cs
@@ -131,7 +131,7 @@ namespace TIAMWebApp.Shared.Application.Utility
var resultList = (await SignalRClient.GetAllAsync>(SignalRCrudTags.GetAllMessageTag, ContextId)) ?? throw new NullReferenceException();
- LoadDataSource(resultList);
+ await LoadDataSource(resultList);
}
public Task LoadDataSourceAsync(bool clearChangeTracking = true)
@@ -141,9 +141,9 @@ namespace TIAMWebApp.Shared.Application.Utility
return SignalRClient.GetAllAsync>(SignalRCrudTags.GetAllMessageTag, ContextId, result=>
{
if (result.Status != SignalResponseStatus.Success || result.ResponseData == null)
- throw new NullReferenceException($"result.Status != SignalResponseStatus.Success || result.ResponseData == null; Status: {SignalResponseStatus.Success}");
+ throw new NullReferenceException($"LoadDataSourceAsync; result.Status != SignalResponseStatus.Success || result.ResponseData == null; Status: {SignalResponseStatus.Success}");
- LoadDataSource(result.ResponseData);
+ LoadDataSource(result.ResponseData).Forget();
});
}
@@ -225,7 +225,7 @@ namespace TIAMWebApp.Shared.Application.Utility
Monitor.Enter(_syncRoot);
try
{
- Update(index, value);
+ UpdateUnsafe(index, value);
}
finally
{
@@ -235,11 +235,6 @@ namespace TIAMWebApp.Shared.Application.Utility
}
}
- ///
- /// AddMessageTag
- ///
- ///
- ///
public void Add(T newValue)
{
if (newValue.Id.IsNullOrEmpty()) throw new ArgumentNullException(nameof(newValue), @"Add->newValue.Id.IsNullOrEmpty()");
@@ -257,15 +252,37 @@ namespace TIAMWebApp.Shared.Application.Utility
{
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 T AddOrUpdate(T newValue)
+ public async Task AddOrUpdate(T newValue, bool autoSave)
{
if (newValue.Id.IsNullOrEmpty()) throw new ArgumentNullException(nameof(newValue), @"AddOrUpdate->newValue.Id.IsNullOrEmpty()");
@@ -275,7 +292,7 @@ namespace TIAMWebApp.Shared.Application.Utility
{
var index = IndexOf(newValue);
- return index > -1 ? Update(index, newValue) : UnsafeAdd(newValue);
+ return index > -1 ? await Update(index, newValue, autoSave) : await Add(newValue, autoSave);
}
finally
{
@@ -292,12 +309,10 @@ namespace TIAMWebApp.Shared.Application.Utility
// }
//}
- protected T UnsafeAdd(T newValue)
+ protected void UnsafeAdd(T newValue)
{
TrackingItems.AddTrackingItem(TrackingState.Add, newValue);
InnerList.Add(newValue);
-
- return newValue;
}
///
@@ -305,6 +320,7 @@ namespace TIAMWebApp.Shared.Application.Utility
///
///
///
+ ///
///
///
public void Insert(int index, T newValue)
@@ -316,7 +332,7 @@ namespace TIAMWebApp.Shared.Application.Utility
try
{
if (Contains(newValue))
- throw new ArgumentException($@"It already contains this Id! Id: {newValue.Id}", nameof(newValue));
+ throw new ArgumentException($@"Insert; It already contains this Id! Id: {newValue.Id}", nameof(newValue));
TrackingItems.AddTrackingItem(TrackingState.Add, newValue);
InnerList.Insert(index, newValue);
@@ -325,28 +341,60 @@ namespace TIAMWebApp.Shared.Application.Utility
{
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 T Update(T newItem) => Update(IndexOf(newItem), newItem);
+ ///
+ public Task Update(T newItem, bool autoSave) => Update(IndexOf(newItem), newItem, autoSave);
///
/// UpdateMessageTag
///
///
///
+ ///
/// ///
/// ///
///
///
- public T Update(int index, T newValue)
+ 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), @"Update->newValue.Id.IsNullOrEmpty()");
+ 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);
@@ -356,20 +404,18 @@ namespace TIAMWebApp.Shared.Application.Utility
var currentItem = InnerList[index];
if (currentItem.Id != newValue.Id)
- throw new ArgumentException($@"currentItem.Id != item.Id! Id: {newValue.Id}", nameof(newValue));
+ throw new ArgumentException($@"UpdateUnsafe; currentItem.Id != item.Id! Id: {newValue.Id}", nameof(newValue));
TrackingItems.AddTrackingItem(TrackingState.Update, newValue, currentItem);
InnerList[index] = newValue;
-
- return newValue;
}
finally
{
Monitor.Exit(_syncRoot);
}
-
}
+
///
/// RemoveMessageTag
///
@@ -392,9 +438,26 @@ namespace TIAMWebApp.Shared.Application.Utility
{
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);
+ }
+ }
///
///
///
@@ -439,9 +502,27 @@ namespace TIAMWebApp.Shared.Application.Utility
{
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);
+ }
+ }
///
///
///
@@ -518,7 +599,6 @@ namespace TIAMWebApp.Shared.Application.Utility
{
try
{
- //throw new Exception();
await SaveTrackingItemUnsafe(trackingItem);
}
catch(Exception ex)
@@ -533,26 +613,49 @@ namespace TIAMWebApp.Shared.Application.Utility
{
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)
+ public async Task SaveItem(Guid id)
{
Monitor.Enter(_syncRoot);
try
{
- T? resultItem = null;
+ 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
@@ -561,17 +664,18 @@ namespace TIAMWebApp.Shared.Application.Utility
}
}
- public async Task SaveItem(Guid id, TrackingState trackingState)
+ public async Task SaveItem(Guid id, TrackingState trackingState)
{
Monitor.Enter(_syncRoot);
try
{
- T? resultItem = null;
+ 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
@@ -580,31 +684,68 @@ namespace TIAMWebApp.Shared.Application.Utility
}
}
- public Task SaveItem(T item, TrackingState trackingState) => SaveItemUnsafe(item, trackingState);
+ public Task SaveItem(T item, TrackingState trackingState) => SaveItemUnsafe(item, trackingState);
- protected Task SaveTrackingItemUnsafe(TrackingItem trackingItem)
+ protected Task SaveTrackingItemUnsafe(TrackingItem trackingItem)
=> SaveItemUnsafe(trackingItem.CurrentValue, trackingItem.TrackingState);
- protected async Task SaveItemUnsafe(T item, TrackingState 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) return null; //throw new ArgumentException($"messageTag == SignalRTags.None");
+ if (messageTag == SignalRTags.None) throw new ArgumentException($"SaveItemUnsafe; messageTag == SignalRTags.None");
var result = await SignalRClient.PostDataAsync(messageTag, item);
- if (result == null) return null; //throw new NullReferenceException($"result == null");
+ if (result == null) throw new NullReferenceException($"SaveItemUnsafe; result == null");
- if (TryGetTrackingItem(item.Id, out var trackingItem))
- TrackingItems.Remove(trackingItem);
-
- if (TryGetIndex(result.Id, out var index))
- InnerList[index] = result;
-
- var eventArgs = new ItemChangedEventArgs(result, trackingState);
- if (OnDataSourceItemChanged != null) await OnDataSourceItemChanged.Invoke(eventArgs);
+ 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))