From d8cf307693d8d93aa61bae6cce929006e7bc31b4 Mon Sep 17 00:00:00 2001 From: jmayer913 <72579603+jmayer913@users.noreply.github.com> Date: Fri, 31 Oct 2025 15:51:32 -0400 Subject: [PATCH 01/20] Updated Version, .NET, Packages --- .../JMayer.Example.WebAssemblyBlazor.Shared.csproj | 4 ++-- .../JMayer.Example.WebAssemblyBlazor.Client.csproj | 8 ++++---- .../JMayer.Example.WebAssemblyBlazor.csproj | 10 +++++----- TestProject/TestProject.csproj | 14 +++++++------- 4 files changed, 18 insertions(+), 18 deletions(-) diff --git a/JMayer.Example.WebAssemblyBlazor.Shared/JMayer.Example.WebAssemblyBlazor.Shared.csproj b/JMayer.Example.WebAssemblyBlazor.Shared/JMayer.Example.WebAssemblyBlazor.Shared.csproj index c5a87b7..a60af49 100644 --- a/JMayer.Example.WebAssemblyBlazor.Shared/JMayer.Example.WebAssemblyBlazor.Shared.csproj +++ b/JMayer.Example.WebAssemblyBlazor.Shared/JMayer.Example.WebAssemblyBlazor.Shared.csproj @@ -1,10 +1,10 @@  - net8.0 + net9.0 enable enable - 3.2.0 + 9.0.0 diff --git a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/JMayer.Example.WebAssemblyBlazor.Client.csproj b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/JMayer.Example.WebAssemblyBlazor.Client.csproj index 9894451..7ea057c 100644 --- a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/JMayer.Example.WebAssemblyBlazor.Client.csproj +++ b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/JMayer.Example.WebAssemblyBlazor.Client.csproj @@ -1,17 +1,17 @@  - net8.0 + net9.0 enable enable true Default - 3.2.0 + 9.0.0 - - + + diff --git a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.csproj b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.csproj index 3ca5411..a26a993 100644 --- a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.csproj +++ b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.csproj @@ -1,19 +1,19 @@  - net8.0 + net9.0 enable enable - 3.2.0 + 9.0.0 - - - + + + diff --git a/TestProject/TestProject.csproj b/TestProject/TestProject.csproj index 65d54f2..42e0d25 100644 --- a/TestProject/TestProject.csproj +++ b/TestProject/TestProject.csproj @@ -1,7 +1,7 @@ - net8.0 + net9.0 enable enable @@ -12,13 +12,13 @@ - - - - - + + + + + - + runtime; build; native; contentfiles; analyzers; buildtransitive all From 0a407ccc0f10ef2ee76eed6569a970465f441b74 Mon Sep 17 00:00:00 2001 From: jmayer913 <72579603+jmayer913@users.noreply.github.com> Date: Sat, 1 Nov 2025 11:06:20 -0400 Subject: [PATCH 02/20] Changes based on JMayer library changes --- .../Data/Assets/Asset.cs | 13 ++-- .../Data/Assets/StorageLocation.cs | 14 ++--- .../Data/Parts/Part.cs | 8 ++- .../Data/Parts/Stock.cs | 4 +- .../Database/BHSExampleBuilder.cs | 5 -- .../DataLayer/Assets/AssetDataLayer.cs | 62 ++++++++++--------- .../DataLayer/Assets/IAssetDataLayer.cs | 2 +- .../Assets/IStorageLocationDataLayer.cs | 2 +- .../Assets/StorageLocationDataLayer.cs | 13 ++-- .../DataLayer/Parts/IPartDataLayer.cs | 2 +- .../DataLayer/Parts/IStockDataLayer.cs | 2 +- .../Database/DataLayer/Parts/PartDataLayer.cs | 6 +- .../DataLayer/Parts/StockDataLayer.cs | 15 ++--- .../HTTP/DataLayer/Assets/AssetDataLayer.cs | 4 +- .../HTTP/DataLayer/Assets/IAssetDataLayer.cs | 2 +- .../Assets/IStorageLocationDataLayer.cs | 2 +- .../Assets/StorageLocationDataLayer.cs | 2 +- .../HTTP/DataLayer/Parts/IPartDataLayer.cs | 2 +- .../HTTP/DataLayer/Parts/IStockDataLayer.cs | 2 +- .../HTTP/DataLayer/Parts/PartDataLayer.cs | 4 +- .../HTTP/DataLayer/Parts/StockDataLayer.cs | 2 +- ...er.Example.WebAssemblyBlazor.Shared.csproj | 2 +- JMayer.Example.WebAssemblyBlazor.sln | 12 ++++ .../Components/Base/CardDialogBase.cs | 13 ++-- .../Components/Base/EditableCardBase.cs | 13 ++-- .../Components/Base/InspectorBase.cs | 6 +- .../Components/Base/NewDialogBase.cs | 11 ++-- .../Components/Base/OverviewCardBase.cs | 15 ++--- .../Components/Base/SearchBase.cs | 10 +-- .../Components/DataObjectTimestamp.razor | 2 +- .../Components/ServerSideValidation.cs | 14 +++-- .../Extensions/StringExtension.cs | 9 ++- .../Pages/Assets/Cards/OverviewCardBase.cs | 20 +++--- .../Assets/Dialogs/NewAssetDialogBase.cs | 18 +++--- .../Pages/Parts/Cards/OverviewCardBase.cs | 2 + .../Pages/Parts/Dialogs/NewPartDialogBase.cs | 2 + .../Pages/Parts/Dialogs/StockDialogBase.cs | 8 ++- .../Controllers/Assets/AssetController.cs | 9 +-- .../Assets/StorageLocationController.cs | 4 +- .../Controllers/Parts/PartController.cs | 9 +-- .../Controllers/Parts/StockController.cs | 4 +- .../JMayer.Example.WebAssemblyBlazor.csproj | 2 +- TestProject/DataHelper.cs | 15 ++--- .../Test/WebRequest/Assets/AssetUnitTest.cs | 14 ++--- .../Assets/StorageLocationUnitTest.cs | 28 ++++----- .../Test/WebRequest/Parts/PartUnitTest.cs | 15 +++-- .../Test/WebRequest/Parts/StockUnitTest.cs | 29 ++++----- TestProject/TestProject.csproj | 2 +- 48 files changed, 239 insertions(+), 217 deletions(-) diff --git a/JMayer.Example.WebAssemblyBlazor.Shared/Data/Assets/Asset.cs b/JMayer.Example.WebAssemblyBlazor.Shared/Data/Assets/Asset.cs index e46a56f..888bd06 100644 --- a/JMayer.Example.WebAssemblyBlazor.Shared/Data/Assets/Asset.cs +++ b/JMayer.Example.WebAssemblyBlazor.Shared/Data/Assets/Asset.cs @@ -1,11 +1,12 @@ using JMayer.Data.Data; +using System.ComponentModel.DataAnnotations; namespace JMayer.Example.WebAssemblyBlazor.Shared.Data.Assets; /// /// The class represents an asset (equipment) that needs to be monitored and work orders can be preformed on it. /// -public class Asset : UserEditableDataObject +public class Asset : DataObject { /// /// The property gets/sets the common category for the asset. @@ -38,16 +39,18 @@ public class Asset : UserEditableDataObject /// /// This is only used by the backend when updating the parent path. /// - internal string MeAsParentPath - { - get => ParentID == null ? Name : $"{ParentPath}/{Name}"; - } + internal string MeAsParentPath => ParentID is null ? (Name ?? string.Empty) : $"{ParentPath}/{Name ?? string.Empty}"; /// /// The property gets/sets the model for the asset. /// public string? Model { get; set; } + /// + /// Overridden to add Required data annotation. + [Required] + public override string? Name { get => base.Name; set => base.Name = value; } + /// /// The property gets/sets id for the parent of this asset. /// diff --git a/JMayer.Example.WebAssemblyBlazor.Shared/Data/Assets/StorageLocation.cs b/JMayer.Example.WebAssemblyBlazor.Shared/Data/Assets/StorageLocation.cs index ce73e3d..9250b66 100644 --- a/JMayer.Example.WebAssemblyBlazor.Shared/Data/Assets/StorageLocation.cs +++ b/JMayer.Example.WebAssemblyBlazor.Shared/Data/Assets/StorageLocation.cs @@ -3,21 +3,21 @@ namespace JMayer.Example.WebAssemblyBlazor.Shared.Data.Assets; +#warning I wonder if I should make the locations nullable since no value can be set. +#warning I should use Name instead of FriendlyName; maybe I can override Name only have it be get or hide the set with the access level. + /// /// The class represents a storage location for an area asset. /// /// -/// The OwnerId in the SubUserEditableDataObject will represent an asset. +/// The OwnerId in the SubDataObject will represent an asset. /// -public class StorageLocation : SubUserEditableDataObject +public class StorageLocation : SubDataObject { /// /// The property gets/sets the friendly name (locations concatenated). /// - public string FriendlyName - { - get => $"{LocationA}{(!string.IsNullOrWhiteSpace(LocationB) ? $" {LocationB}" : string.Empty)}{(!string.IsNullOrWhiteSpace(LocationC) ? $" {LocationC}" : string.Empty)}"; - } + public string FriendlyName => $"{LocationA}{(string.IsNullOrWhiteSpace(LocationB) is false ? $" {LocationB}" : string.Empty)}{(string.IsNullOrWhiteSpace(LocationC) is false ? $" {LocationC}" : string.Empty)}"; /// /// The property gets/sets the name of the A location for the storage location. @@ -46,7 +46,7 @@ public override void MapProperties(DataObject dataObject) { base.MapProperties(dataObject); - if (dataObject is StorageLocation storageLocation) + if (dataObject is StorageLocation storageLocation) { LocationA = storageLocation.LocationA; LocationB = storageLocation.LocationB; diff --git a/JMayer.Example.WebAssemblyBlazor.Shared/Data/Parts/Part.cs b/JMayer.Example.WebAssemblyBlazor.Shared/Data/Parts/Part.cs index 7d482b0..8ea25cb 100644 --- a/JMayer.Example.WebAssemblyBlazor.Shared/Data/Parts/Part.cs +++ b/JMayer.Example.WebAssemblyBlazor.Shared/Data/Parts/Part.cs @@ -1,11 +1,12 @@ using JMayer.Data.Data; +using System.ComponentModel.DataAnnotations; namespace JMayer.Example.WebAssemblyBlazor.Shared.Data.Parts; /// /// The class represents a part to be used for repairing an asset. /// -public class Part : UserEditableDataObject +public class Part : DataObject { /// /// The property gets/sets the common category for the part. @@ -32,6 +33,11 @@ public class Part : UserEditableDataObject /// public string? Model { get; set; } + /// + /// Overridden to add Required data annotation. + [Required] + public override string? Name { get => base.Name; set => base.Name = value; } + /// /// The property gets/sets is no longer procedured by the manfacturer. /// diff --git a/JMayer.Example.WebAssemblyBlazor.Shared/Data/Parts/Stock.cs b/JMayer.Example.WebAssemblyBlazor.Shared/Data/Parts/Stock.cs index dec2866..ccb0f14 100644 --- a/JMayer.Example.WebAssemblyBlazor.Shared/Data/Parts/Stock.cs +++ b/JMayer.Example.WebAssemblyBlazor.Shared/Data/Parts/Stock.cs @@ -7,9 +7,9 @@ namespace JMayer.Example.WebAssemblyBlazor.Shared.Data.Parts; /// The class represents stock for a part at a particular storage location. /// /// -/// The OwnerId in the SubUserEditableDataObject will represent a part. +/// The OwnerId in the SubDataObject will represent a part. /// -public class Stock : SubUserEditableDataObject +public class Stock : SubDataObject { /// /// The property gets/sets the amount of stock at the location for the part. diff --git a/JMayer.Example.WebAssemblyBlazor.Shared/Database/BHSExampleBuilder.cs b/JMayer.Example.WebAssemblyBlazor.Shared/Database/BHSExampleBuilder.cs index aba1926..b5a9f94 100644 --- a/JMayer.Example.WebAssemblyBlazor.Shared/Database/BHSExampleBuilder.cs +++ b/JMayer.Example.WebAssemblyBlazor.Shared/Database/BHSExampleBuilder.cs @@ -232,7 +232,6 @@ private void BuildStock() _ = StockDataLayer.CreateAsync(new Stock() { Amount = 5 * (index + 1), - Name = "A Name", OwnerInteger64ID = parts[index].Integer64ID, StorageLocationID = storageLocations[index].Integer64ID, StorageLocationName = storageLocations[index].FriendlyName, @@ -261,7 +260,6 @@ private void BuildStorageLocations() LocationC = "S1", OwnerInteger64ID = asset.Integer64ID, }; - storageLocation.Name = storageLocation.FriendlyName; _ = StorageLocationDataLayer.CreateAsync(storageLocation); storageLocation = new StorageLocation() @@ -271,7 +269,6 @@ private void BuildStorageLocations() LocationC = "S2", OwnerInteger64ID = asset.Integer64ID, }; - storageLocation.Name = storageLocation.FriendlyName; _ = StorageLocationDataLayer.CreateAsync(storageLocation); storageLocation = new StorageLocation() @@ -281,7 +278,6 @@ private void BuildStorageLocations() LocationC = "S1", OwnerInteger64ID = asset.Integer64ID, }; - storageLocation.Name = storageLocation.FriendlyName; _ = StorageLocationDataLayer.CreateAsync(storageLocation); storageLocation = new StorageLocation() @@ -291,7 +287,6 @@ private void BuildStorageLocations() LocationC = "S2", OwnerInteger64ID = asset.Integer64ID, }; - storageLocation.Name = storageLocation.FriendlyName; _ = StorageLocationDataLayer.CreateAsync(storageLocation); } } diff --git a/JMayer.Example.WebAssemblyBlazor.Shared/Database/DataLayer/Assets/AssetDataLayer.cs b/JMayer.Example.WebAssemblyBlazor.Shared/Database/DataLayer/Assets/AssetDataLayer.cs index bdfa594..51cccf6 100644 --- a/JMayer.Example.WebAssemblyBlazor.Shared/Database/DataLayer/Assets/AssetDataLayer.cs +++ b/JMayer.Example.WebAssemblyBlazor.Shared/Database/DataLayer/Assets/AssetDataLayer.cs @@ -6,23 +6,24 @@ namespace JMayer.Example.WebAssemblyBlazor.Shared.Database.DataLayer.Assets; /// /// The class manages CRUD interactions with the database for an asset. /// -public class AssetDataLayer : UserEditableDataLayer, IAssetDataLayer +public class AssetDataLayer : StandardCRUDDataLayer, IAssetDataLayer { + /// + /// The default constructor. + /// + public AssetDataLayer() => IsUniqueNameRequired = true; + /// /// /// This is overriden so the parent path can be set before creation. /// public override async Task CreateAsync(Asset dataObject, CancellationToken cancellationToken = default) { - //Set the parent path is a parent exists. - if (dataObject.ParentID != null) + //Set the parent path if a parent exists. + if (dataObject.ParentID is not null) { Asset? parent = await GetSingleAsync(obj => obj.Integer64ID == dataObject.ParentID, cancellationToken); - - if (parent != null) - { - dataObject.ParentPath = parent.MeAsParentPath; - } + dataObject.ParentPath = parent?.MeAsParentPath; } return await base.CreateAsync(dataObject, cancellationToken); @@ -53,23 +54,24 @@ public override async Task DeleteAsync(Asset dataObject, CancellationToken cance /// A list of children assets or an empty list is none exists. private async Task> GetChildrenAsync(Asset parent, CancellationToken cancellationToken) { - List returnList = []; List children = await GetAllAsync(obj => obj.ParentID == parent.Integer64ID, cancellationToken: cancellationToken); - if (children.Count > 0) + if (children.Count is 0) { - returnList = [.. children]; + return []; + } + + List returnList = [.. children]; - foreach (Asset child in children) + foreach (Asset child in children) + { + if (child.ParentID is not null) { - if (child.ParentID != null) - { - List temp = await GetChildrenAsync(child, cancellationToken); + List temp = await GetChildrenAsync(child, cancellationToken); - if (temp.Count > 0) - { - returnList.AddRange(temp); - } + if (temp.Count > 0) + { + returnList.AddRange(temp); } } } @@ -87,9 +89,9 @@ public override async Task UpdateAsync(Asset dataObject, CancellationToke Asset? originalDataObject = await GetSingleAsync(obj => obj.Integer64ID == dataObject.Integer64ID, cancellationToken); //Update the parent path if the parent has changed. - if (originalDataObject != null && originalDataObject.ParentID != dataObject.ParentID) + if (originalDataObject is not null && originalDataObject.ParentID != dataObject.ParentID) { - if (dataObject.ParentID == null) + if (dataObject.ParentID is null) { dataObject.ParentPath = null; } @@ -103,7 +105,7 @@ public override async Task UpdateAsync(Asset dataObject, CancellationToke dataObject = await base.UpdateAsync(dataObject, cancellationToken); //All child under the asset must update their parent's path if the name has changed or the parent has changed. - if (originalDataObject != null && (originalDataObject.Name != dataObject.Name || originalDataObject.ParentID != dataObject.ParentID)) + if (originalDataObject is not null && (originalDataObject.Name != dataObject.Name || originalDataObject.ParentID != dataObject.ParentID)) { await UpdateParentPathAsync(dataObject.MeAsParentPath, dataObject, cancellationToken); } @@ -122,15 +124,17 @@ private async Task UpdateParentPathAsync(string? parentPath, Asset parentAsset, { List children = await GetAllAsync(obj => obj.ParentID == parentAsset.Integer64ID, cancellationToken: cancellationToken); - if (children.Count > 0) + if (children.Count is 0) { - foreach (Asset childAsset in children) - { - childAsset.ParentPath = parentPath; - await UpdateParentPathAsync(childAsset.MeAsParentPath, childAsset, cancellationToken); - } + return; + } - _ = await UpdateAsync(children, cancellationToken); + foreach (Asset childAsset in children) + { + childAsset.ParentPath = parentPath; + await UpdateParentPathAsync(childAsset.MeAsParentPath, childAsset, cancellationToken); } + + _ = await UpdateAsync(children, cancellationToken); } } diff --git a/JMayer.Example.WebAssemblyBlazor.Shared/Database/DataLayer/Assets/IAssetDataLayer.cs b/JMayer.Example.WebAssemblyBlazor.Shared/Database/DataLayer/Assets/IAssetDataLayer.cs index 3a64f8b..3b837a0 100644 --- a/JMayer.Example.WebAssemblyBlazor.Shared/Database/DataLayer/Assets/IAssetDataLayer.cs +++ b/JMayer.Example.WebAssemblyBlazor.Shared/Database/DataLayer/Assets/IAssetDataLayer.cs @@ -6,6 +6,6 @@ namespace JMayer.Example.WebAssemblyBlazor.Shared.Database.DataLayer.Assets; /// /// The interface for interacting with an asset collection in a database using CRUD operations. /// -public interface IAssetDataLayer : IUserEditableDataLayer +public interface IAssetDataLayer : IStandardCRUDDataLayer { } diff --git a/JMayer.Example.WebAssemblyBlazor.Shared/Database/DataLayer/Assets/IStorageLocationDataLayer.cs b/JMayer.Example.WebAssemblyBlazor.Shared/Database/DataLayer/Assets/IStorageLocationDataLayer.cs index f7549e0..96d1330 100644 --- a/JMayer.Example.WebAssemblyBlazor.Shared/Database/DataLayer/Assets/IStorageLocationDataLayer.cs +++ b/JMayer.Example.WebAssemblyBlazor.Shared/Database/DataLayer/Assets/IStorageLocationDataLayer.cs @@ -6,6 +6,6 @@ namespace JMayer.Example.WebAssemblyBlazor.Shared.Database.DataLayer.Assets; /// /// The interface for interacting with a storage location collection in a database using CRUD operations. /// -public interface IStorageLocationDataLayer : IUserEditableDataLayer +public interface IStorageLocationDataLayer : IStandardSubCRUDDataLayer { } diff --git a/JMayer.Example.WebAssemblyBlazor.Shared/Database/DataLayer/Assets/StorageLocationDataLayer.cs b/JMayer.Example.WebAssemblyBlazor.Shared/Database/DataLayer/Assets/StorageLocationDataLayer.cs index 81f22bb..eec481a 100644 --- a/JMayer.Example.WebAssemblyBlazor.Shared/Database/DataLayer/Assets/StorageLocationDataLayer.cs +++ b/JMayer.Example.WebAssemblyBlazor.Shared/Database/DataLayer/Assets/StorageLocationDataLayer.cs @@ -8,7 +8,7 @@ namespace JMayer.Example.WebAssemblyBlazor.Shared.Database.DataLayer.Assets; /// /// The class manages CRUD interactions with the database for a storage location. /// -public class StorageLocationDataLayer : UserEditableDataLayer, IStorageLocationDataLayer +public class StorageLocationDataLayer : StandardSubCRUDDataLayer, IStorageLocationDataLayer { /// /// The data layer for interacting with assets. @@ -49,21 +49,18 @@ private async void AssetDataLayer_Deleted(object? sender, DeletedEventArgs e) /// /// - /// Overriding and not calling the base because the parent class forces the Name property - /// to be unique but the property is not used. Also, added additional server-side validation - /// unique to the storage location. + /// Overriding to check if the owner asset exists and the storage location doesn't already exist. /// public override async Task> ValidateAsync(StorageLocation dataObject, CancellationToken cancellationToken = default) { - ArgumentNullException.ThrowIfNull(dataObject); - List validationResults = dataObject.Validate(); + List validationResults = await base.ValidateAsync(dataObject, cancellationToken); - if (await _assetDataLayer.ExistAsync(obj => obj.Integer64ID == dataObject.OwnerInteger64ID, cancellationToken) == false) + if (await _assetDataLayer.ExistAsync(obj => obj.Integer64ID == dataObject.OwnerInteger64ID, cancellationToken) is false) { validationResults.Add(new ValidationResult($"The {dataObject.OwnerInteger64ID} asset was not found in the data store.", [nameof(StorageLocation.OwnerInteger64ID)])); } - if (await ExistAsync(obj => obj.Integer64ID != dataObject.Integer64ID && obj.LocationA == dataObject.LocationA && obj.LocationB == dataObject.LocationB && obj.LocationC == dataObject.LocationC, cancellationToken) == true) + if (await ExistAsync(obj => obj.Integer64ID != dataObject.Integer64ID && obj.LocationA == dataObject.LocationA && obj.LocationB == dataObject.LocationB && obj.LocationC == dataObject.LocationC, cancellationToken) is true) { validationResults.Add(new ValidationResult("The location already exists in the data store.", [nameof(StorageLocation.LocationA)])); } diff --git a/JMayer.Example.WebAssemblyBlazor.Shared/Database/DataLayer/Parts/IPartDataLayer.cs b/JMayer.Example.WebAssemblyBlazor.Shared/Database/DataLayer/Parts/IPartDataLayer.cs index cc4e32c..8df0a0b 100644 --- a/JMayer.Example.WebAssemblyBlazor.Shared/Database/DataLayer/Parts/IPartDataLayer.cs +++ b/JMayer.Example.WebAssemblyBlazor.Shared/Database/DataLayer/Parts/IPartDataLayer.cs @@ -6,6 +6,6 @@ namespace JMayer.Example.WebAssemblyBlazor.Shared.Database.DataLayer.Parts; /// /// The interface for interacting with a parts collection in a database using CRUD operations. /// -public interface IPartDataLayer : IUserEditableDataLayer +public interface IPartDataLayer : IStandardCRUDDataLayer { } diff --git a/JMayer.Example.WebAssemblyBlazor.Shared/Database/DataLayer/Parts/IStockDataLayer.cs b/JMayer.Example.WebAssemblyBlazor.Shared/Database/DataLayer/Parts/IStockDataLayer.cs index e830512..948b3ab 100644 --- a/JMayer.Example.WebAssemblyBlazor.Shared/Database/DataLayer/Parts/IStockDataLayer.cs +++ b/JMayer.Example.WebAssemblyBlazor.Shared/Database/DataLayer/Parts/IStockDataLayer.cs @@ -6,6 +6,6 @@ namespace JMayer.Example.WebAssemblyBlazor.Shared.Database.DataLayer.Parts; /// /// The interface for interacting with a part stock collection in a database using CRUD operations. /// -public interface IStockDataLayer : IUserEditableDataLayer +public interface IStockDataLayer : IStandardSubCRUDDataLayer { } diff --git a/JMayer.Example.WebAssemblyBlazor.Shared/Database/DataLayer/Parts/PartDataLayer.cs b/JMayer.Example.WebAssemblyBlazor.Shared/Database/DataLayer/Parts/PartDataLayer.cs index 0d6abe8..22865b0 100644 --- a/JMayer.Example.WebAssemblyBlazor.Shared/Database/DataLayer/Parts/PartDataLayer.cs +++ b/JMayer.Example.WebAssemblyBlazor.Shared/Database/DataLayer/Parts/PartDataLayer.cs @@ -6,6 +6,10 @@ namespace JMayer.Example.WebAssemblyBlazor.Shared.Database.DataLayer.Parts; /// /// The class manages CRUD interactions with the database for a part. /// -public class PartDataLayer : UserEditableDataLayer, IPartDataLayer +public class PartDataLayer : StandardCRUDDataLayer, IPartDataLayer { + /// + /// The default constructor. + /// + public PartDataLayer() => IsUniqueNameRequired = true; } diff --git a/JMayer.Example.WebAssemblyBlazor.Shared/Database/DataLayer/Parts/StockDataLayer.cs b/JMayer.Example.WebAssemblyBlazor.Shared/Database/DataLayer/Parts/StockDataLayer.cs index 847c8b6..7eb11d0 100644 --- a/JMayer.Example.WebAssemblyBlazor.Shared/Database/DataLayer/Parts/StockDataLayer.cs +++ b/JMayer.Example.WebAssemblyBlazor.Shared/Database/DataLayer/Parts/StockDataLayer.cs @@ -9,7 +9,7 @@ namespace JMayer.Example.WebAssemblyBlazor.Shared.Database.DataLayer.Parts; /// /// The class manages CRUD interactions with the database for part stock. /// -public class StockDataLayer : UserEditableDataLayer, IStockDataLayer +public class StockDataLayer : StandardSubCRUDDataLayer, IStockDataLayer { /// /// The data layer for interacting with parts. @@ -112,26 +112,23 @@ private async void StorageLocationDataLayer_Updated(object? sender, JMayer.Data. /// /// - /// Overriding and not calling the base because the parent class forces the Name property - /// to be unique but the property is not used. Also, added additional server-side validation - /// unique to the stock. + /// Overriding to check if the owner part exists, the storage location exists and the stock location doesn't already exist. /// public override async Task> ValidateAsync(Stock dataObject, CancellationToken cancellationToken = default) { - ArgumentNullException.ThrowIfNull(dataObject); - List validationResults = dataObject.Validate(); + List validationResults = await base.ValidateAsync(dataObject, cancellationToken); - if (await _partDataLayer.ExistAsync(obj => obj.Integer64ID == dataObject.OwnerInteger64ID, cancellationToken) == false) + if (await _partDataLayer.ExistAsync(obj => obj.Integer64ID == dataObject.OwnerInteger64ID, cancellationToken) is false) { validationResults.Add(new ValidationResult($"The {dataObject.OwnerInteger64ID} part was not found in the data store.", [nameof(Stock.OwnerInteger64ID)])); } - if (await _storageLocationDataLayer.ExistAsync(obj => obj.Integer64ID == dataObject.StorageLocationID, cancellationToken) == false) + if (await _storageLocationDataLayer.ExistAsync(obj => obj.Integer64ID == dataObject.StorageLocationID, cancellationToken) is false) { validationResults.Add(new ValidationResult($"The {dataObject.StorageLocationID} storage location was not found in the data store.", [nameof(Stock.StorageLocationID)])); } - if (await ExistAsync(obj => obj.Integer64ID != dataObject.Integer64ID && obj.OwnerInteger64ID == dataObject.OwnerInteger64ID && obj.StorageLocationID == dataObject.StorageLocationID, cancellationToken) == true) + if (await ExistAsync(obj => obj.Integer64ID != dataObject.Integer64ID && obj.OwnerInteger64ID == dataObject.OwnerInteger64ID && obj.StorageLocationID == dataObject.StorageLocationID, cancellationToken) is true) { validationResults.Add(new ValidationResult("The stock location already exists in the data store for the part.", [nameof(Stock.StorageLocationID)])); } diff --git a/JMayer.Example.WebAssemblyBlazor.Shared/HTTP/DataLayer/Assets/AssetDataLayer.cs b/JMayer.Example.WebAssemblyBlazor.Shared/HTTP/DataLayer/Assets/AssetDataLayer.cs index 68c9a41..254217a 100644 --- a/JMayer.Example.WebAssemblyBlazor.Shared/HTTP/DataLayer/Assets/AssetDataLayer.cs +++ b/JMayer.Example.WebAssemblyBlazor.Shared/HTTP/DataLayer/Assets/AssetDataLayer.cs @@ -8,7 +8,7 @@ namespace JMayer.Example.WebAssemblyBlazor.Shared.HTTP.DataLayer.Assets; /// /// The class manages CRUD interactions with a remote server for an asset. /// -public class AssetDataLayer : UserEditableDataLayer, IAssetDataLayer +public class AssetDataLayer : StandardCRUDDataLayer, IAssetDataLayer { /// public AssetDataLayer(HttpClient httpClient) : base(httpClient) { } @@ -19,7 +19,7 @@ public AssetDataLayer(HttpClient httpClient) : base(httpClient) { } List? categories = null; HttpResponseMessage httpResponseMessage = await HttpClient.GetAsync($"api/{TypeName}/Category/All", cancellationToken); - if (httpResponseMessage.IsSuccessStatusCode && httpResponseMessage.StatusCode != HttpStatusCode.NoContent) + if (httpResponseMessage.IsSuccessStatusCode && httpResponseMessage.StatusCode is not HttpStatusCode.NoContent) { categories = await httpResponseMessage.Content.ReadFromJsonAsync>(cancellationToken); } diff --git a/JMayer.Example.WebAssemblyBlazor.Shared/HTTP/DataLayer/Assets/IAssetDataLayer.cs b/JMayer.Example.WebAssemblyBlazor.Shared/HTTP/DataLayer/Assets/IAssetDataLayer.cs index 1838ba1..3a18db6 100644 --- a/JMayer.Example.WebAssemblyBlazor.Shared/HTTP/DataLayer/Assets/IAssetDataLayer.cs +++ b/JMayer.Example.WebAssemblyBlazor.Shared/HTTP/DataLayer/Assets/IAssetDataLayer.cs @@ -6,7 +6,7 @@ namespace JMayer.Example.WebAssemblyBlazor.Shared.HTTP.DataLayer.Assets; /// /// The interface for interacting with a remote server using CRUD operations specifically for assets. /// -public interface IAssetDataLayer : IUserEditableDataLayer +public interface IAssetDataLayer : IStandardCRUDDataLayer { /// /// The method returns all the defined categories for the assets. diff --git a/JMayer.Example.WebAssemblyBlazor.Shared/HTTP/DataLayer/Assets/IStorageLocationDataLayer.cs b/JMayer.Example.WebAssemblyBlazor.Shared/HTTP/DataLayer/Assets/IStorageLocationDataLayer.cs index a55f232..44c2da0 100644 --- a/JMayer.Example.WebAssemblyBlazor.Shared/HTTP/DataLayer/Assets/IStorageLocationDataLayer.cs +++ b/JMayer.Example.WebAssemblyBlazor.Shared/HTTP/DataLayer/Assets/IStorageLocationDataLayer.cs @@ -6,6 +6,6 @@ namespace JMayer.Example.WebAssemblyBlazor.Shared.HTTP.DataLayer.Assets; /// /// The interface for interacting with a remote server using CRUD operations specifically for storage locations. /// -public interface IStorageLocationDataLayer : ISubUserEditableDataLayer +public interface IStorageLocationDataLayer : IStandardSubCRUDDataLayer { } diff --git a/JMayer.Example.WebAssemblyBlazor.Shared/HTTP/DataLayer/Assets/StorageLocationDataLayer.cs b/JMayer.Example.WebAssemblyBlazor.Shared/HTTP/DataLayer/Assets/StorageLocationDataLayer.cs index f3c2071..1f4b62f 100644 --- a/JMayer.Example.WebAssemblyBlazor.Shared/HTTP/DataLayer/Assets/StorageLocationDataLayer.cs +++ b/JMayer.Example.WebAssemblyBlazor.Shared/HTTP/DataLayer/Assets/StorageLocationDataLayer.cs @@ -6,7 +6,7 @@ namespace JMayer.Example.WebAssemblyBlazor.Shared.HTTP.DataLayer.Assets; /// /// The class manages CRUD interactions with a remote server for a storage location. /// -public class StorageLocationDataLayer : SubUserEditableDataLayer, IStorageLocationDataLayer +public class StorageLocationDataLayer : StandardSubCRUDDataLayer, IStorageLocationDataLayer { /// public StorageLocationDataLayer(HttpClient httpClient) : base(httpClient) { } diff --git a/JMayer.Example.WebAssemblyBlazor.Shared/HTTP/DataLayer/Parts/IPartDataLayer.cs b/JMayer.Example.WebAssemblyBlazor.Shared/HTTP/DataLayer/Parts/IPartDataLayer.cs index aa77405..517dc62 100644 --- a/JMayer.Example.WebAssemblyBlazor.Shared/HTTP/DataLayer/Parts/IPartDataLayer.cs +++ b/JMayer.Example.WebAssemblyBlazor.Shared/HTTP/DataLayer/Parts/IPartDataLayer.cs @@ -6,7 +6,7 @@ namespace JMayer.Example.WebAssemblyBlazor.Shared.HTTP.DataLayer.Parts; /// /// The interface for interacting with a remote server using CRUD operations specifically for parts. /// -public interface IPartDataLayer : IUserEditableDataLayer +public interface IPartDataLayer : IStandardCRUDDataLayer { /// /// The method returns all the defined categories for the parts. diff --git a/JMayer.Example.WebAssemblyBlazor.Shared/HTTP/DataLayer/Parts/IStockDataLayer.cs b/JMayer.Example.WebAssemblyBlazor.Shared/HTTP/DataLayer/Parts/IStockDataLayer.cs index d37804d..ed890a1 100644 --- a/JMayer.Example.WebAssemblyBlazor.Shared/HTTP/DataLayer/Parts/IStockDataLayer.cs +++ b/JMayer.Example.WebAssemblyBlazor.Shared/HTTP/DataLayer/Parts/IStockDataLayer.cs @@ -6,6 +6,6 @@ namespace JMayer.Example.WebAssemblyBlazor.Shared.HTTP.DataLayer.Parts; /// /// The interface for interacting with a remote server using CRUD operations specifically for part stock. /// -public interface IStockDataLayer : ISubUserEditableDataLayer +public interface IStockDataLayer : IStandardSubCRUDDataLayer { } diff --git a/JMayer.Example.WebAssemblyBlazor.Shared/HTTP/DataLayer/Parts/PartDataLayer.cs b/JMayer.Example.WebAssemblyBlazor.Shared/HTTP/DataLayer/Parts/PartDataLayer.cs index 91e1641..c6cdb15 100644 --- a/JMayer.Example.WebAssemblyBlazor.Shared/HTTP/DataLayer/Parts/PartDataLayer.cs +++ b/JMayer.Example.WebAssemblyBlazor.Shared/HTTP/DataLayer/Parts/PartDataLayer.cs @@ -8,7 +8,7 @@ namespace JMayer.Example.WebAssemblyBlazor.Shared.HTTP.DataLayer.Parts; /// /// The class manages CRUD interactions with a remote server for a part. /// -public class PartDataLayer : UserEditableDataLayer, IPartDataLayer +public class PartDataLayer : StandardCRUDDataLayer, IPartDataLayer { /// public PartDataLayer(HttpClient httpClient) : base(httpClient) { } @@ -19,7 +19,7 @@ public PartDataLayer(HttpClient httpClient) : base(httpClient) { } List? categories = null; HttpResponseMessage httpResponseMessage = await HttpClient.GetAsync($"api/{TypeName}/Category/All", cancellationToken); - if (httpResponseMessage.IsSuccessStatusCode && httpResponseMessage.StatusCode != HttpStatusCode.NoContent) + if (httpResponseMessage.IsSuccessStatusCode && httpResponseMessage.StatusCode is not HttpStatusCode.NoContent) { categories = await httpResponseMessage.Content.ReadFromJsonAsync>(cancellationToken); } diff --git a/JMayer.Example.WebAssemblyBlazor.Shared/HTTP/DataLayer/Parts/StockDataLayer.cs b/JMayer.Example.WebAssemblyBlazor.Shared/HTTP/DataLayer/Parts/StockDataLayer.cs index c5271e4..4c95562 100644 --- a/JMayer.Example.WebAssemblyBlazor.Shared/HTTP/DataLayer/Parts/StockDataLayer.cs +++ b/JMayer.Example.WebAssemblyBlazor.Shared/HTTP/DataLayer/Parts/StockDataLayer.cs @@ -6,7 +6,7 @@ namespace JMayer.Example.WebAssemblyBlazor.Shared.HTTP.DataLayer.Parts; /// /// The class manages CRUD interactions with a remote server for a part stock. /// -public class StockDataLayer : SubUserEditableDataLayer, IStockDataLayer +public class StockDataLayer : StandardSubCRUDDataLayer, IStockDataLayer { /// public StockDataLayer(HttpClient httpClient) : base(httpClient) { } diff --git a/JMayer.Example.WebAssemblyBlazor.Shared/JMayer.Example.WebAssemblyBlazor.Shared.csproj b/JMayer.Example.WebAssemblyBlazor.Shared/JMayer.Example.WebAssemblyBlazor.Shared.csproj index a60af49..736eee1 100644 --- a/JMayer.Example.WebAssemblyBlazor.Shared/JMayer.Example.WebAssemblyBlazor.Shared.csproj +++ b/JMayer.Example.WebAssemblyBlazor.Shared/JMayer.Example.WebAssemblyBlazor.Shared.csproj @@ -8,7 +8,7 @@ - + diff --git a/JMayer.Example.WebAssemblyBlazor.sln b/JMayer.Example.WebAssemblyBlazor.sln index 6e5eddd..2fba71e 100644 --- a/JMayer.Example.WebAssemblyBlazor.sln +++ b/JMayer.Example.WebAssemblyBlazor.sln @@ -11,6 +11,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JMayer.Example.WebAssemblyB EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestProject", "TestProject\TestProject.csproj", "{C0DD761B-7F78-45DF-A25D-6D022212C839}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JMayer.Data", "..\JMayer-Data-Library\JMayer.Data\JMayer.Data.csproj", "{5E2E9979-417E-9AC0-DE5B-ED439D651066}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JMayer.Web.Mvc", "..\JMayer-Web-Mvc-Library\JMayer.Web.Mvc\JMayer.Web.Mvc.csproj", "{185EFF51-282E-8F0A-7CE5-41B2029C51D3}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -33,6 +37,14 @@ Global {C0DD761B-7F78-45DF-A25D-6D022212C839}.Debug|Any CPU.Build.0 = Debug|Any CPU {C0DD761B-7F78-45DF-A25D-6D022212C839}.Release|Any CPU.ActiveCfg = Release|Any CPU {C0DD761B-7F78-45DF-A25D-6D022212C839}.Release|Any CPU.Build.0 = Release|Any CPU + {5E2E9979-417E-9AC0-DE5B-ED439D651066}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5E2E9979-417E-9AC0-DE5B-ED439D651066}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5E2E9979-417E-9AC0-DE5B-ED439D651066}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5E2E9979-417E-9AC0-DE5B-ED439D651066}.Release|Any CPU.Build.0 = Release|Any CPU + {185EFF51-282E-8F0A-7CE5-41B2029C51D3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {185EFF51-282E-8F0A-7CE5-41B2029C51D3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {185EFF51-282E-8F0A-7CE5-41B2029C51D3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {185EFF51-282E-8F0A-7CE5-41B2029C51D3}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Components/Base/CardDialogBase.cs b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Components/Base/CardDialogBase.cs index ac237c2..9b3b3c1 100644 --- a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Components/Base/CardDialogBase.cs +++ b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Components/Base/CardDialogBase.cs @@ -14,8 +14,8 @@ namespace JMayer.Example.WebAssemblyBlazor.Client.Components.Base; /// Must be a UserEditableDataObject. /// Must be a IUserEditableDataLayer. public class CardDialogBase : ComponentBase - where T : SubUserEditableDataObject, new() - where U : ISubUserEditableDataLayer + where T : SubDataObject, new() + where U : IStandardSubCRUDDataLayer { /// /// The property gets/sets the data layer to be used by the dialog. @@ -72,7 +72,7 @@ public class CardDialogBase : ComponentBase protected override void OnParametersSet() { //For new records, set the owner to the value set when the dialog is opened. - if (DataObject.OwnerInteger64ID == 0) + if (DataObject.OwnerInteger64ID is 0) { DataObject.OwnerInteger64ID = OwnerId; } @@ -109,17 +109,18 @@ protected virtual async Task OnSubmitEditFormAsync() { MudDialog.Close(); } - else if (operationResult.ServerSideValidationResult?.Errors.Count > 0) + else if (operationResult.ValidationErrors.Count > 0) { Dictionary> errors = []; - foreach (ServerSideValidationError error in operationResult.ServerSideValidationResult.Errors) + foreach (var errorKeyPairs in operationResult.ValidationErrors) { - errors.Add(error.PropertyName, [error.ErrorMessage]); + errors.Add(errorKeyPairs.Key, [.. errorKeyPairs.Value]); } ServerSideValidation.DisplayErrors(errors); } +#warning I need to decide if the problem details are utilized. else if (operationResult.StatusCode == HttpStatusCode.Conflict) { await DialogService.ShowEditConflictMessageAsync(); diff --git a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Components/Base/EditableCardBase.cs b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Components/Base/EditableCardBase.cs index 3514e2c..e53a58b 100644 --- a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Components/Base/EditableCardBase.cs +++ b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Components/Base/EditableCardBase.cs @@ -13,8 +13,8 @@ namespace JMayer.Example.WebAssemblyBlazor.Client.Components.Base; /// Must be a ISubUserEditableDataLayer. /// Must be a component that's also a dialog. public class EditableCardBase : ComponentBase - where T : SubUserEditableDataObject - where U : ISubUserEditableDataLayer + where T : SubDataObject + where U : IStandardSubCRUDDataLayer where V : ComponentBase { /// @@ -62,7 +62,7 @@ protected virtual async Task> OnDataGridStateChangedAsync(GridState< { PagedList? pagedDataObjects = await DataLayer.GetPageAsync(OwnerID, gridState.ToQueryDefinition()); - if (pagedDataObjects != null) + if (pagedDataObjects is not null) { return new GridData() { @@ -88,7 +88,7 @@ protected virtual async Task OnDeleteButtonClickAsync(T dataObject) { bool? result = await DialogService.ShowConfirmActionMessageAsync(); - if (result == true) + if (result is true) { try { @@ -98,6 +98,7 @@ protected virtual async Task OnDeleteButtonClickAsync(T dataObject) { await MudDataGrid.ReloadServerData(); } +#warning I need to decide if the problem details are utilized. else { await DialogService.ShowErrorMessageAsync("Failed to delete the object because of an error on the server."); @@ -124,7 +125,7 @@ protected virtual async Task OnEditButtonClickAsync(T dataObject) IDialogReference dialogReference = await DialogService.ShowAsync($"Edit the {DataObjectTypeName.SpaceCapitalLetters()}", dialogParameters); DialogResult? dialogResult = await dialogReference.Result; - if (dialogResult?.Canceled == false) + if (dialogResult?.Canceled is false) { await MudDataGrid.ReloadServerData(); } @@ -144,7 +145,7 @@ protected virtual async Task OnNewButtonClickAsync() IDialogReference dialogReference = await DialogService.ShowAsync($"Create a New {DataObjectTypeName.SpaceCapitalLetters()}", dialogParameters); DialogResult? dialogResult = await dialogReference.Result; - if (dialogResult?.Canceled == false) + if (dialogResult?.Canceled is false) { await MudDataGrid.ReloadServerData(); } diff --git a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Components/Base/InspectorBase.cs b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Components/Base/InspectorBase.cs index c1d58ed..c25cce4 100644 --- a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Components/Base/InspectorBase.cs +++ b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Components/Base/InspectorBase.cs @@ -4,14 +4,16 @@ namespace JMayer.Example.WebAssemblyBlazor.Client.Components.Base; +#warning There's no error handling if DataLayer.GetSingleAsync() throws an exception because of network issues. + /// /// The class manages interaction for an inspector. /// /// Must be a UserEditableDataObject. /// Must be a IUserEditableDataLayer. public class InspectorBase : ComponentBase - where T : UserEditableDataObject - where U : IUserEditableDataLayer + where T : DataObject + where U : IStandardCRUDDataLayer { /// /// The property gets/sets the data layer to used by the page. diff --git a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Components/Base/NewDialogBase.cs b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Components/Base/NewDialogBase.cs index 08972dd..25f5406 100644 --- a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Components/Base/NewDialogBase.cs +++ b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Components/Base/NewDialogBase.cs @@ -13,8 +13,8 @@ namespace JMayer.Example.WebAssemblyBlazor.Client.Components.Base; /// Must be a UserEditableDataObject. /// Must be a IUserEditableDataLayer. public class NewDialogBase : ComponentBase - where T : UserEditableDataObject, new() - where U : IUserEditableDataLayer + where T : DataObject, new() + where U : IStandardCRUDDataLayer { /// /// The property gets/sets the data layer to be used by the dialog. @@ -77,17 +77,18 @@ protected virtual async Task OnSubmitEditFormAsync() { MudDialog.Close(); } - else if (operationResult.ServerSideValidationResult?.Errors.Count > 0) + else if (operationResult.ValidationErrors.Count > 0) { Dictionary> errors = []; - foreach (ServerSideValidationError error in operationResult.ServerSideValidationResult.Errors) + foreach (var errorKeyPair in operationResult.ValidationErrors) { - errors.Add(error.PropertyName, [error.ErrorMessage]); + errors.Add(errorKeyPair.Key, [.. errorKeyPair.Value]); } ServerSideValidation.DisplayErrors(errors); } + #warning I need to decide if the problem details are utilized. else { await DialogService.ShowErrorMessageAsync("Failed to create the object because of an error on the server."); diff --git a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Components/Base/OverviewCardBase.cs b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Components/Base/OverviewCardBase.cs index 741b1d1..f87d548 100644 --- a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Components/Base/OverviewCardBase.cs +++ b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Components/Base/OverviewCardBase.cs @@ -14,8 +14,8 @@ namespace JMayer.Example.WebAssemblyBlazor.Client.Components.Base; /// Must be a UserEditableDataObject. /// Must be a IUserEditableDataLayer. public class OverviewCardBase : ComponentBase - where T : UserEditableDataObject, new() - where U : IUserEditableDataLayer + where T : DataObject, new() + where U : IStandardCRUDDataLayer { /// /// The property gets/sets the data layer to used by the page. @@ -90,25 +90,26 @@ protected virtual async Task OnSubmitFormAsync() { OperationResult operationResult = await DataLayer.UpdateAsync(DataObject); - if (operationResult.IsSuccessStatusCode && operationResult.DataObject != null) + if (operationResult.IsSuccessStatusCode && operationResult.DataObject is not null) { Updated = true; DataObject.MapProperties((T)operationResult.DataObject); OriginalDataObject.MapProperties(DataObject); EditContext.MarkAsUnmodified(); } - else if (operationResult.ServerSideValidationResult?.Errors.Count > 0) + else if (operationResult.ValidationErrors.Count > 0) { Dictionary> errors = []; - foreach (ServerSideValidationError error in operationResult.ServerSideValidationResult.Errors) + foreach (var errorKeyPair in operationResult.ValidationErrors) { - errors.Add(error.PropertyName, [error.ErrorMessage]); + errors.Add(errorKeyPair.Key, [.. errorKeyPair.Value]); } ServerSideValidation.DisplayErrors(errors); } - else if (operationResult.StatusCode == HttpStatusCode.Conflict) +#warning I need to decide if the problem details are utilized. + else if (operationResult.StatusCode is HttpStatusCode.Conflict) { await DialogService.ShowEditConflictMessageAsync(); } diff --git a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Components/Base/SearchBase.cs b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Components/Base/SearchBase.cs index 6cf36ed..7bb789f 100644 --- a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Components/Base/SearchBase.cs +++ b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Components/Base/SearchBase.cs @@ -13,8 +13,8 @@ namespace JMayer.Example.WebAssemblyBlazor.Client.Components.Base; /// Must be a IUserEditableDataLayer. /// Must be a component that's also a dialog. public class SearchBase : ComponentBase - where T : UserEditableDataObject - where U : IUserEditableDataLayer + where T : DataObject + where U : IStandardCRUDDataLayer where V : ComponentBase { /// @@ -56,7 +56,7 @@ protected virtual async Task> OnDataGridStateChangedAsync(GridState< { PagedList? pagedDataObjects = await DataLayer.GetPageAsync(gridState.ToQueryDefinition()); - if (pagedDataObjects != null) + if (pagedDataObjects is not null) { return new GridData() { @@ -82,7 +82,7 @@ protected virtual async Task OnDeleteButtonClickAsync(T dataObject) { bool? result = await DialogService.ShowConfirmActionMessageAsync(); - if (result == true) + if (result is true) { try { @@ -122,7 +122,7 @@ protected virtual async Task OnNewButtonClickAsync() IDialogReference dialogReference = await DialogService.ShowAsync($"Create a New {DataObjectTypeName.SpaceCapitalLetters()}"); DialogResult? dialogResult = await dialogReference.Result; - if (dialogResult?.Canceled == false) + if (dialogResult?.Canceled is false) { await MudDataGrid.ReloadServerData(); } diff --git a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Components/DataObjectTimestamp.razor b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Components/DataObjectTimestamp.razor index 591c598..6c3c908 100644 --- a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Components/DataObjectTimestamp.razor +++ b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Components/DataObjectTimestamp.razor @@ -1,4 +1,4 @@ -@typeparam T where T : UserEditableDataObject +@typeparam T where T : DataObject @implements IDisposable @if (Updated) diff --git a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Components/ServerSideValidation.cs b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Components/ServerSideValidation.cs index 6701c8a..fe62767 100644 --- a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Components/ServerSideValidation.cs +++ b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Components/ServerSideValidation.cs @@ -25,15 +25,17 @@ public class ServerSideValidation : ComponentBase /// The errors to display. public void DisplayErrors(Dictionary> errors) { - if (_store != null) + if (_store is null) { - foreach (var error in errors) - { - _store.Add(EditContext.Field(error.Key), error.Value); - } + return; + } - EditContext.NotifyValidationStateChanged(); + foreach (var error in errors) + { + _store.Add(EditContext.Field(error.Key), error.Value); } + + EditContext.NotifyValidationStateChanged(); } /// diff --git a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Extensions/StringExtension.cs b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Extensions/StringExtension.cs index 8efe686..89e1521 100644 --- a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Extensions/StringExtension.cs +++ b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Extensions/StringExtension.cs @@ -1,4 +1,6 @@ -namespace JMayer.Example.WebAssemblyBlazor.Client.Extensions; +using System.Text.RegularExpressions; + +namespace JMayer.Example.WebAssemblyBlazor.Client.Extensions; /// /// The static class contains extension methods for the string class. @@ -10,8 +12,5 @@ public static class StringExtension /// /// The string to space. /// A string. - public static string SpaceCapitalLetters(this string value) - { - return string.Concat(value.Select(c => char.IsUpper(c) ? $" {c}" : c.ToString())).TrimStart(); - } + public static string SpaceCapitalLetters(this string value) => Regex.Replace(value, "([A-Z])", " $1").Trim(); } diff --git a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Pages/Assets/Cards/OverviewCardBase.cs b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Pages/Assets/Cards/OverviewCardBase.cs index 69d8283..59b8387 100644 --- a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Pages/Assets/Cards/OverviewCardBase.cs +++ b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Pages/Assets/Cards/OverviewCardBase.cs @@ -15,14 +15,14 @@ public class OverviewCardBase : Components.Base.OverviewCardBase - /// The property gets/sets the assets to choose for a parent. + /// The property gets/sets the categories for the parts. /// - protected List Assets { get; set; } = []; + protected List Categories { get; set; } = []; /// - /// The property gets/sets the categories for the parts. + /// The property gets/sets the assets to choose for a parent. /// - protected List Categories { get; set; } = []; + protected List ParentAssets { get; set; } = []; /// /// The property gets/sets the parent asset which the user selected. @@ -44,19 +44,19 @@ protected ListView? SelectedAssetParent /// protected override async Task OnParametersSetAsync() { - Assets = await DataLayer.GetAllListViewAsync() ?? []; + ParentAssets = await DataLayer.GetAllListViewAsync() ?? []; Categories = await DataLayer.GetCategoriesAsync() ?? []; - if (DataObject.ParentID != null) + if (DataObject.ParentID is not null) { Asset? parent = await DataLayer.GetSingleAsync(DataObject.ParentID ?? 0); - if (parent != null) + if (parent is not null) { SelectedAssetParent = new ListView() { Integer64ID = parent.Integer64ID, - Name = parent.Name, + Name = parent.Name ?? string.Empty, }; } } @@ -74,11 +74,11 @@ protected async Task> OnAssetParentAutoCompleteSearchAsync { if (string.IsNullOrWhiteSpace(value)) { - return await Task.FromResult(Assets); + return await Task.FromResult(ParentAssets); } else { - return await Task.FromResult(Assets.Where(obj => obj.Name.Contains(value))); + return await Task.FromResult(ParentAssets.Where(obj => obj.Name.Contains(value))); } } diff --git a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Pages/Assets/Dialogs/NewAssetDialogBase.cs b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Pages/Assets/Dialogs/NewAssetDialogBase.cs index b51d647..d65a1ff 100644 --- a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Pages/Assets/Dialogs/NewAssetDialogBase.cs +++ b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Pages/Assets/Dialogs/NewAssetDialogBase.cs @@ -5,6 +5,8 @@ namespace JMayer.Example.WebAssemblyBlazor.Client.Pages.Assets.Dialogs; +#warning There's no error handling if DataLayer.GetAllListViewAsync() or DataLayer.GetCategoriesAsync() throws an exception because of network issues. + /// /// The class manages user interactions with the NewAssetDialog.razor dialog. /// @@ -16,15 +18,15 @@ public class NewAssetDialogBase : NewDialogBase private ListView? _selectedAssetParent; /// - /// The property gets/sets the assets to choose for a parent. + /// The property gets/sets the categories for the parts. /// - protected List Assets { get; set; } = []; + protected List Categories { get; set; } = []; /// - /// The property gets/sets the categories for the parts. + /// The property gets/sets the assets to choose for a parent. /// - protected List Categories { get; set; } = []; - + protected List ParentAssets { get; set; } = []; + /// /// The property gets/sets the parent asset which the user selected. /// @@ -45,7 +47,7 @@ protected ListView? SelectedAssetParent /// A Task object for the async. protected override async Task OnParametersSetAsync() { - Assets = await DataLayer.GetAllListViewAsync() ?? []; + ParentAssets = await DataLayer.GetAllListViewAsync() ?? []; Categories = await DataLayer.GetCategoriesAsync() ?? []; await base.OnParametersSetAsync(); } @@ -60,11 +62,11 @@ protected async Task> OnAssetParentAutoCompleteSearchAsync { if (string.IsNullOrWhiteSpace(value)) { - return await Task.FromResult(Assets); + return await Task.FromResult(ParentAssets); } else { - return await Task.FromResult(Assets.Where(obj => obj.Name.Contains(value))); + return await Task.FromResult(ParentAssets.Where(obj => obj.Name.Contains(value))); } } diff --git a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Pages/Parts/Cards/OverviewCardBase.cs b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Pages/Parts/Cards/OverviewCardBase.cs index fab8782..0817295 100644 --- a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Pages/Parts/Cards/OverviewCardBase.cs +++ b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Pages/Parts/Cards/OverviewCardBase.cs @@ -3,6 +3,8 @@ namespace JMayer.Example.WebAssemblyBlazor.Client.Pages.Parts.Cards; +#warning There's no error handling if DataLayer.GetCategoriesAsync() throws an exception because of network issues. + /// /// The class manages user interactions with the OverviewCard.razor component. /// diff --git a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Pages/Parts/Dialogs/NewPartDialogBase.cs b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Pages/Parts/Dialogs/NewPartDialogBase.cs index 50c4a96..2b1f313 100644 --- a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Pages/Parts/Dialogs/NewPartDialogBase.cs +++ b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Pages/Parts/Dialogs/NewPartDialogBase.cs @@ -4,6 +4,8 @@ namespace JMayer.Example.WebAssemblyBlazor.Client.Pages.Parts.Dialogs; +#warning There's no error handling if DataLayer.GetCategoriesAsync() throws an exception because of network issues. + /// /// The class manages user interactions with the NewPartDialog.razor dialog. /// diff --git a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Pages/Parts/Dialogs/StockDialogBase.cs b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Pages/Parts/Dialogs/StockDialogBase.cs index 6a8b885..69db1fe 100644 --- a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Pages/Parts/Dialogs/StockDialogBase.cs +++ b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Pages/Parts/Dialogs/StockDialogBase.cs @@ -8,6 +8,8 @@ namespace JMayer.Example.WebAssemblyBlazor.Client.Pages.Parts.Dialogs; +#warning There's no error handling if DataLayer.GetAllListViewAsync() throws an exception because of network issues. + /// /// The class manages user interactions with the StockDialog.razor dialog. /// @@ -65,16 +67,16 @@ protected override async Task OnParametersSetAsync() { StorageLocations = await StorageLocationDataLayer.GetAllListViewAsync() ?? []; - if (!IsNewRecord) + if (IsNewRecord is false) { StorageLocation? storageLocation = await StorageLocationDataLayer.GetSingleAsync(DataObject.StorageLocationID); - if (storageLocation != null) + if (storageLocation is not null) { SelectedStorageLocation = new ListView() { Integer64ID = storageLocation.Integer64ID, - Name = storageLocation.Name, + Name = storageLocation.Name ?? string.Empty, }; } } diff --git a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor/Controllers/Assets/AssetController.cs b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor/Controllers/Assets/AssetController.cs index f96fbbe..b31eabe 100644 --- a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor/Controllers/Assets/AssetController.cs +++ b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor/Controllers/Assets/AssetController.cs @@ -1,6 +1,7 @@ using JMayer.Example.WebAssemblyBlazor.Shared.Data.Assets; using JMayer.Example.WebAssemblyBlazor.Shared.Database.DataLayer.Assets; -using JMayer.Web.Mvc.Controller; +using JMayer.Web.Mvc.Controller.Api; +using JMayer.Web.Mvc.Extension; using Microsoft.AspNetCore.Mvc; namespace JMayer.Example.WebAssemblyBlazor.Controllers.Assets; @@ -10,7 +11,7 @@ namespace JMayer.Example.WebAssemblyBlazor.Controllers.Assets; /// [Route("api/[controller]")] [ApiController] -public class AssetController : UserEditableController +public class AssetController : StandardCRUDController { /// public AssetController(IAssetDataLayer dataLayer, ILogger logger) : base(dataLayer, logger) { } @@ -30,8 +31,8 @@ public async Task GetCategoriesAsync() } catch (Exception ex) { - Logger.LogError(ex, "Failed to return the asset categories."); - return Problem(); + Logger.LogError(ex, "Failed to return the {Type} categories.", DataObjectTypeName); + return Problem(title: $"{DataObjectTypeName} Get Categories Error", detail: $"Failed to return the {DataObjectTypeName.SpaceCapitalLetters()} categories records because of an error on the server."); } } } diff --git a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor/Controllers/Assets/StorageLocationController.cs b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor/Controllers/Assets/StorageLocationController.cs index 6b93076..b55008e 100644 --- a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor/Controllers/Assets/StorageLocationController.cs +++ b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor/Controllers/Assets/StorageLocationController.cs @@ -1,6 +1,6 @@ using JMayer.Example.WebAssemblyBlazor.Shared.Data.Assets; using JMayer.Example.WebAssemblyBlazor.Shared.Database.DataLayer.Assets; -using JMayer.Web.Mvc.Controller; +using JMayer.Web.Mvc.Controller.Api; using Microsoft.AspNetCore.Mvc; namespace JMayer.Example.WebAssemblyBlazor.Controllers.Assets; @@ -10,7 +10,7 @@ namespace JMayer.Example.WebAssemblyBlazor.Controllers.Assets; /// [Route("api/[controller]")] [ApiController] -public class StorageLocationController : SubUserEditableController +public class StorageLocationController : StandardSubCRUDController { /// public StorageLocationController(IStorageLocationDataLayer dataLayer, ILogger logger) : base(dataLayer, logger) { } diff --git a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor/Controllers/Parts/PartController.cs b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor/Controllers/Parts/PartController.cs index b722ab9..e1efa09 100644 --- a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor/Controllers/Parts/PartController.cs +++ b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor/Controllers/Parts/PartController.cs @@ -1,6 +1,7 @@ using JMayer.Example.WebAssemblyBlazor.Shared.Data.Parts; using JMayer.Example.WebAssemblyBlazor.Shared.Database.DataLayer.Parts; -using JMayer.Web.Mvc.Controller; +using JMayer.Web.Mvc.Controller.Api; +using JMayer.Web.Mvc.Extension; using Microsoft.AspNetCore.Mvc; namespace JMayer.Example.WebAssemblyBlazor.Controllers.Parts; @@ -10,7 +11,7 @@ namespace JMayer.Example.WebAssemblyBlazor.Controllers.Parts; /// [Route("api/[controller]")] [ApiController] -public class PartController : UserEditableController +public class PartController : StandardCRUDController { /// public PartController(IPartDataLayer dataLayer, ILogger logger) : base(dataLayer, logger) { } @@ -30,8 +31,8 @@ public async Task GetCategoriesAsync() } catch (Exception ex) { - Logger.LogError(ex, "Failed to return the part categories."); - return Problem(); + Logger.LogError(ex, "Failed to return the {Type} categories.", DataObjectTypeName); + return Problem(title: $"{DataObjectTypeName} Get Categories Error", detail: $"Failed to return the {DataObjectTypeName.SpaceCapitalLetters()} categories records because of an error on the server."); } } } diff --git a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor/Controllers/Parts/StockController.cs b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor/Controllers/Parts/StockController.cs index a0aefb6..f3246f5 100644 --- a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor/Controllers/Parts/StockController.cs +++ b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor/Controllers/Parts/StockController.cs @@ -1,6 +1,6 @@ using JMayer.Example.WebAssemblyBlazor.Shared.Data.Parts; using JMayer.Example.WebAssemblyBlazor.Shared.Database.DataLayer.Parts; -using JMayer.Web.Mvc.Controller; +using JMayer.Web.Mvc.Controller.Api; using Microsoft.AspNetCore.Mvc; namespace JMayer.Example.WebAssemblyBlazor.Controllers.Parts; @@ -10,7 +10,7 @@ namespace JMayer.Example.WebAssemblyBlazor.Controllers.Parts; /// [Route("api/[controller]")] [ApiController] -public class StockController : SubUserEditableController +public class StockController : StandardSubCRUDController { /// public StockController(IStockDataLayer dataLayer, ILogger logger) : base(dataLayer, logger) { } diff --git a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.csproj b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.csproj index a26a993..38d086f 100644 --- a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.csproj +++ b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.csproj @@ -8,9 +8,9 @@ + - diff --git a/TestProject/DataHelper.cs b/TestProject/DataHelper.cs index 964ecd4..a84dc7a 100644 --- a/TestProject/DataHelper.cs +++ b/TestProject/DataHelper.cs @@ -20,14 +20,13 @@ internal static class DataHelper public static async Task GetOrCreateAreaAssetAsync(HttpClient client, string areaName) { AssetDataLayer dataLayer = new(client); - List? assets = await dataLayer.GetAllAsync(); - if (assets != null) + if (assets is not null) { Asset? areaAsset = assets.FirstOrDefault(obj => obj.Name == areaName && obj.Type == AssetType.Area); - if (areaAsset != null) + if (areaAsset is not null) { return areaAsset; } @@ -46,14 +45,13 @@ internal static class DataHelper public static async Task GetOrCreatePartAsync(HttpClient client, string name) { PartDataLayer dataLayer = new(client); - List? parts = await dataLayer.GetAllAsync(); - if (parts != null) + if (parts is not null) { Part? part = parts.FirstOrDefault(obj => obj.Name == name); - if (part != null) + if (part is not null) { return part; } @@ -73,14 +71,13 @@ internal static class DataHelper public static async Task GetOrCreateStorageLocationAsync(HttpClient client, string locationName, long ownerID) { StorageLocationDataLayer dataLayer = new(client); - List? storageLocations = await dataLayer.GetAllAsync(); - if (storageLocations != null) + if (storageLocations is not null) { StorageLocation? foundStorageLocation = storageLocations.FirstOrDefault(obj => obj.LocationA == locationName); - if (foundStorageLocation != null) + if (foundStorageLocation is not null) { return foundStorageLocation; } diff --git a/TestProject/Test/WebRequest/Assets/AssetUnitTest.cs b/TestProject/Test/WebRequest/Assets/AssetUnitTest.cs index e97aca9..7875b0d 100644 --- a/TestProject/Test/WebRequest/Assets/AssetUnitTest.cs +++ b/TestProject/Test/WebRequest/Assets/AssetUnitTest.cs @@ -111,12 +111,11 @@ public async Task VerifyAddDuplicateAssetFailure() Assert.Equal(HttpStatusCode.BadRequest, operationResult.StatusCode); //A validation error was returned. - Assert.NotNull(operationResult.ServerSideValidationResult); - Assert.Single(operationResult.ServerSideValidationResult.Errors); + Assert.Single(operationResult.ValidationErrors); //The correct error was returned. - Assert.Contains("name already exists", operationResult.ServerSideValidationResult.Errors[0].ErrorMessage); - Assert.Equal(nameof(Asset.Name), operationResult.ServerSideValidationResult.Errors[0].PropertyName); + Assert.Contains(operationResult.ValidationErrors, obj => obj.Key == nameof(Asset.Name)); + Assert.Contains("name already exists", operationResult.ValidationErrors[nameof(Asset.Name)][0]); } /// @@ -497,12 +496,11 @@ public async Task VerifyUpdateDuplicateAssetFailure() Assert.Equal(HttpStatusCode.BadRequest, operationResult.StatusCode); //A validation error was returned. - Assert.NotNull(operationResult.ServerSideValidationResult); - Assert.Single(operationResult.ServerSideValidationResult.Errors); + Assert.Single(operationResult.ValidationErrors); //The correct error was returned. - Assert.Contains("name already exists", operationResult.ServerSideValidationResult.Errors[0].ErrorMessage); - Assert.Equal(nameof(Asset.Name), operationResult.ServerSideValidationResult.Errors[0].PropertyName); + Assert.Contains(operationResult.ValidationErrors, obj => obj.Key == nameof(Asset.Name)); + Assert.Contains("name already exists", operationResult.ValidationErrors[nameof(Asset.Name)][0]); } else { diff --git a/TestProject/Test/WebRequest/Assets/StorageLocationUnitTest.cs b/TestProject/Test/WebRequest/Assets/StorageLocationUnitTest.cs index 0bb3bf6..657403f 100644 --- a/TestProject/Test/WebRequest/Assets/StorageLocationUnitTest.cs +++ b/TestProject/Test/WebRequest/Assets/StorageLocationUnitTest.cs @@ -88,12 +88,11 @@ public async Task VerifyAddDuplicateStorageLocationFailure(string locationA, str Assert.Equal(HttpStatusCode.BadRequest, operationResult.StatusCode); //A validation error was returned. - Assert.NotNull(operationResult.ServerSideValidationResult); - Assert.Single(operationResult.ServerSideValidationResult.Errors); + Assert.Single(operationResult.ValidationErrors); //The correct error was returned. - Assert.Contains("location already exists", operationResult.ServerSideValidationResult.Errors[0].ErrorMessage); - Assert.Equal(nameof(StorageLocation.LocationA), operationResult.ServerSideValidationResult.Errors[0].PropertyName); + Assert.Contains(operationResult.ValidationErrors, obj => obj.Key == nameof(StorageLocation.LocationA)); + Assert.Contains("location already exists", operationResult.ValidationErrors[nameof(StorageLocation.LocationA)][0]); } /// @@ -157,12 +156,11 @@ public async Task VerifyAddStorageLocationDependenciesNotExists() Assert.Equal(HttpStatusCode.BadRequest, operationResult.StatusCode); //A validation error was returned. - Assert.NotNull(operationResult.ServerSideValidationResult); - Assert.Single(operationResult.ServerSideValidationResult.Errors); + Assert.Single(operationResult.ValidationErrors); //The correct error was returned. - Assert.Contains("asset was not found", operationResult.ServerSideValidationResult.Errors[0].ErrorMessage); - Assert.Equal(nameof(StorageLocation.OwnerInteger64ID), operationResult.ServerSideValidationResult.Errors[0].PropertyName); + Assert.Contains(operationResult.ValidationErrors, obj => obj.Key == nameof(StorageLocation.OwnerInteger64ID)); + Assert.Contains("asset was not found", operationResult.ValidationErrors[nameof(StorageLocation.OwnerInteger64ID)][0]); } /// @@ -456,12 +454,11 @@ public async Task VerifyUpdateDuplicateStorageLocationFailure(string locationA, Assert.Equal(HttpStatusCode.BadRequest, operationResult.StatusCode); //A validation error was returned. - Assert.NotNull(operationResult.ServerSideValidationResult); - Assert.Single(operationResult.ServerSideValidationResult.Errors); + Assert.Single(operationResult.ValidationErrors); //The correct error was returned. - Assert.Contains("location already exists", operationResult.ServerSideValidationResult.Errors[0].ErrorMessage); - Assert.Equal(nameof(StorageLocation.LocationA), operationResult.ServerSideValidationResult.Errors[0].PropertyName); + Assert.Contains(operationResult.ValidationErrors, obj => obj.Key == nameof(StorageLocation.LocationA)); + Assert.Contains("location already exists", operationResult.ValidationErrors[nameof(StorageLocation.LocationA)][0]); } else { @@ -568,12 +565,11 @@ public async Task VerifyUpdateStorageLocationDependenciesNotExists() Assert.Equal(HttpStatusCode.BadRequest, operationResult.StatusCode); //A validation error was returned. - Assert.NotNull(operationResult.ServerSideValidationResult); - Assert.Single(operationResult.ServerSideValidationResult.Errors); + Assert.Single(operationResult.ValidationErrors); //The correct error was returned. - Assert.Contains("asset was not found", operationResult.ServerSideValidationResult.Errors[0].ErrorMessage); - Assert.Equal(nameof(StorageLocation.OwnerInteger64ID), operationResult.ServerSideValidationResult.Errors[0].PropertyName); + Assert.Contains(operationResult.ValidationErrors, obj => obj.Key == nameof(StorageLocation.OwnerInteger64ID)); + Assert.Contains("asset was not found", operationResult.ValidationErrors[nameof(StorageLocation.OwnerInteger64ID)][0]); } /// diff --git a/TestProject/Test/WebRequest/Parts/PartUnitTest.cs b/TestProject/Test/WebRequest/Parts/PartUnitTest.cs index c58e7c0..7f20adc 100644 --- a/TestProject/Test/WebRequest/Parts/PartUnitTest.cs +++ b/TestProject/Test/WebRequest/Parts/PartUnitTest.cs @@ -1,5 +1,6 @@ using JMayer.Data.Data; using JMayer.Data.HTTP.DataLayer; +using JMayer.Example.WebAssemblyBlazor.Shared.Data.Assets; using JMayer.Example.WebAssemblyBlazor.Shared.Data.Parts; using JMayer.Example.WebAssemblyBlazor.Shared.HTTP.DataLayer.Parts; using Microsoft.AspNetCore.Mvc.Testing; @@ -57,12 +58,11 @@ public async Task VerifyAddDuplicatePartFailure() Assert.Equal(HttpStatusCode.BadRequest, operationResult.StatusCode); //A validation error was returned. - Assert.NotNull(operationResult.ServerSideValidationResult); - Assert.Single(operationResult.ServerSideValidationResult.Errors); + Assert.Single(operationResult.ValidationErrors); //The correct error was returned. - Assert.Contains("name already exists", operationResult.ServerSideValidationResult.Errors[0].ErrorMessage); - Assert.Equal(nameof(Part.Name), operationResult.ServerSideValidationResult.Errors[0].PropertyName); + Assert.Contains(operationResult.ValidationErrors, obj => obj.Key == nameof(Part.Name)); + Assert.Contains("name already exists", operationResult.ValidationErrors[nameof(Part.Name)][0]); } /// @@ -254,12 +254,11 @@ public async Task VerifyUpdateDuplicatePartFailure() Assert.Equal(HttpStatusCode.BadRequest, operationResult.StatusCode); //A validation error was returned. - Assert.NotNull(operationResult.ServerSideValidationResult); - Assert.Single(operationResult.ServerSideValidationResult.Errors); + Assert.Single(operationResult.ValidationErrors); //The correct error was returned. - Assert.Contains("name already exists", operationResult.ServerSideValidationResult.Errors[0].ErrorMessage); - Assert.Equal(nameof(Part.Name), operationResult.ServerSideValidationResult.Errors[0].PropertyName); + Assert.Contains(operationResult.ValidationErrors, obj => obj.Key == nameof(Part.Name)); + Assert.Contains("name already exists", operationResult.ValidationErrors[nameof(Part.Name)][0]); } else { diff --git a/TestProject/Test/WebRequest/Parts/StockUnitTest.cs b/TestProject/Test/WebRequest/Parts/StockUnitTest.cs index f24ad45..7e8e932 100644 --- a/TestProject/Test/WebRequest/Parts/StockUnitTest.cs +++ b/TestProject/Test/WebRequest/Parts/StockUnitTest.cs @@ -83,12 +83,11 @@ public async Task VerifyAddDuplicateStockFailure() Assert.Equal(HttpStatusCode.BadRequest, operationResult.StatusCode); //A validation error was returned. - Assert.NotNull(operationResult.ServerSideValidationResult); - Assert.Single(operationResult.ServerSideValidationResult.Errors); + Assert.Single(operationResult.ValidationErrors); //The correct error was returned. - Assert.Contains("stock location already exists", operationResult.ServerSideValidationResult.Errors[0].ErrorMessage); - Assert.Equal(nameof(Stock.StorageLocationID), operationResult.ServerSideValidationResult.Errors[0].PropertyName); + Assert.Contains(operationResult.ValidationErrors, obj => obj.Key == nameof(Stock.StorageLocationID)); + Assert.Contains("stock location already exists", operationResult.ValidationErrors[nameof(Stock.StorageLocationID)][0]); } /// @@ -168,14 +167,13 @@ public async Task VerifyAddStockDependenciesNotExists() Assert.Equal(HttpStatusCode.BadRequest, operationResult.StatusCode); //A validation error was returned. - Assert.NotNull(operationResult.ServerSideValidationResult); - Assert.Equal(2, operationResult.ServerSideValidationResult.Errors.Count); + Assert.Equal(2, operationResult.ValidationErrors.Count); //The correct error was returned. - Assert.Contains("part was not found", operationResult.ServerSideValidationResult.Errors[0].ErrorMessage); - Assert.Equal(nameof(Stock.OwnerInteger64ID), operationResult.ServerSideValidationResult.Errors[0].PropertyName); - Assert.Contains("storage location was not found", operationResult.ServerSideValidationResult.Errors[1].ErrorMessage); - Assert.Equal(nameof(Stock.StorageLocationID), operationResult.ServerSideValidationResult.Errors[1].PropertyName); + Assert.Contains(operationResult.ValidationErrors, obj => obj.Key == nameof(Stock.OwnerInteger64ID)); + Assert.Contains("part was not found", operationResult.ValidationErrors[nameof(Stock.OwnerInteger64ID)][0]); + Assert.Contains(operationResult.ValidationErrors, obj => obj.Key == nameof(Stock.StorageLocationID)); + Assert.Contains("storage location was not found", operationResult.ValidationErrors[nameof(Stock.StorageLocationID)][0]); } /// @@ -715,14 +713,13 @@ public async Task VerifyUpdateStockDependenciesNotExists() Assert.Equal(HttpStatusCode.BadRequest, operationResult.StatusCode); //A validation error was returned. - Assert.NotNull(operationResult.ServerSideValidationResult); - Assert.Equal(2, operationResult.ServerSideValidationResult.Errors.Count); + Assert.Equal(2, operationResult.ValidationErrors.Count); //The correct error was returned. - Assert.Contains("part was not found", operationResult.ServerSideValidationResult.Errors[0].ErrorMessage); - Assert.Equal(nameof(Stock.OwnerInteger64ID), operationResult.ServerSideValidationResult.Errors[0].PropertyName); - Assert.Contains("storage location was not found", operationResult.ServerSideValidationResult.Errors[1].ErrorMessage); - Assert.Equal(nameof(Stock.StorageLocationID), operationResult.ServerSideValidationResult.Errors[1].PropertyName); + Assert.Contains(operationResult.ValidationErrors, obj => obj.Key == nameof(Stock.OwnerInteger64ID)); + Assert.Contains("part was not found", operationResult.ValidationErrors[nameof(Stock.OwnerInteger64ID)][0]); + Assert.Contains(operationResult.ValidationErrors, obj => obj.Key == nameof(Stock.StorageLocationID)); + Assert.Contains("storage location was not found", operationResult.ValidationErrors[nameof(Stock.StorageLocationID)][0]); } else { diff --git a/TestProject/TestProject.csproj b/TestProject/TestProject.csproj index 42e0d25..66b19a9 100644 --- a/TestProject/TestProject.csproj +++ b/TestProject/TestProject.csproj @@ -11,7 +11,6 @@ - @@ -29,6 +28,7 @@ + From 92ec805344c0a5ebd97babafceb3be11510c2e23 Mon Sep 17 00:00:00 2001 From: jmayer913 <72579603+jmayer913@users.noreply.github.com> Date: Sun, 2 Nov 2025 13:14:59 -0500 Subject: [PATCH 03/20] Added missing try...catch to datalayer calls --- .../Components/Base/InspectorBase.cs | 20 ++++++++++++--- .../Pages/Assets/Cards/OverviewCardBase.cs | 25 +++++++++++++------ .../Assets/Dialogs/NewAssetDialogBase.cs | 20 ++++++++++++--- .../Pages/Parts/Cards/OverviewCardBase.cs | 15 ++++++++--- .../Pages/Parts/Dialogs/NewPartDialogBase.cs | 13 +++++++--- .../Pages/Parts/Dialogs/StockDialogBase.cs | 25 ++++++++++--------- 6 files changed, 84 insertions(+), 34 deletions(-) diff --git a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Components/Base/InspectorBase.cs b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Components/Base/InspectorBase.cs index c25cce4..2c4f7a4 100644 --- a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Components/Base/InspectorBase.cs +++ b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Components/Base/InspectorBase.cs @@ -1,11 +1,11 @@ using JMayer.Data.Data; using JMayer.Data.HTTP.DataLayer; +using JMayer.Example.WebAssemblyBlazor.Client.Extensions; using Microsoft.AspNetCore.Components; +using MudBlazor; namespace JMayer.Example.WebAssemblyBlazor.Client.Components.Base; -#warning There's no error handling if DataLayer.GetSingleAsync() throws an exception because of network issues. - /// /// The class manages interaction for an inspector. /// @@ -26,6 +26,12 @@ public class InspectorBase : ComponentBase /// protected T? DataObject { get; set; } + /// + /// The property gets/sets the dialog service used for managing MudDialogs. + /// + [Inject] + protected IDialogService DialogService { get; set; } = default!; + /// /// The property gets/sets the index key for the data object. /// @@ -43,7 +49,15 @@ public class InspectorBase : ComponentBase /// A Task object for the async. protected override async Task OnParametersSetAsync() { - DataObject = await DataLayer.GetSingleAsync(IndexKey); + try + { + DataObject = await DataLayer.GetSingleAsync(IndexKey); + } + catch + { + await DialogService.ShowErrorMessageAsync("Failed to communicate with the server."); + } + await base.OnParametersSetAsync(); Initialized = true; } diff --git a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Pages/Assets/Cards/OverviewCardBase.cs b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Pages/Assets/Cards/OverviewCardBase.cs index 59b8387..0611ddd 100644 --- a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Pages/Assets/Cards/OverviewCardBase.cs +++ b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Pages/Assets/Cards/OverviewCardBase.cs @@ -1,4 +1,5 @@ using JMayer.Data.Data; +using JMayer.Example.WebAssemblyBlazor.Client.Extensions; using JMayer.Example.WebAssemblyBlazor.Shared.Data.Assets; using JMayer.Example.WebAssemblyBlazor.Shared.HTTP.DataLayer.Assets; @@ -44,20 +45,28 @@ protected ListView? SelectedAssetParent /// protected override async Task OnParametersSetAsync() { - ParentAssets = await DataLayer.GetAllListViewAsync() ?? []; - Categories = await DataLayer.GetCategoriesAsync() ?? []; + Task?> categoryTask = DataLayer.GetCategoriesAsync(); + Task?> parentAssetTask = DataLayer.GetAllListViewAsync(); + + try + { + await Task.WhenAll(categoryTask, parentAssetTask); + } + catch + { + await DialogService.ShowErrorMessageAsync("Failed to communicate with the server."); + } + + Categories = categoryTask.Result ?? []; + ParentAssets = parentAssetTask.Result ?? []; if (DataObject.ParentID is not null) { - Asset? parent = await DataLayer.GetSingleAsync(DataObject.ParentID ?? 0); + ListView? parent = ParentAssets.FirstOrDefault(obj => obj.Integer64ID == DataObject.ParentID); if (parent is not null) { - SelectedAssetParent = new ListView() - { - Integer64ID = parent.Integer64ID, - Name = parent.Name ?? string.Empty, - }; + SelectedAssetParent = parent; } } diff --git a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Pages/Assets/Dialogs/NewAssetDialogBase.cs b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Pages/Assets/Dialogs/NewAssetDialogBase.cs index d65a1ff..102ec14 100644 --- a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Pages/Assets/Dialogs/NewAssetDialogBase.cs +++ b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Pages/Assets/Dialogs/NewAssetDialogBase.cs @@ -1,12 +1,11 @@ using JMayer.Data.Data; using JMayer.Example.WebAssemblyBlazor.Client.Components.Base; +using JMayer.Example.WebAssemblyBlazor.Client.Extensions; using JMayer.Example.WebAssemblyBlazor.Shared.Data.Assets; using JMayer.Example.WebAssemblyBlazor.Shared.HTTP.DataLayer.Assets; namespace JMayer.Example.WebAssemblyBlazor.Client.Pages.Assets.Dialogs; -#warning There's no error handling if DataLayer.GetAllListViewAsync() or DataLayer.GetCategoriesAsync() throws an exception because of network issues. - /// /// The class manages user interactions with the NewAssetDialog.razor dialog. /// @@ -47,8 +46,21 @@ protected ListView? SelectedAssetParent /// A Task object for the async. protected override async Task OnParametersSetAsync() { - ParentAssets = await DataLayer.GetAllListViewAsync() ?? []; - Categories = await DataLayer.GetCategoriesAsync() ?? []; + Task?> categoryTask = DataLayer.GetCategoriesAsync(); + Task?> parentAssetTask = DataLayer.GetAllListViewAsync(); + + try + { + await Task.WhenAll(categoryTask, parentAssetTask); + } + catch + { + await DialogService.ShowErrorMessageAsync("Failed to communicate with the server."); + } + + Categories = categoryTask.Result ?? []; + ParentAssets = parentAssetTask.Result ?? []; + await base.OnParametersSetAsync(); } diff --git a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Pages/Parts/Cards/OverviewCardBase.cs b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Pages/Parts/Cards/OverviewCardBase.cs index 0817295..7b05177 100644 --- a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Pages/Parts/Cards/OverviewCardBase.cs +++ b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Pages/Parts/Cards/OverviewCardBase.cs @@ -1,10 +1,9 @@ -using JMayer.Example.WebAssemblyBlazor.Shared.Data.Parts; +using JMayer.Example.WebAssemblyBlazor.Client.Extensions; +using JMayer.Example.WebAssemblyBlazor.Shared.Data.Parts; using JMayer.Example.WebAssemblyBlazor.Shared.HTTP.DataLayer.Parts; namespace JMayer.Example.WebAssemblyBlazor.Client.Pages.Parts.Cards; -#warning There's no error handling if DataLayer.GetCategoriesAsync() throws an exception because of network issues. - /// /// The class manages user interactions with the OverviewCard.razor component. /// @@ -21,7 +20,15 @@ public class OverviewCardBase : Components.Base.OverviewCardBase protected override async Task OnParametersSetAsync() { - Categories = await DataLayer.GetCategoriesAsync() ?? []; + try + { + Categories = await DataLayer.GetCategoriesAsync() ?? []; + } + catch + { + await DialogService.ShowErrorMessageAsync("Failed to communicate with the server."); + } + await base.OnParametersSetAsync(); } diff --git a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Pages/Parts/Dialogs/NewPartDialogBase.cs b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Pages/Parts/Dialogs/NewPartDialogBase.cs index 2b1f313..f9946f4 100644 --- a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Pages/Parts/Dialogs/NewPartDialogBase.cs +++ b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Pages/Parts/Dialogs/NewPartDialogBase.cs @@ -1,11 +1,10 @@ using JMayer.Example.WebAssemblyBlazor.Client.Components.Base; +using JMayer.Example.WebAssemblyBlazor.Client.Extensions; using JMayer.Example.WebAssemblyBlazor.Shared.Data.Parts; using JMayer.Example.WebAssemblyBlazor.Shared.HTTP.DataLayer.Parts; namespace JMayer.Example.WebAssemblyBlazor.Client.Pages.Parts.Dialogs; -#warning There's no error handling if DataLayer.GetCategoriesAsync() throws an exception because of network issues. - /// /// The class manages user interactions with the NewPartDialog.razor dialog. /// @@ -22,7 +21,15 @@ public class NewPartDialogBase : NewDialogBase /// protected override async Task OnParametersSetAsync() { - Categories = await DataLayer.GetCategoriesAsync() ?? []; + try + { + Categories = await DataLayer.GetCategoriesAsync() ?? []; + } + catch + { + await DialogService.ShowErrorMessageAsync("Failed to communicate with the server."); + } + await base.OnParametersSetAsync(); } diff --git a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Pages/Parts/Dialogs/StockDialogBase.cs b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Pages/Parts/Dialogs/StockDialogBase.cs index 69db1fe..2cf6d8e 100644 --- a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Pages/Parts/Dialogs/StockDialogBase.cs +++ b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Pages/Parts/Dialogs/StockDialogBase.cs @@ -1,6 +1,6 @@ using JMayer.Data.Data; using JMayer.Example.WebAssemblyBlazor.Client.Components.Base; -using JMayer.Example.WebAssemblyBlazor.Shared.Data.Assets; +using JMayer.Example.WebAssemblyBlazor.Client.Extensions; using JMayer.Example.WebAssemblyBlazor.Shared.Data.Parts; using JMayer.Example.WebAssemblyBlazor.Shared.HTTP.DataLayer.Assets; using JMayer.Example.WebAssemblyBlazor.Shared.HTTP.DataLayer.Parts; @@ -8,8 +8,6 @@ namespace JMayer.Example.WebAssemblyBlazor.Client.Pages.Parts.Dialogs; -#warning There's no error handling if DataLayer.GetAllListViewAsync() throws an exception because of network issues. - /// /// The class manages user interactions with the StockDialog.razor dialog. /// @@ -65,21 +63,24 @@ protected override void OnParametersSet() /// A Task object for the async. protected override async Task OnParametersSetAsync() { - StorageLocations = await StorageLocationDataLayer.GetAllListViewAsync() ?? []; - - if (IsNewRecord is false) + try { - StorageLocation? storageLocation = await StorageLocationDataLayer.GetSingleAsync(DataObject.StorageLocationID); + StorageLocations = await StorageLocationDataLayer.GetAllListViewAsync() ?? []; - if (storageLocation is not null) + if (IsNewRecord is false) { - SelectedStorageLocation = new ListView() + ListView? storageLocation = StorageLocations.FirstOrDefault(obj => obj.Integer64ID == DataObject.StorageLocationID); + + if (storageLocation is not null) { - Integer64ID = storageLocation.Integer64ID, - Name = storageLocation.Name ?? string.Empty, - }; + SelectedStorageLocation = storageLocation; + } } } + catch + { + await DialogService.ShowErrorMessageAsync("Failed to communicate with the server."); + } await base.OnParametersSetAsync(); } From a39b88413c7f53db89f79b630fbb27ba5d80ef7c Mon Sep 17 00:00:00 2001 From: jmayer913 <72579603+jmayer913@users.noreply.github.com> Date: Sun, 2 Nov 2025 13:21:13 -0500 Subject: [PATCH 04/20] Utilized problem details returned by the server --- .../Components/Base/CardDialogBase.cs | 6 ++---- .../Components/Base/EditableCardBase.cs | 5 ++++- .../Components/Base/NewDialogBase.cs | 5 ++++- .../Components/Base/OverviewCardBase.cs | 6 ++---- .../Extensions/IDialogServiceExtension.cs | 11 ----------- 5 files changed, 12 insertions(+), 21 deletions(-) diff --git a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Components/Base/CardDialogBase.cs b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Components/Base/CardDialogBase.cs index 9b3b3c1..cceaa38 100644 --- a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Components/Base/CardDialogBase.cs +++ b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Components/Base/CardDialogBase.cs @@ -4,7 +4,6 @@ using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components.Forms; using MudBlazor; -using System.Net; namespace JMayer.Example.WebAssemblyBlazor.Client.Components.Base; @@ -120,10 +119,9 @@ protected virtual async Task OnSubmitEditFormAsync() ServerSideValidation.DisplayErrors(errors); } -#warning I need to decide if the problem details are utilized. - else if (operationResult.StatusCode == HttpStatusCode.Conflict) + else if (operationResult.ProblemDetails is not null) { - await DialogService.ShowEditConflictMessageAsync(); + await DialogService.ShowErrorMessageAsync(operationResult.ProblemDetails); } else { diff --git a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Components/Base/EditableCardBase.cs b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Components/Base/EditableCardBase.cs index e53a58b..65b2db8 100644 --- a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Components/Base/EditableCardBase.cs +++ b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Components/Base/EditableCardBase.cs @@ -98,7 +98,10 @@ protected virtual async Task OnDeleteButtonClickAsync(T dataObject) { await MudDataGrid.ReloadServerData(); } -#warning I need to decide if the problem details are utilized. + else if (operationResult.ProblemDetails is not null) + { + await DialogService.ShowErrorMessageAsync(operationResult.ProblemDetails); + } else { await DialogService.ShowErrorMessageAsync("Failed to delete the object because of an error on the server."); diff --git a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Components/Base/NewDialogBase.cs b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Components/Base/NewDialogBase.cs index 25f5406..963969e 100644 --- a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Components/Base/NewDialogBase.cs +++ b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Components/Base/NewDialogBase.cs @@ -88,7 +88,10 @@ protected virtual async Task OnSubmitEditFormAsync() ServerSideValidation.DisplayErrors(errors); } - #warning I need to decide if the problem details are utilized. + else if (operationResult.ProblemDetails is not null) + { + await DialogService.ShowErrorMessageAsync(operationResult.ProblemDetails); + } else { await DialogService.ShowErrorMessageAsync("Failed to create the object because of an error on the server."); diff --git a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Components/Base/OverviewCardBase.cs b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Components/Base/OverviewCardBase.cs index f87d548..2e46171 100644 --- a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Components/Base/OverviewCardBase.cs +++ b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Components/Base/OverviewCardBase.cs @@ -4,7 +4,6 @@ using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components.Forms; using MudBlazor; -using System.Net; namespace JMayer.Example.WebAssemblyBlazor.Client.Components.Base; @@ -108,10 +107,9 @@ protected virtual async Task OnSubmitFormAsync() ServerSideValidation.DisplayErrors(errors); } -#warning I need to decide if the problem details are utilized. - else if (operationResult.StatusCode is HttpStatusCode.Conflict) + else if (operationResult.ProblemDetails is not null) { - await DialogService.ShowEditConflictMessageAsync(); + await DialogService.ShowErrorMessageAsync(operationResult.ProblemDetails); } else { diff --git a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Extensions/IDialogServiceExtension.cs b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Extensions/IDialogServiceExtension.cs index 180400e..a99d4f3 100644 --- a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Extensions/IDialogServiceExtension.cs +++ b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Extensions/IDialogServiceExtension.cs @@ -18,17 +18,6 @@ public static class IDialogServiceExtension return await dialogService.ShowMessageBox("Warning", message, cancelText: "Cancel"); } - /// - /// The method displays an edit conflict message to the user. - /// - /// The dialog service used to display the error message. - /// The message to display to the user. - /// A Task object for the async. - public static async Task ShowEditConflictMessageAsync(this IDialogService dialogService, string message = "The submitted data was detected to be out of date; please refresh and try again.") - { - _ = await dialogService.ShowMessageBox("Warning", message, options: new DialogOptions() { CloseButton = false }); - } - /// /// The method displays an error message to the user. /// From ed381457874f2f9207de1a055719453b2897cfce Mon Sep 17 00:00:00 2001 From: jmayer913 <72579603+jmayer913@users.noreply.github.com> Date: Sun, 2 Nov 2025 13:31:25 -0500 Subject: [PATCH 05/20] Removed unnecessary override Name is now optional so the storage location and stock don't need to set one just to pass validation. --- .../Data/Assets/StorageLocation.cs | 3 --- .../Assets/Dialogs/StorageLocationDialogBase.cs | 11 ----------- .../Pages/Parts/Dialogs/StockDialogBase.cs | 13 ------------- 3 files changed, 27 deletions(-) diff --git a/JMayer.Example.WebAssemblyBlazor.Shared/Data/Assets/StorageLocation.cs b/JMayer.Example.WebAssemblyBlazor.Shared/Data/Assets/StorageLocation.cs index 9250b66..74e2c33 100644 --- a/JMayer.Example.WebAssemblyBlazor.Shared/Data/Assets/StorageLocation.cs +++ b/JMayer.Example.WebAssemblyBlazor.Shared/Data/Assets/StorageLocation.cs @@ -3,9 +3,6 @@ namespace JMayer.Example.WebAssemblyBlazor.Shared.Data.Assets; -#warning I wonder if I should make the locations nullable since no value can be set. -#warning I should use Name instead of FriendlyName; maybe I can override Name only have it be get or hide the set with the access level. - /// /// The class represents a storage location for an area asset. /// diff --git a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Pages/Assets/Dialogs/StorageLocationDialogBase.cs b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Pages/Assets/Dialogs/StorageLocationDialogBase.cs index b9e1898..b715764 100644 --- a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Pages/Assets/Dialogs/StorageLocationDialogBase.cs +++ b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Pages/Assets/Dialogs/StorageLocationDialogBase.cs @@ -1,7 +1,6 @@ using JMayer.Example.WebAssemblyBlazor.Client.Components.Base; using JMayer.Example.WebAssemblyBlazor.Shared.Data.Assets; using JMayer.Example.WebAssemblyBlazor.Shared.HTTP.DataLayer.Assets; -using Microsoft.AspNetCore.Components; namespace JMayer.Example.WebAssemblyBlazor.Client.Pages.Assets.Dialogs; @@ -10,16 +9,6 @@ namespace JMayer.Example.WebAssemblyBlazor.Client.Pages.Assets.Dialogs; /// public class StorageLocationDialogBase : CardDialogBase { - /// - public override Task SetParametersAsync(ParameterView parameters) - { - //The Name property is a required field but the - //StorageLocation data object doesn't use it so - //it needs to be set to pass validation. - DataObject.Name = "A Name"; - return base.SetParametersAsync(parameters); - } - /// protected override async Task OnSubmitEditFormAsync() { diff --git a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Pages/Parts/Dialogs/StockDialogBase.cs b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Pages/Parts/Dialogs/StockDialogBase.cs index 2cf6d8e..fb6d8ca 100644 --- a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Pages/Parts/Dialogs/StockDialogBase.cs +++ b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Pages/Parts/Dialogs/StockDialogBase.cs @@ -44,19 +44,6 @@ protected ListView? SelectedStorageLocation } } - /// - /// The method sets up the component after the parameters are set. - /// - /// A Task object for the async. - protected override void OnParametersSet() - { - //The Name property is a required field but the - //Stock data object doesn't use it so - //it needs to be set to pass validation. - DataObject.Name = "A Name"; - base.OnParametersSet(); - } - /// /// The method sets up the component after the parameters are set. /// From 76bcdcc90d115221c0afa0137e364d0ba8aacaba Mon Sep 17 00:00:00 2001 From: jmayer913 <72579603+jmayer913@users.noreply.github.com> Date: Sun, 2 Nov 2025 13:41:13 -0500 Subject: [PATCH 06/20] Code cleanup --- .../Extensions/GridStateExtension.cs | 2 +- .../Extensions/IDialogServiceExtension.cs | 8 ++------ .../Pages/Assets/Dialogs/StorageLocationDialogBase.cs | 4 +--- .../Pages/NotFound.razor | 4 ---- 4 files changed, 4 insertions(+), 14 deletions(-) diff --git a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Extensions/GridStateExtension.cs b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Extensions/GridStateExtension.cs index 03eb918..945ba62 100644 --- a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Extensions/GridStateExtension.cs +++ b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Extensions/GridStateExtension.cs @@ -65,7 +65,7 @@ public static QueryDefinition ToQueryDefinition(this GridState gridState) { string value = string.Empty; - if (filterDefinition.Value != null && !string.IsNullOrWhiteSpace(filterDefinition.Value.ToString())) + if (filterDefinition.Value is not null && string.IsNullOrWhiteSpace(filterDefinition.Value.ToString()) is false) { if (filterDefinition.Value is DateTime dateTime) { diff --git a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Extensions/IDialogServiceExtension.cs b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Extensions/IDialogServiceExtension.cs index a99d4f3..8e8a9fb 100644 --- a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Extensions/IDialogServiceExtension.cs +++ b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Extensions/IDialogServiceExtension.cs @@ -14,9 +14,7 @@ public static class IDialogServiceExtension /// The message to display to the user. /// True means the user confirm the action; false or null means the user didn't. public static async Task ShowConfirmActionMessageAsync(this IDialogService dialogService, string message = "Do you want to confirm this action?") - { - return await dialogService.ShowMessageBox("Warning", message, cancelText: "Cancel"); - } + => _ = await dialogService.ShowMessageBox("Warning", message, cancelText: "Cancel"); /// /// The method displays an error message to the user. @@ -25,7 +23,5 @@ public static class IDialogServiceExtension /// The message to display to the user. /// A Task object for the async. public static async Task ShowErrorMessageAsync(this IDialogService dialogService, string message) - { - _ = await dialogService.ShowMessageBox("Error", message, options: new DialogOptions() { CloseButton = false }); - } + => _ = await dialogService.ShowMessageBox("Error", message, options: new DialogOptions() { CloseButton = false }); } diff --git a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Pages/Assets/Dialogs/StorageLocationDialogBase.cs b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Pages/Assets/Dialogs/StorageLocationDialogBase.cs index b715764..928e6ef 100644 --- a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Pages/Assets/Dialogs/StorageLocationDialogBase.cs +++ b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Pages/Assets/Dialogs/StorageLocationDialogBase.cs @@ -10,11 +10,9 @@ namespace JMayer.Example.WebAssemblyBlazor.Client.Pages.Assets.Dialogs; public class StorageLocationDialogBase : CardDialogBase { /// + /// Overridden because the Name property is used for the ListView and we need to make sure the Name property is set to the FriendlyName. protected override async Task OnSubmitEditFormAsync() { - //The Name property is used for the ListView and - //this ensures the ListView displays the friendly - //name. DataObject.Name = DataObject.FriendlyName; await base.OnSubmitEditFormAsync(); } diff --git a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Pages/NotFound.razor b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Pages/NotFound.razor index 06a5868..faade9d 100644 --- a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Pages/NotFound.razor +++ b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Pages/NotFound.razor @@ -1,7 +1,3 @@ @page "/NotFound" Sorry, the page was not found. - -@code { - -} From 905f02b71536c11cc1cce6814c2fa1030720ce8b Mon Sep 17 00:00:00 2001 From: jmayer913 <72579603+jmayer913@users.noreply.github.com> Date: Tue, 4 Nov 2025 15:43:53 -0500 Subject: [PATCH 07/20] Code cleanup on the unit tests --- .../Components/Base/SearchBase.cs | 30 +-- .../Test/WebRequest/Assets/AssetUnitTest.cs | 131 +++---------- .../Assets/StorageLocationUnitTest.cs | 102 +++------- .../Test/WebRequest/Parts/PartUnitTest.cs | 40 +--- .../Test/WebRequest/Parts/StockUnitTest.cs | 179 ++++++------------ 5 files changed, 138 insertions(+), 344 deletions(-) diff --git a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Components/Base/SearchBase.cs b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Components/Base/SearchBase.cs index 7bb789f..1d80359 100644 --- a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Components/Base/SearchBase.cs +++ b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Components/Base/SearchBase.cs @@ -82,26 +82,28 @@ protected virtual async Task OnDeleteButtonClickAsync(T dataObject) { bool? result = await DialogService.ShowConfirmActionMessageAsync(); - if (result is true) + if (result is not true) { - try - { - OperationResult operationResult = await DataLayer.DeleteAsync(dataObject); + return; + } - if (operationResult.IsSuccessStatusCode) - { - await MudDataGrid.ReloadServerData(); - } - else - { - await DialogService.ShowErrorMessageAsync("Failed to delete the object because of an error on the server."); - } + try + { + OperationResult operationResult = await DataLayer.DeleteAsync(dataObject); + + if (operationResult.IsSuccessStatusCode) + { + await MudDataGrid.ReloadServerData(); } - catch + else { - await DialogService.ShowErrorMessageAsync("Failed to communicate with the server."); + await DialogService.ShowErrorMessageAsync("Failed to delete the object because of an error on the server."); } } + catch + { + await DialogService.ShowErrorMessageAsync("Failed to communicate with the server."); + } } /// diff --git a/TestProject/Test/WebRequest/Assets/AssetUnitTest.cs b/TestProject/Test/WebRequest/Assets/AssetUnitTest.cs index 7875b0d..2993ed5 100644 --- a/TestProject/Test/WebRequest/Assets/AssetUnitTest.cs +++ b/TestProject/Test/WebRequest/Assets/AssetUnitTest.cs @@ -55,14 +55,13 @@ public async Task VerifyAddAsset(string name, string? description, AssetType ass long? parentID = null; - if (!string.IsNullOrEmpty(parentName)) + if (parentName is not null) { parentID = (await dataLayer.GetAllListViewAsync())?.FirstOrDefault(obj => obj.Name == parentName)?.Integer64ID; - if (parentID == null) + if (parentID is null) { Assert.Fail("The parent asset was not found."); - return; } } @@ -92,12 +91,7 @@ public async Task VerifyAddDuplicateAssetFailure() AssetDataLayer dataLayer = new(client); OperationResult operationResult = await dataLayer.CreateAsync(new Asset() { Name = "Duplicate Asset Test" }); - - if (!operationResult.IsSuccessStatusCode) - { - Assert.Fail("Failed to create the first asset."); - return; - } + Assert.True(operationResult.IsSuccessStatusCode, "Failed to create the first asset."); operationResult = await dataLayer.CreateAsync(new Asset() { Name = "Duplicate Asset Test" }); @@ -110,11 +104,9 @@ public async Task VerifyAddDuplicateAssetFailure() //A bad request status was returned. Assert.Equal(HttpStatusCode.BadRequest, operationResult.StatusCode); - //A validation error was returned. - Assert.Single(operationResult.ValidationErrors); - //The correct error was returned. Assert.Contains(operationResult.ValidationErrors, obj => obj.Key == nameof(Asset.Name)); + Assert.Single(operationResult.ValidationErrors[nameof(Asset.Name)]); Assert.Contains("name already exists", operationResult.ValidationErrors[nameof(Asset.Name)][0]); } @@ -144,10 +136,10 @@ public async Task VerifyDeleteAsset() OperationResult operationResult = await dataLayer.CreateAsync(new Asset() { Name = "Delete Asset Test" }); - if (operationResult.DataObject is Asset asset) + if (operationResult.IsSuccessStatusCode && operationResult.DataObject is Asset asset) { operationResult = await dataLayer.DeleteAsync(asset); - Assert.True(operationResult.IsSuccessStatusCode); + Assert.True(operationResult.IsSuccessStatusCode, "The operation should have successed."); } else { @@ -168,23 +160,13 @@ public async Task VerifyDeleteAssetParentCascade() long preCount = await dataLayer.CountAsync(); OperationResult operationResult = await dataLayer.CreateAsync(new Asset() { Name = "Delete Parent Test" }); - if (operationResult.DataObject is Asset parentAsset) + if (operationResult.IsSuccessStatusCode && operationResult.DataObject is Asset parentAsset) { operationResult = await dataLayer.CreateAsync(new Asset() { Name = "Test Child 1", ParentID = parentAsset.Integer64ID }); - - if (!operationResult.IsSuccessStatusCode) - { - Assert.Fail("Failed to create the child asset."); - return; - } + Assert.True(operationResult.IsSuccessStatusCode, "Failed to create the child asset."); operationResult = await dataLayer.CreateAsync(new Asset() { Name = "Test Child 2", ParentID = parentAsset.Integer64ID }); - - if (!operationResult.IsSuccessStatusCode) - { - Assert.Fail("Failed to create the child asset."); - return; - } + Assert.True(operationResult.IsSuccessStatusCode, "Failed to create the child asset."); operationResult = await dataLayer.DeleteAsync(parentAsset); long postCount = await dataLayer.CountAsync(); @@ -196,7 +178,6 @@ public async Task VerifyDeleteAssetParentCascade() else { Assert.Fail("Failed to create the parent asset."); - return; } } @@ -277,7 +258,7 @@ public async Task VerifyGetSingleAssetWithId() OperationResult operationResult = await dataLayer.CreateAsync(new Asset() { Name = "Get Single Asset Test" }); - if (operationResult.DataObject is Asset createdAsset) + if (operationResult.IsSuccessStatusCode && operationResult.DataObject is Asset createdAsset) { Asset? asset = await dataLayer.GetSingleAsync(createdAsset.Integer64ID); Assert.NotNull(asset); @@ -310,7 +291,7 @@ public async Task VerifyGetSingleAssetWithId() [InlineData("Test Asset 6", "Test AL1-05", "Test AL1-05", "Conveyor", "Make", "Model", "Manufacturer", null, Priority.Medium, false)] [InlineData("Test Asset 7", "Test AL1-05-BSD", "Test AL1-05-BSD", "BSD", "Make", "Model", "Manufacturer", "Manufacturer Number", Priority.Medium, false)] [InlineData("Test Asset 8", "Test AL1-VSU", "Test AL1-VSU", "VSU", "Make", "Model", "Manufacturer", "Manufacturer Number", Priority.Medium, true)] - public async Task VerifyUpdateAsset(string originalName, string newName, string description, string? category, string? make, string? model, string? manufacturer, string? manufacturerNumber, Priority priority, bool online) + public async Task VerifyUpdateAsset(string originalName, string newName, string? description, string? category, string? make, string? model, string? manufacturer, string? manufacturerNumber, Priority priority, bool online) { HttpClient client = _factory.CreateClient(); AssetDataLayer dataLayer = new(client); @@ -359,7 +340,7 @@ public async Task VerifyUpdateAssetOldDataConflict() Name = "Old Data Asset Test", }); - if (operationResult.DataObject is Asset firstAsset) + if (operationResult.IsSuccessStatusCode && operationResult.DataObject is Asset firstAsset) { Asset secondAsset = new(firstAsset); @@ -367,12 +348,7 @@ public async Task VerifyUpdateAssetOldDataConflict() secondAsset.Category = "A Category"; operationResult = await dataLayer.UpdateAsync(secondAsset); - - if (!operationResult.IsSuccessStatusCode) - { - Assert.Fail("Failed to update the second asset."); - return; - } + Assert.True(operationResult.IsSuccessStatusCode, "Failed to update the second asset."); operationResult = await dataLayer.UpdateAsync(firstAsset); @@ -383,7 +359,6 @@ public async Task VerifyUpdateAssetOldDataConflict() else { Assert.Fail("Failed to create the asset."); - return; } } @@ -400,61 +375,42 @@ public async Task VerifyUpdateAssetTreeStructure() OperationResult operationResult = await dataLayer.CreateAsync(new Asset() { Name = "Root Asset Tree Structure Test" }); Asset? rootAsset = operationResult.DataObject as Asset; - if (rootAsset == null) + if (rootAsset is null) { Assert.Fail("Failed to create the root asset"); - return; } operationResult = await dataLayer.CreateAsync(new Asset() { Name = "Other Root Asset Tree Structure Test" }); Asset? otherRootAsset = operationResult.DataObject as Asset; - if (otherRootAsset == null) + if (otherRootAsset is null) { Assert.Fail("Failed to create the other root asset"); - return; } operationResult = await dataLayer.CreateAsync(new Asset() { Name = "Middle Asset Tree Structure Test", ParentID = rootAsset.Integer64ID }); Asset? middleAsset = operationResult.DataObject as Asset; - if (middleAsset == null) + if (middleAsset is null) { Assert.Fail("Failed to create the middle asset."); - return; } operationResult = await dataLayer.CreateAsync(new Asset() { Name = "Leaf Asset Tree Structure Test 1", ParentID = middleAsset.Integer64ID }); - - if (!operationResult.IsSuccessStatusCode) - { - Assert.Fail("Failed to create the first leaf asset."); - return; - } + Assert.True(operationResult.IsSuccessStatusCode, "Failed to create the first leaf asset."); operationResult = await dataLayer.CreateAsync(new Asset() { Name = "Leaf Asset Tree Structure Test 2", ParentID = middleAsset.Integer64ID }); - - if (!operationResult.IsSuccessStatusCode) - { - Assert.Fail("Failed to create the second leaf asset."); - return; - } + Assert.True(operationResult.IsSuccessStatusCode, "Failed to create the second leaf asset."); middleAsset.ParentID = otherRootAsset.Integer64ID; operationResult = await dataLayer.UpdateAsync(middleAsset); - - if (!operationResult.IsSuccessStatusCode) - { - Assert.Fail("Failed to update the parent of the middle asset."); - return; - } + Assert.True(operationResult.IsSuccessStatusCode, "Failed to update the parent of the middle asset."); List? allAssets = await dataLayer.GetAllAsync(); - if (allAssets == null) + if (allAssets is null) { Assert.Fail("Failed to retrieve the assets."); - return; } List testTreeAssets = allAssets.Where(obj => obj.Integer64ID == middleAsset.Integer64ID || obj.ParentID == middleAsset.Integer64ID).ToList(); @@ -472,16 +428,11 @@ public async Task VerifyUpdateDuplicateAssetFailure() AssetDataLayer dataLayer = new(client); OperationResult operationResult = await dataLayer.CreateAsync(new Asset() { Name = "Duplicate Asset Test 1" }); - - if (!operationResult.IsSuccessStatusCode) - { - Assert.Fail("Failed to create the first asset."); - return; - } + Assert.True(operationResult.IsSuccessStatusCode, "Failed to create the first asset."); operationResult = await dataLayer.CreateAsync(new Asset() { Name = "Duplicate Asset Test 2" }); - if (operationResult.DataObject is Asset asset) + if (operationResult.IsSuccessStatusCode && operationResult.DataObject is Asset asset) { asset.Name = "Duplicate Asset Test 1"; operationResult = await dataLayer.UpdateAsync(asset); @@ -495,11 +446,9 @@ public async Task VerifyUpdateDuplicateAssetFailure() //A bad request status was returned. Assert.Equal(HttpStatusCode.BadRequest, operationResult.StatusCode); - //A validation error was returned. - Assert.Single(operationResult.ValidationErrors); - //The correct error was returned. Assert.Contains(operationResult.ValidationErrors, obj => obj.Key == nameof(Asset.Name)); + Assert.Single(operationResult.ValidationErrors[nameof(Asset.Name)]); Assert.Contains("name already exists", operationResult.ValidationErrors[nameof(Asset.Name)][0]); } else @@ -521,55 +470,37 @@ public async Task VerifyUpdateRootAssetName() OperationResult operationResult = await dataLayer.CreateAsync(new Asset() { Name = "Root Asset Rename Test" }); Asset? rootAsset = operationResult.DataObject as Asset; - if (rootAsset == null) + if (rootAsset is null) { Assert.Fail("Failed to create the root asset"); - return; } operationResult = await dataLayer.CreateAsync(new Asset() { Name = "Middle Asset Rename Test", ParentID = rootAsset.Integer64ID }); Asset? middleAsset = operationResult.DataObject as Asset; - if (middleAsset == null) + if (middleAsset is null) { Assert.Fail("Failed to create the middle asset."); - return; } operationResult = await dataLayer.CreateAsync(new Asset() { Name = "Leaf Asset Rename Test 1", ParentID = middleAsset.Integer64ID }); - - if (!operationResult.IsSuccessStatusCode) - { - Assert.Fail("Failed to create the first leaf asset."); - return; - } + Assert.True(operationResult.IsSuccessStatusCode, "Failed to create the first leaf asset."); operationResult = await dataLayer.CreateAsync(new Asset() { Name = "Leaf Asset Rename Test 2", ParentID = middleAsset.Integer64ID }); - - if (!operationResult.IsSuccessStatusCode) - { - Assert.Fail("Failed to create the second leaf asset."); - return; - } + Assert.True(operationResult.IsSuccessStatusCode, "Failed to create the second leaf asset."); rootAsset.Name = "New Root Asset Rename Test"; operationResult = await dataLayer.UpdateAsync(rootAsset); - - if (!operationResult.IsSuccessStatusCode) - { - Assert.Fail("Failed to rename of the root asset."); - return; - } + Assert.True(operationResult.IsSuccessStatusCode, "Failed to rename of the root asset."); List? allAssets = await dataLayer.GetAllAsync(); - if (allAssets == null) + if (allAssets is null) { Assert.Fail("Failed to retrieve the assets."); - return; } - List testTreeAssets = allAssets.Where(obj => obj.Integer64ID == middleAsset.Integer64ID || obj.ParentID == middleAsset.Integer64ID).ToList(); - Assert.All(testTreeAssets, asset => Assert.True(asset.ParentPath != null && asset.ParentPath.Contains(rootAsset.Name))); + List testTreeAssets = [.. allAssets.Where(obj => obj.Integer64ID == middleAsset.Integer64ID || obj.ParentID == middleAsset.Integer64ID)]; + Assert.All(testTreeAssets, asset => Assert.True(asset.ParentPath is not null && asset.ParentPath.Contains(rootAsset.Name))); } } diff --git a/TestProject/Test/WebRequest/Assets/StorageLocationUnitTest.cs b/TestProject/Test/WebRequest/Assets/StorageLocationUnitTest.cs index 657403f..0fda7c4 100644 --- a/TestProject/Test/WebRequest/Assets/StorageLocationUnitTest.cs +++ b/TestProject/Test/WebRequest/Assets/StorageLocationUnitTest.cs @@ -46,10 +46,9 @@ public async Task VerifyAddDuplicateStorageLocationFailure(string locationA, str Asset? areaAsset = await DataHelper.GetOrCreateAreaAssetAsync(client, Constants.TestAreaAsset); - if (areaAsset == null) + if (areaAsset is null) { Assert.Fail("Failed to retrieve or create the area asset."); - return; } StorageLocation storageLocation = new() @@ -61,12 +60,7 @@ public async Task VerifyAddDuplicateStorageLocationFailure(string locationA, str }; storageLocation.Name = storageLocation.FriendlyName; OperationResult operationResult = await dataLayer.CreateAsync(storageLocation); - - if (!operationResult.IsSuccessStatusCode) - { - Assert.Fail("Failed to create the first storage location."); - return; - } + Assert.True(operationResult.IsSuccessStatusCode, "Failed to create the first storage location."); storageLocation = new() { @@ -87,11 +81,9 @@ public async Task VerifyAddDuplicateStorageLocationFailure(string locationA, str //A bad request status was returned. Assert.Equal(HttpStatusCode.BadRequest, operationResult.StatusCode); - //A validation error was returned. - Assert.Single(operationResult.ValidationErrors); - //The correct error was returned. Assert.Contains(operationResult.ValidationErrors, obj => obj.Key == nameof(StorageLocation.LocationA)); + Assert.Single(operationResult.ValidationErrors[nameof(StorageLocation.LocationA)]); Assert.Contains("location already exists", operationResult.ValidationErrors[nameof(StorageLocation.LocationA)][0]); } @@ -113,10 +105,9 @@ public async Task VerifyAddStorageLocation(string locationA, string locationB, s Asset? areaAsset = await DataHelper.GetOrCreateAreaAssetAsync(client, Constants.TestAreaAsset); - if (areaAsset == null) + if (areaAsset is null) { Assert.Fail("Failed to retrieve or create the area asset."); - return; } StorageLocation storageLocation = new() @@ -155,11 +146,9 @@ public async Task VerifyAddStorageLocationDependenciesNotExists() //A bad request status was returned. Assert.Equal(HttpStatusCode.BadRequest, operationResult.StatusCode); - //A validation error was returned. - Assert.Single(operationResult.ValidationErrors); - //The correct error was returned. Assert.Contains(operationResult.ValidationErrors, obj => obj.Key == nameof(StorageLocation.OwnerInteger64ID)); + Assert.Single(operationResult.ValidationErrors[nameof(StorageLocation.OwnerInteger64ID)]); Assert.Contains("asset was not found", operationResult.ValidationErrors[nameof(StorageLocation.OwnerInteger64ID)][0]); } @@ -189,35 +178,19 @@ public async Task VerifyDeleteAreaAssetCascade() Asset? areaAsset = await DataHelper.GetOrCreateAreaAssetAsync(client, "Cascade Area Asset-Storage Location Delete Test"); - if (areaAsset == null) + if (areaAsset is null) { Assert.Fail("Failed to retrieve or create the area asset."); - return; } OperationResult operationResult = await dataLayer.CreateAsync(new StorageLocation() { LocationA = "Cascade Area Asset-Storage Location Delete Test 1", Name = "Cascade Storage Location Delete Test 1", OwnerInteger64ID = areaAsset.Integer64ID }); - - if (!operationResult.IsSuccessStatusCode) - { - Assert.Fail("Failed to create the storage location."); - return; - } + Assert.True(operationResult.IsSuccessStatusCode, "Failed to create the first storage location."); operationResult = await dataLayer.CreateAsync(new StorageLocation() { LocationA = "Cascade Area Asset-Storage Location Delete Test 2", Name = "Cascade Storage Location Delete Test 2", OwnerInteger64ID = areaAsset.Integer64ID }); - - if (!operationResult.IsSuccessStatusCode) - { - Assert.Fail("Failed to create the storage location."); - return; - } + Assert.True(operationResult.IsSuccessStatusCode, "Failed to create the second storage location."); operationResult = await dataLayer.CreateAsync(new StorageLocation() { LocationA = "Cascade Area Asset-Storage Location Delete Test 3", Name = "Cascade Storage Location Delete Test 3", OwnerInteger64ID = areaAsset.Integer64ID }); - - if (!operationResult.IsSuccessStatusCode) - { - Assert.Fail("Failed to create the storage location."); - return; - } + Assert.True(operationResult.IsSuccessStatusCode, "Failed to create the third storage location."); await new AssetDataLayer(client).DeleteAsync(areaAsset); @@ -239,15 +212,14 @@ public async Task VerifyDeleteStorageLocation() Asset? areaAsset = await DataHelper.GetOrCreateAreaAssetAsync(client, Constants.TestAreaAsset); - if (areaAsset == null) + if (areaAsset is null) { Assert.Fail("Failed to retrieve or create the area asset."); - return; } OperationResult operationResult = await dataLayer.CreateAsync(new StorageLocation() { LocationA = "Delete Storage Location Test", Name = "Test", OwnerInteger64ID = areaAsset.Integer64ID }); - if (operationResult.DataObject is StorageLocation storageLocation) + if (operationResult.IsSuccessStatusCode && operationResult.DataObject is StorageLocation storageLocation) { operationResult = await dataLayer.DeleteAsync(storageLocation); Assert.True(operationResult.IsSuccessStatusCode, "The operation should have been successful."); @@ -287,10 +259,9 @@ public async Task VerifyGetAllListViewStorageLocationsWithOwnerId() Asset? areaAsset = await DataHelper.GetOrCreateAreaAssetAsync(client, BHSExampleBuilder.MainPartStorageAreaAssetName); - if (areaAsset == null) + if (areaAsset is null) { Assert.Fail("Failed to find the area asset"); - return; } List? storageLocations = await dataLayer.GetAllListViewAsync(areaAsset.Integer64ID); @@ -329,10 +300,9 @@ public async Task VerifyGetAllStorageLocationsWithOwnerId() Asset? areaAsset = await DataHelper.GetOrCreateAreaAssetAsync(client, BHSExampleBuilder.MainPartStorageAreaAssetName); - if (areaAsset == null) + if (areaAsset is null) { Assert.Fail("Failed to find the area asset"); - return; } List? storageLocations = await dataLayer.GetAllAsync(areaAsset.Integer64ID); @@ -368,15 +338,14 @@ public async Task VerifyGetSingleStorageLocationWithIdA() Asset? areaAsset = await DataHelper.GetOrCreateAreaAssetAsync(client, Constants.TestAreaAsset); - if (areaAsset == null) + if (areaAsset is null) { Assert.Fail("Failed to retrieve or create the area asset."); - return; } OperationResult operationResult = await dataLayer.CreateAsync(new StorageLocation() { LocationA = "Get Single Storage Location Test", Name = "Test", OwnerInteger64ID = areaAsset.Integer64ID }); - if (operationResult.DataObject is StorageLocation createdStorageLocation) + if (operationResult.IsSuccessStatusCode && operationResult.DataObject is StorageLocation createdStorageLocation) { StorageLocation? fetchedStorageLocation = await dataLayer.GetSingleAsync(createdStorageLocation.Integer64ID); Assert.NotNull(fetchedStorageLocation); @@ -405,10 +374,9 @@ public async Task VerifyUpdateDuplicateStorageLocationFailure(string locationA, Asset? areaAsset = await DataHelper.GetOrCreateAreaAssetAsync(client, Constants.TestAreaAsset); - if (areaAsset == null) + if (areaAsset is null) { Assert.Fail("Failed to retrieve or create the area asset."); - return; } StorageLocation firstStorageLocation = new() @@ -420,12 +388,7 @@ public async Task VerifyUpdateDuplicateStorageLocationFailure(string locationA, }; firstStorageLocation.Name = firstStorageLocation.FriendlyName; OperationResult operationResult = await dataLayer.CreateAsync(firstStorageLocation); - - if (!operationResult.IsSuccessStatusCode) - { - Assert.Fail("Failed to create the first storage location."); - return; - } + Assert.True(operationResult.IsSuccessStatusCode, "Failed to create the first storage location."); StorageLocation secondStorageLocation = new() { @@ -453,17 +416,14 @@ public async Task VerifyUpdateDuplicateStorageLocationFailure(string locationA, //A bad request status was returned. Assert.Equal(HttpStatusCode.BadRequest, operationResult.StatusCode); - //A validation error was returned. - Assert.Single(operationResult.ValidationErrors); - //The correct error was returned. Assert.Contains(operationResult.ValidationErrors, obj => obj.Key == nameof(StorageLocation.LocationA)); + Assert.Single(operationResult.ValidationErrors[nameof(StorageLocation.LocationA)]); Assert.Contains("location already exists", operationResult.ValidationErrors[nameof(StorageLocation.LocationA)][0]); } else { Assert.Fail("Failed to create the second storage location."); - return; } } @@ -485,10 +445,9 @@ public async Task VerifyUpdateStorageLocation(string originalLocationA, string l Asset? areaAsset = await DataHelper.GetOrCreateAreaAssetAsync(client, Constants.TestAreaAsset); - if (areaAsset == null) + if (areaAsset is null) { Assert.Fail("Failed to retrieve or create the area asset."); - return; } StorageLocation originalStorageLocation = new() @@ -531,10 +490,9 @@ public async Task VerifyUpdateStorageLocationDependenciesNotExists() Asset? areaAsset = await DataHelper.GetOrCreateAreaAssetAsync(client, Constants.TestAreaAsset); - if (areaAsset == null) + if (areaAsset is null) { Assert.Fail("Failed to retrieve or create the area asset."); - return; } StorageLocation? storageLocation = new() @@ -546,10 +504,9 @@ public async Task VerifyUpdateStorageLocationDependenciesNotExists() OperationResult operationResult = await dataLayer.CreateAsync(storageLocation); storageLocation = operationResult.DataObject as StorageLocation; - if (storageLocation == null) + if (storageLocation is null) { Assert.Fail("Failed to create the storage location."); - return; } storageLocation.OwnerInteger64ID = 0; @@ -564,11 +521,9 @@ public async Task VerifyUpdateStorageLocationDependenciesNotExists() //A bad request status was returned. Assert.Equal(HttpStatusCode.BadRequest, operationResult.StatusCode); - //A validation error was returned. - Assert.Single(operationResult.ValidationErrors); - //The correct error was returned. Assert.Contains(operationResult.ValidationErrors, obj => obj.Key == nameof(StorageLocation.OwnerInteger64ID)); + Assert.Single(operationResult.ValidationErrors[nameof(StorageLocation.OwnerInteger64ID)]); Assert.Contains("asset was not found", operationResult.ValidationErrors[nameof(StorageLocation.OwnerInteger64ID)][0]); } @@ -584,10 +539,9 @@ public async Task VerifyUpdateStorageLocationOldDataConflict() Asset? areaAsset = await DataHelper.GetOrCreateAreaAssetAsync(client, Constants.TestAreaAsset); - if (areaAsset == null) + if (areaAsset is null) { Assert.Fail("Failed to retrieve or create the area asset."); - return; } OperationResult operationResult = await dataLayer.CreateAsync(new StorageLocation() @@ -597,7 +551,7 @@ public async Task VerifyUpdateStorageLocationOldDataConflict() OwnerInteger64ID = areaAsset.Integer64ID, }); - if (operationResult.DataObject is StorageLocation firstStorageLocation) + if (operationResult.IsSuccessStatusCode && operationResult.DataObject is StorageLocation firstStorageLocation) { StorageLocation secondStorageLocation = new(firstStorageLocation); @@ -605,12 +559,7 @@ public async Task VerifyUpdateStorageLocationOldDataConflict() secondStorageLocation.LocationB = "Old Data Storage Location Test 2"; operationResult = await dataLayer.UpdateAsync(secondStorageLocation); - - if (!operationResult.IsSuccessStatusCode) - { - Assert.Fail("Failed to update the second storage location."); - return; - } + Assert.True(operationResult.IsSuccessStatusCode, "Failed to update the second storage location."); operationResult = await dataLayer.UpdateAsync(firstStorageLocation); @@ -621,7 +570,6 @@ public async Task VerifyUpdateStorageLocationOldDataConflict() else { Assert.Fail("Failed to create the storage location."); - return; } } } diff --git a/TestProject/Test/WebRequest/Parts/PartUnitTest.cs b/TestProject/Test/WebRequest/Parts/PartUnitTest.cs index 7f20adc..d145dfc 100644 --- a/TestProject/Test/WebRequest/Parts/PartUnitTest.cs +++ b/TestProject/Test/WebRequest/Parts/PartUnitTest.cs @@ -1,6 +1,5 @@ using JMayer.Data.Data; using JMayer.Data.HTTP.DataLayer; -using JMayer.Example.WebAssemblyBlazor.Shared.Data.Assets; using JMayer.Example.WebAssemblyBlazor.Shared.Data.Parts; using JMayer.Example.WebAssemblyBlazor.Shared.HTTP.DataLayer.Parts; using Microsoft.AspNetCore.Mvc.Testing; @@ -39,12 +38,7 @@ public async Task VerifyAddDuplicatePartFailure() PartDataLayer dataLayer = new(client); OperationResult operationResult = await dataLayer.CreateAsync(new Part() { Name = "Add Duplicate Part Test" }); - - if (!operationResult.IsSuccessStatusCode) - { - Assert.Fail("Failed to create the first part."); - return; - } + Assert.True(operationResult.IsSuccessStatusCode, "Failed to create the first part."); operationResult = await dataLayer.CreateAsync(new Part() { Name = "Add Duplicate Part Test" }); @@ -57,11 +51,9 @@ public async Task VerifyAddDuplicatePartFailure() //A bad request status was returned. Assert.Equal(HttpStatusCode.BadRequest, operationResult.StatusCode); - //A validation error was returned. - Assert.Single(operationResult.ValidationErrors); - //The correct error was returned. Assert.Contains(operationResult.ValidationErrors, obj => obj.Key == nameof(Part.Name)); + Assert.Single(operationResult.ValidationErrors[nameof(Part.Name)]); Assert.Contains("name already exists", operationResult.ValidationErrors[nameof(Part.Name)][0]); } @@ -120,7 +112,7 @@ public async Task VerifyDeletePart() OperationResult operationResult = await dataLayer.CreateAsync(new Part() { Name = "Delete Part Test" }); - if (operationResult.DataObject is Part part) + if (operationResult.IsSuccessStatusCode && operationResult.DataObject is Part part) { operationResult = await dataLayer.DeleteAsync(part); Assert.True(operationResult.IsSuccessStatusCode); @@ -208,7 +200,7 @@ public async Task VerifyGetSinglePartWithId() OperationResult operationResult = await dataLayer.CreateAsync(new Part() { Name = "Get Single Part Test" }); - if (operationResult.DataObject is Part createdPart) + if (operationResult.IsSuccessStatusCode && operationResult.DataObject is Part createdPart) { Part? fetchedPart = await dataLayer.GetSingleAsync(createdPart.Integer64ID); Assert.NotNull(fetchedPart); @@ -230,16 +222,11 @@ public async Task VerifyUpdateDuplicatePartFailure() PartDataLayer dataLayer = new(client); OperationResult operationResult = await dataLayer.CreateAsync(new Part() { Name = "Add Duplicate Part Test 1" }); - - if (!operationResult.IsSuccessStatusCode) - { - Assert.Fail("Failed to create the first part."); - return; - } + Assert.True(operationResult.IsSuccessStatusCode, "Failed to create the first part."); operationResult = await dataLayer.CreateAsync(new Part() { Name = "Add Duplicate Part Test 2" }); - if (operationResult.DataObject is Part part) + if (operationResult.IsSuccessStatusCode && operationResult.DataObject is Part part) { part.Name = "Add Duplicate Part Test 1"; operationResult = await dataLayer.UpdateAsync(part); @@ -253,17 +240,14 @@ public async Task VerifyUpdateDuplicatePartFailure() //A bad request status was returned. Assert.Equal(HttpStatusCode.BadRequest, operationResult.StatusCode); - //A validation error was returned. - Assert.Single(operationResult.ValidationErrors); - //The correct error was returned. Assert.Contains(operationResult.ValidationErrors, obj => obj.Key == nameof(Part.Name)); + Assert.Single(operationResult.ValidationErrors[nameof(Part.Name)]); Assert.Contains("name already exists", operationResult.ValidationErrors[nameof(Part.Name)][0]); } else { Assert.Fail("Failed to create the second part."); - return; } } @@ -336,7 +320,7 @@ public async Task VerifyUpdatePartOldDataConflict() Name = "Old Data Part Test", }); - if (operationResult.DataObject is Part firstPart) + if (operationResult.IsSuccessStatusCode && operationResult.DataObject is Part firstPart) { Part secondPart = new(firstPart); @@ -344,12 +328,7 @@ public async Task VerifyUpdatePartOldDataConflict() secondPart.Obsolete = true; operationResult = await dataLayer.UpdateAsync(secondPart); - - if (!operationResult.IsSuccessStatusCode) - { - Assert.Fail("Failed to update the second part."); - return; - } + Assert.True(operationResult.IsSuccessStatusCode, "Failed to update the second part."); operationResult = await dataLayer.UpdateAsync(firstPart); @@ -360,7 +339,6 @@ public async Task VerifyUpdatePartOldDataConflict() else { Assert.Fail("Failed to create the part."); - return; } } } diff --git a/TestProject/Test/WebRequest/Parts/StockUnitTest.cs b/TestProject/Test/WebRequest/Parts/StockUnitTest.cs index 7e8e932..fc1f84d 100644 --- a/TestProject/Test/WebRequest/Parts/StockUnitTest.cs +++ b/TestProject/Test/WebRequest/Parts/StockUnitTest.cs @@ -41,35 +41,27 @@ public async Task VerifyAddDuplicateStockFailure() Asset? areaAsset = await DataHelper.GetOrCreateAreaAssetAsync(client, Constants.TestAreaAsset); - if (areaAsset == null) + if (areaAsset is null) { Assert.Fail("Failed to retrieve or create the area asset."); - return; } StorageLocation? storageLocation = await DataHelper.GetOrCreateStorageLocationAsync(client, Constants.TestStorageLocation, areaAsset.Integer64ID); - if (storageLocation == null) + if (storageLocation is null) { Assert.Fail("Failed to retrieve or create the storage location."); - return; } Part? part = await DataHelper.GetOrCreatePartAsync(client, "Duplicate Stock Test"); - if (part == null) + if (part is null) { Assert.Fail("Failed to retrieve or create the part."); - return; } OperationResult operationResult = await dataLayer.CreateAsync(new Stock() { Amount = 0, Name = "Duplicate Stock Test", OwnerInteger64ID = part.Integer64ID, StorageLocationID = storageLocation.Integer64ID, StorageLocationName = storageLocation.FriendlyName }); - - if (!operationResult.IsSuccessStatusCode) - { - Assert.Fail("Failed to create the first stock."); - return; - } + Assert.True(operationResult.IsSuccessStatusCode, "Failed to create the first stock."); operationResult = await dataLayer.CreateAsync(new Stock() { Amount = 0, Name = "Duplicate Stock Test", OwnerInteger64ID = part.Integer64ID, StorageLocationID = storageLocation.Integer64ID, StorageLocationName = storageLocation.FriendlyName }); @@ -82,11 +74,9 @@ public async Task VerifyAddDuplicateStockFailure() //A bad request status was returned. Assert.Equal(HttpStatusCode.BadRequest, operationResult.StatusCode); - //A validation error was returned. - Assert.Single(operationResult.ValidationErrors); - //The correct error was returned. Assert.Contains(operationResult.ValidationErrors, obj => obj.Key == nameof(Stock.StorageLocationID)); + Assert.Single(operationResult.ValidationErrors[nameof(Stock.StorageLocationID)]); Assert.Contains("stock location already exists", operationResult.ValidationErrors[nameof(Stock.StorageLocationID)][0]); } @@ -108,26 +98,23 @@ public async Task VerifyAddStock(string locationName, string partName, decimal a Asset? areaAsset = await DataHelper.GetOrCreateAreaAssetAsync(client, Constants.TestAreaAsset); - if (areaAsset == null) + if (areaAsset is null) { Assert.Fail("Failed to retrieve or create the area asset."); - return; } StorageLocation? storageLocation = await DataHelper.GetOrCreateStorageLocationAsync(client, locationName, areaAsset.Integer64ID); - if (storageLocation == null) + if (storageLocation is null) { Assert.Fail("Failed to retrieve or create the storage location."); - return; } Part? part = await DataHelper.GetOrCreatePartAsync(client, partName); - if (part == null) + if (part is null) { Assert.Fail("Failed to retrieve or create the part."); - return; } Stock partStock = new() @@ -166,13 +153,13 @@ public async Task VerifyAddStockDependenciesNotExists() //A bad request status was returned. Assert.Equal(HttpStatusCode.BadRequest, operationResult.StatusCode); - //A validation error was returned. - Assert.Equal(2, operationResult.ValidationErrors.Count); - //The correct error was returned. Assert.Contains(operationResult.ValidationErrors, obj => obj.Key == nameof(Stock.OwnerInteger64ID)); + Assert.Single(operationResult.ValidationErrors[nameof(Stock.OwnerInteger64ID)]); Assert.Contains("part was not found", operationResult.ValidationErrors[nameof(Stock.OwnerInteger64ID)][0]); + Assert.Contains(operationResult.ValidationErrors, obj => obj.Key == nameof(Stock.StorageLocationID)); + Assert.Single(operationResult.ValidationErrors[nameof(Stock.StorageLocationID)]); Assert.Contains("storage location was not found", operationResult.ValidationErrors[nameof(Stock.StorageLocationID)][0]); } @@ -202,37 +189,30 @@ public async Task VerifyDeleteAreaAssetCascade() Asset? areaAsset = await DataHelper.GetOrCreateAreaAssetAsync(client, "Cascade Asset-Stock Delete Test"); - if (areaAsset == null) + if (areaAsset is null) { Assert.Fail("Failed to retrieve or create the area asset."); - return; } StorageLocation? storageLocation = await DataHelper.GetOrCreateStorageLocationAsync(client, "Cascade Asset-Stock Delete Test", areaAsset.Integer64ID); - if (storageLocation == null) + if (storageLocation is null) { Assert.Fail("Failed to retrieve or create the storage location."); - return; } Part? part = await DataHelper.GetOrCreatePartAsync(client, Constants.TestPart); - if (part == null) + if (part is null) { Assert.Fail("Failed to retrieve or create the part."); - return; } OperationResult operationResult = await dataLayer.CreateAsync(new Stock() { Amount = 0, Name = "Cascade Asset-Stock Delete Test", OwnerInteger64ID = part.Integer64ID, StorageLocationID = storageLocation.Integer64ID, StorageLocationName = storageLocation.FriendlyName }); + Assert.True(operationResult.IsSuccessStatusCode, "Failed to create the stock."); - if (!operationResult.IsSuccessStatusCode) - { - Assert.Fail("Failed to create the stock."); - return; - } - - await new AssetDataLayer(client).DeleteAsync(areaAsset); + operationResult = await new AssetDataLayer(client).DeleteAsync(areaAsset); + Assert.True(operationResult.IsSuccessStatusCode, "Failed to delete the area asset."); List? stocks = await dataLayer.GetAllAsync(areaAsset.Integer64ID); @@ -253,37 +233,30 @@ public async Task VerifyDeletePartCascade() Asset? areaAsset = await DataHelper.GetOrCreateAreaAssetAsync(client, Constants.TestAreaAsset); - if (areaAsset == null) + if (areaAsset is null) { Assert.Fail("Failed to retrieve or create the area asset."); - return; } StorageLocation? storageLocation = await DataHelper.GetOrCreateStorageLocationAsync(client, Constants.TestStorageLocation, areaAsset.Integer64ID); - if (storageLocation == null) + if (storageLocation is null) { Assert.Fail("Failed to retrieve or create the storage location."); - return; } Part? part = await DataHelper.GetOrCreatePartAsync(client, "Cascade Part-Stock Delete Test"); - if (part == null) + if (part is null) { Assert.Fail("Failed to retrieve or create the part."); - return; } OperationResult operationResult = await dataLayer.CreateAsync(new Stock() { Amount = 0, Name = "Cascade Part-Stock Delete Test", OwnerInteger64ID = part.Integer64ID, StorageLocationID = storageLocation.Integer64ID, StorageLocationName = storageLocation.FriendlyName }); + Assert.True(operationResult.IsSuccessStatusCode, "Failed to create the stock."); - if (!operationResult.IsSuccessStatusCode) - { - Assert.Fail("Failed to create the stock."); - return; - } - - await new PartDataLayer(client).DeleteAsync(part); + operationResult = await new PartDataLayer(client).DeleteAsync(part); + Assert.True(operationResult.IsSuccessStatusCode, "Failed to delete the part."); List? stocks = await dataLayer.GetAllAsync(areaAsset.Integer64ID); @@ -304,31 +277,28 @@ public async Task VerifyDeleteStock() Asset? areaAsset = await DataHelper.GetOrCreateAreaAssetAsync(client, Constants.TestAreaAsset); - if (areaAsset == null) + if (areaAsset is null) { Assert.Fail("Failed to retrieve or create the area asset."); - return; } StorageLocation? storageLocation = await DataHelper.GetOrCreateStorageLocationAsync(client, Constants.TestStorageLocation, areaAsset.Integer64ID); - if (storageLocation == null) + if (storageLocation is null) { Assert.Fail("Failed to retrieve or create the storage location."); - return; } Part? part = await DataHelper.GetOrCreatePartAsync(client, "Delete Stock Test"); - if (part == null) + if (part is null) { Assert.Fail("Failed to retrieve or create the part."); - return; } OperationResult operationResult = await dataLayer.CreateAsync(new Stock() { Amount = 0, Name = "Delete Stock Test", OwnerInteger64ID = part.Integer64ID, StorageLocationID = storageLocation.Integer64ID, StorageLocationName = storageLocation.FriendlyName }); - if (operationResult.DataObject is Stock stock) + if (operationResult.IsSuccessStatusCode && operationResult.DataObject is Stock stock) { operationResult = await dataLayer.DeleteAsync(stock); Assert.True(operationResult.IsSuccessStatusCode); @@ -351,37 +321,30 @@ public async Task VerifyDeleteStorageLocationCascade() Asset? areaAsset = await DataHelper.GetOrCreateAreaAssetAsync(client, Constants.TestAreaAsset); - if (areaAsset == null) + if (areaAsset is null) { Assert.Fail("Failed to retrieve or create the area asset."); - return; } StorageLocation? storageLocation = await DataHelper.GetOrCreateStorageLocationAsync(client, "Cascade Storage Location-Stock Delete Test", areaAsset.Integer64ID); - if (storageLocation == null) + if (storageLocation is null) { Assert.Fail("Failed to retrieve or create the storage location."); - return; } Part? part = await DataHelper.GetOrCreatePartAsync(client, Constants.TestPart); - if (part == null) + if (part is null) { Assert.Fail("Failed to retrieve or create the part."); - return; } OperationResult operationResult = await dataLayer.CreateAsync(new Stock() { Amount = 0, Name = "Cascade Storage Location-Stock Delete Test", OwnerInteger64ID = part.Integer64ID, StorageLocationID = storageLocation.Integer64ID, StorageLocationName = storageLocation.FriendlyName }); + Assert.True(operationResult.IsSuccessStatusCode, "Failed to create the stock."); - if (!operationResult.IsSuccessStatusCode) - { - Assert.Fail("Failed to create the stock."); - return; - } - - await new StorageLocationDataLayer(client).DeleteAsync(storageLocation); + operationResult = await new StorageLocationDataLayer(client).DeleteAsync(storageLocation); + Assert.True(operationResult.IsSuccessStatusCode, "Failed to delete the storage location."); List? stocks = await dataLayer.GetAllAsync(areaAsset.Integer64ID); @@ -485,31 +448,28 @@ public async Task VerifyGetSingleStockWithId() Asset? areaAsset = await DataHelper.GetOrCreateAreaAssetAsync(client, Constants.TestAreaAsset); - if (areaAsset == null) + if (areaAsset is null) { Assert.Fail("Failed to retrieve or create the area asset."); - return; } StorageLocation? storageLocation = await DataHelper.GetOrCreateStorageLocationAsync(client, Constants.TestStorageLocation, areaAsset.Integer64ID); - if (storageLocation == null) + if (storageLocation is null) { Assert.Fail("Failed to retrieve or create the storage location."); - return; } Part? part = await DataHelper.GetOrCreatePartAsync(client, "Get Single Stock Test"); - if (part == null) + if (part is null) { Assert.Fail("Failed to retrieve or create the part."); - return; } OperationResult operationResult = await dataLayer.CreateAsync(new Stock() { Amount = 0, Name = "Get Single Stock Test", OwnerInteger64ID = part.Integer64ID, StorageLocationID = storageLocation.Integer64ID, StorageLocationName = storageLocation.FriendlyName }); - if (operationResult.DataObject is Stock createdPartStock) + if (operationResult.IsSuccessStatusCode && operationResult.DataObject is Stock createdPartStock) { Stock? fetchedPartStock = await dataLayer.GetSingleAsync(createdPartStock.Integer64ID); Assert.NotNull(fetchedPartStock); @@ -532,26 +492,23 @@ public async Task VerifyRenameStorageLocationCascade() Asset? areaAsset = await DataHelper.GetOrCreateAreaAssetAsync(client, Constants.TestAreaAsset); - if (areaAsset == null) + if (areaAsset is null) { Assert.Fail("Failed to retrieve or create the area asset."); - return; } StorageLocation? storageLocation = await DataHelper.GetOrCreateStorageLocationAsync(client, "Rename Storage Location Test", areaAsset.Integer64ID); - if (storageLocation == null) + if (storageLocation is null) { Assert.Fail("Failed to retrieve or create the storage location."); - return; } Part? part = await DataHelper.GetOrCreatePartAsync(client, Constants.TestPart); - if (part == null) + if (part is null) { Assert.Fail("Failed to retrieve or create the part."); - return; } OperationResult operationResult = await dataLayer.CreateAsync(new Stock() @@ -563,16 +520,11 @@ public async Task VerifyRenameStorageLocationCascade() StorageLocationName = storageLocation.FriendlyName, }); - if (operationResult.DataObject is Stock createdPartStock) + if (operationResult.IsSuccessStatusCode && operationResult.DataObject is Stock createdPartStock) { storageLocation.LocationA = "New Storage Location Test"; operationResult = await new StorageLocationDataLayer(client).UpdateAsync(storageLocation); - - if (!operationResult.IsSuccessStatusCode) - { - Assert.Fail("Failed to update the storage location."); - return; - } + Assert.True(operationResult.IsSuccessStatusCode, "Failed to update the storage location."); Stock? fetchedPartStock = await dataLayer.GetSingleAsync(createdPartStock.Integer64ID); @@ -583,7 +535,6 @@ public async Task VerifyRenameStorageLocationCascade() else { Assert.Fail("Failed to create the stock."); - return; } } @@ -605,26 +556,23 @@ public async Task VerifyUpdateStock(string locationName, string partName, decima Asset? areaAsset = await DataHelper.GetOrCreateAreaAssetAsync(client, Constants.TestAreaAsset); - if (areaAsset == null) + if (areaAsset is null) { Assert.Fail("Failed to retrieve or create the area asset."); - return; } StorageLocation? storageLocation = await DataHelper.GetOrCreateStorageLocationAsync(client, locationName, areaAsset.Integer64ID); - if (storageLocation == null) + if (storageLocation is null) { Assert.Fail("Failed to retrieve or create the storage location."); - return; } Part? part = await DataHelper.GetOrCreatePartAsync(client, partName); - if (part == null) + if (part is null) { Assert.Fail("Failed to retrieve or create the part."); - return; } OperationResult operationResult = await dataLayer.CreateAsync(new Stock() @@ -666,26 +614,23 @@ public async Task VerifyUpdateStockDependenciesNotExists() Asset? areaAsset = await DataHelper.GetOrCreateAreaAssetAsync(client, Constants.TestAreaAsset); - if (areaAsset == null) + if (areaAsset is null) { Assert.Fail("Failed to retrieve or create the area asset."); - return; } StorageLocation? storageLocation = await DataHelper.GetOrCreateStorageLocationAsync(client, Constants.TestStorageLocation, areaAsset.Integer64ID); - if (storageLocation == null) + if (storageLocation is null) { Assert.Fail("Failed to retrieve or create the storage location."); - return; } Part? part = await DataHelper.GetOrCreatePartAsync(client, "Update Dependencies Not Exists Stock Test"); - if (part == null) + if (part is null) { Assert.Fail("Failed to retrieve or create the part."); - return; } OperationResult operationResult = await dataLayer.CreateAsync(new Stock() @@ -697,7 +642,7 @@ public async Task VerifyUpdateStockDependenciesNotExists() StorageLocationName = storageLocation.FriendlyName, }); - if (operationResult.DataObject is Stock stock) + if (operationResult.IsSuccessStatusCode && operationResult.DataObject is Stock stock) { stock.OwnerInteger64ID = 0; stock.StorageLocationID = 0; @@ -712,19 +657,18 @@ public async Task VerifyUpdateStockDependenciesNotExists() //A bad request status was returned. Assert.Equal(HttpStatusCode.BadRequest, operationResult.StatusCode); - //A validation error was returned. - Assert.Equal(2, operationResult.ValidationErrors.Count); - //The correct error was returned. Assert.Contains(operationResult.ValidationErrors, obj => obj.Key == nameof(Stock.OwnerInteger64ID)); + Assert.Single(operationResult.ValidationErrors[nameof(Stock.OwnerInteger64ID)]); Assert.Contains("part was not found", operationResult.ValidationErrors[nameof(Stock.OwnerInteger64ID)][0]); + Assert.Contains(operationResult.ValidationErrors, obj => obj.Key == nameof(Stock.StorageLocationID)); + Assert.Single(operationResult.ValidationErrors[nameof(Stock.StorageLocationID)]); Assert.Contains("storage location was not found", operationResult.ValidationErrors[nameof(Stock.StorageLocationID)][0]); } else { Assert.Fail("Failed to create the stock."); - return; } } @@ -740,26 +684,23 @@ public async Task UpdateStockOldDataAsync() Asset? areaAsset = await DataHelper.GetOrCreateAreaAssetAsync(client, Constants.TestAreaAsset); - if (areaAsset == null) + if (areaAsset is null) { Assert.Fail("Failed to retrieve or create the area asset."); - return; } StorageLocation? storageLocation = await DataHelper.GetOrCreateStorageLocationAsync(client, Constants.TestStorageLocation, areaAsset.Integer64ID); - if (storageLocation == null) + if (storageLocation is null) { Assert.Fail("Failed to retrieve or create the storage location."); - return; } Part? part = await DataHelper.GetOrCreatePartAsync(client, "Stock Old Data Test"); - if (part == null) + if (part is null) { Assert.Fail("Failed to retrieve or create the part."); - return; } OperationResult operationResult = await dataLayer.CreateAsync(new Stock() @@ -771,7 +712,7 @@ public async Task UpdateStockOldDataAsync() StorageLocationName = storageLocation.FriendlyName, }); - if (operationResult.DataObject is Stock firstPartStock) + if (operationResult.IsSuccessStatusCode && operationResult.DataObject is Stock firstPartStock) { Stock secondPartStock = new(firstPartStock); @@ -779,12 +720,7 @@ public async Task UpdateStockOldDataAsync() secondPartStock.Amount = 10; operationResult = await dataLayer.UpdateAsync(secondPartStock); - - if (!operationResult.IsSuccessStatusCode) - { - Assert.Fail("Failed to update the second stock."); - return; - } + Assert.True(operationResult.IsSuccessStatusCode, "Failed to update the second stock."); operationResult = await dataLayer.UpdateAsync(firstPartStock); @@ -795,7 +731,6 @@ public async Task UpdateStockOldDataAsync() else { Assert.Fail("Failed to create the stock."); - return; } } } From 09d10a86905e44bd9d9ba20f76959342bfd222e8 Mon Sep 17 00:00:00 2001 From: jmayer913 <72579603+jmayer913@users.noreply.github.com> Date: Sat, 8 Nov 2025 09:17:20 -0500 Subject: [PATCH 08/20] Added more package info --- .../JMayer.Example.WebAssemblyBlazor.Shared.csproj | 3 +++ .../JMayer.Example.WebAssemblyBlazor.Client.csproj | 3 +++ .../JMayer.Example.WebAssemblyBlazor.csproj | 3 +++ 3 files changed, 9 insertions(+) diff --git a/JMayer.Example.WebAssemblyBlazor.Shared/JMayer.Example.WebAssemblyBlazor.Shared.csproj b/JMayer.Example.WebAssemblyBlazor.Shared/JMayer.Example.WebAssemblyBlazor.Shared.csproj index 736eee1..9f439cb 100644 --- a/JMayer.Example.WebAssemblyBlazor.Shared/JMayer.Example.WebAssemblyBlazor.Shared.csproj +++ b/JMayer.Example.WebAssemblyBlazor.Shared/JMayer.Example.WebAssemblyBlazor.Shared.csproj @@ -5,6 +5,9 @@ enable enable 9.0.0 + jmayer913 + jmayer913 + https://github.com/jmayer913/JMayer-Example-WebAssemblyBlazor diff --git a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/JMayer.Example.WebAssemblyBlazor.Client.csproj b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/JMayer.Example.WebAssemblyBlazor.Client.csproj index 7ea057c..c57f068 100644 --- a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/JMayer.Example.WebAssemblyBlazor.Client.csproj +++ b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/JMayer.Example.WebAssemblyBlazor.Client.csproj @@ -7,6 +7,9 @@ true Default 9.0.0 + jmayer913 + jmayer913 + https://github.com/jmayer913/JMayer-Example-WebAssemblyBlazor diff --git a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.csproj b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.csproj index 38d086f..1fe4333 100644 --- a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.csproj +++ b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.csproj @@ -5,6 +5,9 @@ enable enable 9.0.0 + jmayer913 + jmayer913 + https://github.com/jmayer913/JMayer-Example-WebAssemblyBlazor From 312c5309555a25fb61b14c6992c1bbb84553f224 Mon Sep 17 00:00:00 2001 From: jmayer913 <72579603+jmayer913@users.noreply.github.com> Date: Sat, 8 Nov 2025 09:25:00 -0500 Subject: [PATCH 09/20] Removed redundant packages in test project The TestProject references the server and shared projects and those come with packages the TestProject was already referencing. --- TestProject/TestProject.csproj | 4 ---- 1 file changed, 4 deletions(-) diff --git a/TestProject/TestProject.csproj b/TestProject/TestProject.csproj index 66b19a9..0e14ef6 100644 --- a/TestProject/TestProject.csproj +++ b/TestProject/TestProject.csproj @@ -11,10 +11,7 @@ - - - @@ -28,7 +25,6 @@ - From 8c95765e39bbc0c38d2c388168b75dcceeb07dc7 Mon Sep 17 00:00:00 2001 From: jmayer913 <72579603+jmayer913@users.noreply.github.com> Date: Sun, 16 Nov 2025 12:42:39 -0500 Subject: [PATCH 10/20] Turned on old data detection --- .../Database/DataLayer/Assets/AssetDataLayer.cs | 6 +++++- .../Database/DataLayer/Assets/StorageLocationDataLayer.cs | 2 ++ .../Database/DataLayer/Parts/PartDataLayer.cs | 6 +++++- .../Database/DataLayer/Parts/StockDataLayer.cs | 2 ++ 4 files changed, 14 insertions(+), 2 deletions(-) diff --git a/JMayer.Example.WebAssemblyBlazor.Shared/Database/DataLayer/Assets/AssetDataLayer.cs b/JMayer.Example.WebAssemblyBlazor.Shared/Database/DataLayer/Assets/AssetDataLayer.cs index 51cccf6..c35f0e1 100644 --- a/JMayer.Example.WebAssemblyBlazor.Shared/Database/DataLayer/Assets/AssetDataLayer.cs +++ b/JMayer.Example.WebAssemblyBlazor.Shared/Database/DataLayer/Assets/AssetDataLayer.cs @@ -11,7 +11,11 @@ public class AssetDataLayer : StandardCRUDDataLayer, IAssetDataLayer /// /// The default constructor. /// - public AssetDataLayer() => IsUniqueNameRequired = true; + public AssetDataLayer() + { + IsOldDataObjectDetectionEnabled = true; + IsUniqueNameRequired = true; + } /// /// diff --git a/JMayer.Example.WebAssemblyBlazor.Shared/Database/DataLayer/Assets/StorageLocationDataLayer.cs b/JMayer.Example.WebAssemblyBlazor.Shared/Database/DataLayer/Assets/StorageLocationDataLayer.cs index eec481a..8c4daae 100644 --- a/JMayer.Example.WebAssemblyBlazor.Shared/Database/DataLayer/Assets/StorageLocationDataLayer.cs +++ b/JMayer.Example.WebAssemblyBlazor.Shared/Database/DataLayer/Assets/StorageLocationDataLayer.cs @@ -25,6 +25,8 @@ public class StorageLocationDataLayer : StandardSubCRUDDataLayerThe data layer for interacting with assets. public StorageLocationDataLayer(IAssetDataLayer assetDataLayer) { + IsOldDataObjectDetectionEnabled = true; + _assetDataLayer = assetDataLayer; _assetDataLayer.Deleted += AssetDataLayer_Deleted; } diff --git a/JMayer.Example.WebAssemblyBlazor.Shared/Database/DataLayer/Parts/PartDataLayer.cs b/JMayer.Example.WebAssemblyBlazor.Shared/Database/DataLayer/Parts/PartDataLayer.cs index 22865b0..88014ea 100644 --- a/JMayer.Example.WebAssemblyBlazor.Shared/Database/DataLayer/Parts/PartDataLayer.cs +++ b/JMayer.Example.WebAssemblyBlazor.Shared/Database/DataLayer/Parts/PartDataLayer.cs @@ -11,5 +11,9 @@ public class PartDataLayer : StandardCRUDDataLayer, IPartDataLayer /// /// The default constructor. /// - public PartDataLayer() => IsUniqueNameRequired = true; + public PartDataLayer() + { + IsOldDataObjectDetectionEnabled = true; + IsUniqueNameRequired = true; + } } diff --git a/JMayer.Example.WebAssemblyBlazor.Shared/Database/DataLayer/Parts/StockDataLayer.cs b/JMayer.Example.WebAssemblyBlazor.Shared/Database/DataLayer/Parts/StockDataLayer.cs index 7eb11d0..f934d54 100644 --- a/JMayer.Example.WebAssemblyBlazor.Shared/Database/DataLayer/Parts/StockDataLayer.cs +++ b/JMayer.Example.WebAssemblyBlazor.Shared/Database/DataLayer/Parts/StockDataLayer.cs @@ -36,6 +36,8 @@ public class StockDataLayer : StandardSubCRUDDataLayer, IStockDataLayer /// public StockDataLayer(IPartDataLayer partDataLayer, IStorageLocationDataLayer storageLocationDataLayer) { + IsOldDataObjectDetectionEnabled = true; + _partDataLayer = partDataLayer; _partDataLayer.Deleted += PartDataLayer_Deleted; From 252813e790a999639f7f128daf2e9a4943a0c6a6 Mon Sep 17 00:00:00 2001 From: jmayer913 <72579603+jmayer913@users.noreply.github.com> Date: Thu, 20 Nov 2025 16:24:00 -0500 Subject: [PATCH 11/20] Updated .NET Version in Workflow --- .github/workflows/mainworkflow.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/mainworkflow.yml b/.github/workflows/mainworkflow.yml index c8c3466..ba28f55 100644 --- a/.github/workflows/mainworkflow.yml +++ b/.github/workflows/mainworkflow.yml @@ -20,7 +20,7 @@ jobs: - name: Setup .NET uses: actions/setup-dotnet@v4 with: - dotnet-version: 8.0.x + dotnet-version: 9.0.x - name: Restore dependencies run: dotnet restore - name: Build From ff48c1e20e43fe0209f37edd99470f30c99d5fa8 Mon Sep 17 00:00:00 2001 From: jmayer913 <72579603+jmayer913@users.noreply.github.com> Date: Sat, 22 Nov 2025 13:21:47 -0500 Subject: [PATCH 12/20] Did not handle problem details for a delete --- .../Components/Base/SearchBase.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Components/Base/SearchBase.cs b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Components/Base/SearchBase.cs index 1d80359..e5ef80c 100644 --- a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Components/Base/SearchBase.cs +++ b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Components/Base/SearchBase.cs @@ -95,6 +95,10 @@ protected virtual async Task OnDeleteButtonClickAsync(T dataObject) { await MudDataGrid.ReloadServerData(); } + else if (operationResult.ProblemDetails is not null) + { + await DialogService.ShowErrorMessageAsync(operationResult.ProblemDetails); + } else { await DialogService.ShowErrorMessageAsync("Failed to delete the object because of an error on the server."); From 271faf7498801a14b763c1a1e993b039ff43a088 Mon Sep 17 00:00:00 2001 From: jmayer913 <72579603+jmayer913@users.noreply.github.com> Date: Sat, 22 Nov 2025 13:31:39 -0500 Subject: [PATCH 13/20] Code Cleanup --- .../Components/Base/EditableCardBase.cs | 38 ++++++++++--------- .../Components/Base/SearchBase.cs | 4 +- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Components/Base/EditableCardBase.cs b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Components/Base/EditableCardBase.cs index 65b2db8..dd3f6de 100644 --- a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Components/Base/EditableCardBase.cs +++ b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Components/Base/EditableCardBase.cs @@ -88,30 +88,32 @@ protected virtual async Task OnDeleteButtonClickAsync(T dataObject) { bool? result = await DialogService.ShowConfirmActionMessageAsync(); - if (result is true) + if (result is not true) { - try - { - OperationResult operationResult = await DataLayer.DeleteAsync(dataObject); + return; + } - if (operationResult.IsSuccessStatusCode) - { - await MudDataGrid.ReloadServerData(); - } - else if (operationResult.ProblemDetails is not null) - { - await DialogService.ShowErrorMessageAsync(operationResult.ProblemDetails); - } - else - { - await DialogService.ShowErrorMessageAsync("Failed to delete the object because of an error on the server."); - } + try + { + OperationResult operationResult = await DataLayer.DeleteAsync(dataObject); + + if (operationResult.IsSuccessStatusCode) + { + await MudDataGrid.ReloadServerData(); + } + else if (operationResult.ProblemDetails is not null) + { + await DialogService.ShowErrorMessageAsync(operationResult.ProblemDetails); } - catch + else { - await DialogService.ShowErrorMessageAsync("Failed to communicate with the server."); + await DialogService.ShowErrorMessageAsync("Failed to delete the object because of an error on the server."); } } + catch + { + await DialogService.ShowErrorMessageAsync("Failed to communicate with the server."); + } } /// diff --git a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Components/Base/SearchBase.cs b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Components/Base/SearchBase.cs index e5ef80c..27c2962 100644 --- a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Components/Base/SearchBase.cs +++ b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Components/Base/SearchBase.cs @@ -115,9 +115,7 @@ protected virtual async Task OnDeleteButtonClickAsync(T dataObject) /// /// The data object to inspect. protected virtual void OnEditButtonClick(T dataObject) - { - NavigationManager.NavigateTo($"/{DataObjectTypeName}/{dataObject.Integer64ID}"); - } + => NavigationManager.NavigateTo($"/{DataObjectTypeName}/{dataObject.Integer64ID}"); /// /// The method opens a dialog for creating a new data object and if not canceled, refreshes the data grid. From 61f768db40952618edd3ab3b2600918610b8a9d0 Mon Sep 17 00:00:00 2001 From: jmayer913 <72579603+jmayer913@users.noreply.github.com> Date: Sat, 22 Nov 2025 14:10:55 -0500 Subject: [PATCH 14/20] Fixed missing storage location name Added various constants to the example builder. --- .../Database/BHSExampleBuilder.cs | 110 ++++++++++++++---- 1 file changed, 87 insertions(+), 23 deletions(-) diff --git a/JMayer.Example.WebAssemblyBlazor.Shared/Database/BHSExampleBuilder.cs b/JMayer.Example.WebAssemblyBlazor.Shared/Database/BHSExampleBuilder.cs index b5a9f94..5514758 100644 --- a/JMayer.Example.WebAssemblyBlazor.Shared/Database/BHSExampleBuilder.cs +++ b/JMayer.Example.WebAssemblyBlazor.Shared/Database/BHSExampleBuilder.cs @@ -16,26 +16,86 @@ public class BHSExampleBuilder /// public IAssetDataLayer AssetDataLayer { get; set; } + /// + /// The constant for the ATR category name. + /// + private const string AtrCategoryName = "ATR"; + + /// + /// The constant for the bag room category name. + /// + private const string BagRoomCategoryName = "Bag Room"; + + /// + /// The constant for the belt category name. + /// + private const string BeltCategoryName = "Belt"; + + /// + /// The constant for the conveyor category name. + /// + private const string ConveyorCategoryName = "Conveyor"; + + /// + /// The constant for the diverter category name. + /// + private const string DiverterCategoryName = "Diverter"; + + /// + /// The constant for the electrical contact category name. + /// + private const string ElectricalContactCategoryName = "Electrical Contact"; + /// /// The constant for the main part storage area asset name. /// public const string MainPartStorageAreaAssetName = "Main Part Storage"; + /// + /// The constant for the conveyor length for the main sortation subsystem. + /// + private const int MainSortationConveyorLength = 15; + + /// + /// The constant for the conveyor length for the makeup unit subsystem. + /// + private const int MakeupUnitConveyorLength = 6; + + /// + /// The constant for the motor category name. + /// + private const string MotorCategoryName = "Motor"; + /// /// The property gets/sets the data layer used to interact with parts. /// public IPartDataLayer PartDataLayer { get; set; } + /// + /// The constant for the photoeye category name. + /// + private const string PhotoeyeCategoryName = "Photoeye"; + /// /// The property gets/sets the data layer used to interact with part stock. /// public IStockDataLayer StockDataLayer { get; set; } + /// + /// The constant for the storage category name. + /// + private const string StorageCategoryName = "Storage"; + /// /// The property gets/sets the data layer used to interact with asset storage locations. /// public IStorageLocationDataLayer StorageLocationDataLayer { get; set; } + /// + /// The constant for the subsystem category name. + /// + private const string SubSystemCategoryName = "SubSystem"; + /// /// The default constructor. /// @@ -65,15 +125,15 @@ private void BuildAssets() { Asset bagRoomAsset = AssetDataLayer.CreateAsync(new Asset() { - Category = "Bag Room", + Category = BagRoomCategoryName, Description = "The main bag room for the BHS.", - Name = "Main Bag Room", + Name = $"Main Bag Room", Type = AssetType.Group, }).Result; Asset asset = AssetDataLayer.CreateAsync(new Asset() { - Category = "SubSystem", + Category = SubSystemCategoryName, Description = "The main sortation line for the bag room.", Name = "MS1", ParentID = bagRoomAsset.Integer64ID, @@ -82,7 +142,7 @@ private void BuildAssets() _ = AssetDataLayer.CreateAsync(new Asset() { - Category = "ATR", + Category = AtrCategoryName, Description = "The scanner array for reading bags on the main sortation line.", Name = "MS1-ATR", ParentID = asset.Integer64ID, @@ -90,11 +150,11 @@ private void BuildAssets() Type = AssetType.Equipment, }); - for (int index = 1; index <= 15; index++) + for (int index = 1; index <= MainSortationConveyorLength; index++) { _ = AssetDataLayer.CreateAsync(new Asset() { - Category = "Conveyor", + Category = ConveyorCategoryName, Description = "The conveyor which makes up the main sortation line.", Name = $"MS1-{index:00}", ParentID = asset.Integer64ID, @@ -105,7 +165,7 @@ private void BuildAssets() asset = AssetDataLayer.CreateAsync(new Asset() { - Category = "SubSystem", + Category = SubSystemCategoryName, Description = "The one of the destination lines for the bag room.", Name = "MU1", ParentID = bagRoomAsset.Integer64ID, @@ -114,7 +174,7 @@ private void BuildAssets() _ = AssetDataLayer.CreateAsync(new Asset() { - Category = "Diverter", + Category = DiverterCategoryName, Description = "The diverter which pushes bags onto the MU1 destination line.", Name = "MU1-DIV", ParentID = asset.Integer64ID, @@ -122,11 +182,11 @@ private void BuildAssets() Type = AssetType.Equipment, }); - for (int index = 1; index <= 6; index++) + for (int index = 1; index <= MakeupUnitConveyorLength; index++) { _ = AssetDataLayer.CreateAsync(new Asset() { - Category = "Conveyor", + Category = ConveyorCategoryName, Description = "The conveyor which makes up the MU1 destination line.", Name = $"MU1-{index:00}", ParentID = asset.Integer64ID, @@ -137,7 +197,7 @@ private void BuildAssets() asset = AssetDataLayer.CreateAsync(new Asset() { - Category = "SubSystem", + Category = SubSystemCategoryName, Description = "The one of the destination lines for the bag room.", Name = "MU2", ParentID = bagRoomAsset.Integer64ID, @@ -146,7 +206,7 @@ private void BuildAssets() _ = AssetDataLayer.CreateAsync(new Asset() { - Category = "Diverter", + Category = DiverterCategoryName, Description = "The diverter which pushes bags onto the MU2 destination line.", Name = "MU2-DIV", ParentID = asset.Integer64ID, @@ -154,11 +214,11 @@ private void BuildAssets() Type = AssetType.Equipment, }); - for (int index = 1; index <= 6; index++) + for (int index = 1; index <= MakeupUnitConveyorLength; index++) { _ = AssetDataLayer.CreateAsync(new Asset() { - Category = "Conveyor", + Category = ConveyorCategoryName, Description = "The conveyor which makes up the MU2 destination line.", Name = $"MU2-{index:00}", ParentID = asset.Integer64ID, @@ -169,18 +229,18 @@ private void BuildAssets() asset = AssetDataLayer.CreateAsync(new Asset() { - Category = "SubSystem", + Category = SubSystemCategoryName, Description = "The runout line for the bag room.", Name = "MU3", ParentID = bagRoomAsset.Integer64ID, Type = AssetType.Group, }).Result; - for (int index = 1; index <= 6; index++) + for (int index = 1; index <= MakeupUnitConveyorLength; index++) { _ = AssetDataLayer.CreateAsync(new Asset() { - Category = "Conveyor", + Category = ConveyorCategoryName, Description = "The conveyor which makes up the MU3 destination line.", Name = $"MU3-{index:00}", ParentID = asset.Integer64ID, @@ -197,22 +257,22 @@ private void BuildParts() { _ = PartDataLayer.CreateAsync(new Part() { - Category = "Belt", + Category = BeltCategoryName, Name = "Power Turn Belt", }); _ = PartDataLayer.CreateAsync(new Part() { - Category = "Contact", + Category = ElectricalContactCategoryName, Name = "Motor Contactor", }); _ = PartDataLayer.CreateAsync(new Part() { - Category = "Motor", + Category = MotorCategoryName, Name = "Motor 1HP Drive", }); _ = PartDataLayer.CreateAsync(new Part() { - Category = "Photoeye", + Category = PhotoeyeCategoryName, Name = "Photoeye, Polarized Retro Reflective", }); } @@ -247,19 +307,20 @@ private void BuildStorageLocations() { Asset asset = AssetDataLayer.CreateAsync(new Asset() { - Category = "Storage", + Category = StorageCategoryName, Description = "The main part storage for the BHS.", Name = MainPartStorageAreaAssetName, Type = AssetType.Area, }).Result; - StorageLocation storageLocation = new StorageLocation() + StorageLocation storageLocation = new() { LocationA = "A1", LocationB = "R1", LocationC = "S1", OwnerInteger64ID = asset.Integer64ID, }; + storageLocation.Name = storageLocation.FriendlyName; _ = StorageLocationDataLayer.CreateAsync(storageLocation); storageLocation = new StorageLocation() @@ -269,6 +330,7 @@ private void BuildStorageLocations() LocationC = "S2", OwnerInteger64ID = asset.Integer64ID, }; + storageLocation.Name = storageLocation.FriendlyName; _ = StorageLocationDataLayer.CreateAsync(storageLocation); storageLocation = new StorageLocation() @@ -278,6 +340,7 @@ private void BuildStorageLocations() LocationC = "S1", OwnerInteger64ID = asset.Integer64ID, }; + storageLocation.Name = storageLocation.FriendlyName; _ = StorageLocationDataLayer.CreateAsync(storageLocation); storageLocation = new StorageLocation() @@ -287,6 +350,7 @@ private void BuildStorageLocations() LocationC = "S2", OwnerInteger64ID = asset.Integer64ID, }; + storageLocation.Name = storageLocation.FriendlyName; _ = StorageLocationDataLayer.CreateAsync(storageLocation); } } From 89a85db9b886cfce14f6113091901e5797986be0 Mon Sep 17 00:00:00 2001 From: jmayer913 <72579603+jmayer913@users.noreply.github.com> Date: Sat, 22 Nov 2025 15:34:35 -0500 Subject: [PATCH 15/20] Validation was not showing for storage location --- .../Data/Parts/Stock.cs | 1 + .../Pages/Parts/Dialogs/StockDialog.razor | 6 +-- .../Pages/Parts/Dialogs/StockDialogBase.cs | 47 ++++++------------- 3 files changed, 18 insertions(+), 36 deletions(-) diff --git a/JMayer.Example.WebAssemblyBlazor.Shared/Data/Parts/Stock.cs b/JMayer.Example.WebAssemblyBlazor.Shared/Data/Parts/Stock.cs index ccb0f14..7c7641c 100644 --- a/JMayer.Example.WebAssemblyBlazor.Shared/Data/Parts/Stock.cs +++ b/JMayer.Example.WebAssemblyBlazor.Shared/Data/Parts/Stock.cs @@ -22,6 +22,7 @@ public class Stock : SubDataObject /// The property gets/sets the id for the storage location the part is stored at. /// [Required] + [Range(1, long.MaxValue, ErrorMessage = "The Storage Location field is required.")] public long StorageLocationID { get; set; } /// diff --git a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Pages/Parts/Dialogs/StockDialog.razor b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Pages/Parts/Dialogs/StockDialog.razor index 40df8cc..852004d 100644 --- a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Pages/Parts/Dialogs/StockDialog.razor +++ b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Pages/Parts/Dialogs/StockDialog.razor @@ -11,11 +11,11 @@ @if (IsNewRecord) { - + } - else if (SelectedStorageLocation != null) + else { - + } diff --git a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Pages/Parts/Dialogs/StockDialogBase.cs b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Pages/Parts/Dialogs/StockDialogBase.cs index fb6d8ca..98938a6 100644 --- a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Pages/Parts/Dialogs/StockDialogBase.cs +++ b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Pages/Parts/Dialogs/StockDialogBase.cs @@ -13,11 +13,6 @@ namespace JMayer.Example.WebAssemblyBlazor.Client.Pages.Parts.Dialogs; /// public class StockDialogBase : CardDialogBase { - /// - /// The selected storage location. - /// - private ListView? _selectedStorageLocation; - /// /// The property gets/sets the data layer needed to access storage locations. /// @@ -29,21 +24,6 @@ public class StockDialogBase : CardDialogBase /// protected List StorageLocations { get; set; } = []; - /// - /// The property gets/sets the storage location which the user selected. - /// - protected ListView? SelectedStorageLocation - { - get => _selectedStorageLocation; - set - { - _selectedStorageLocation = value; - //Map any selection changes to the StorageLocationId and StorageLocationName property. - DataObject.StorageLocationID = value?.Integer64ID ?? 0; - DataObject.StorageLocationName = value?.Name ?? string.Empty; - } - } - /// /// The method sets up the component after the parameters are set. /// @@ -53,16 +33,6 @@ protected override async Task OnParametersSetAsync() try { StorageLocations = await StorageLocationDataLayer.GetAllListViewAsync() ?? []; - - if (IsNewRecord is false) - { - ListView? storageLocation = StorageLocations.FirstOrDefault(obj => obj.Integer64ID == DataObject.StorageLocationID); - - if (storageLocation is not null) - { - SelectedStorageLocation = storageLocation; - } - } } catch { @@ -78,15 +48,26 @@ protected override async Task OnParametersSetAsync() /// The value to search for. /// Used to cancel the task. /// A list of acceptable categories. - protected async Task> OnStorageLocationAutoCompleteSearchAsync(string value, CancellationToken cancellationToken) + protected async Task> OnStorageLocationAutoCompleteSearchAsync(string value, CancellationToken cancellationToken) { + await Task.Delay(1); + if (string.IsNullOrWhiteSpace(value)) { - return await Task.FromResult(StorageLocations); + return await Task.FromResult(StorageLocations.Select(obj => obj.Integer64ID)); } else { - return await Task.FromResult(StorageLocations.Where(obj => obj.Name.Contains(value))); + return await Task.FromResult(StorageLocations.Where(obj => obj.Name.Contains(value)).Select(obj => obj.Integer64ID)); } } + + /// + /// Overridden so the stock's StorageLocationName is updated before it's submitted to the server. + protected override async Task OnSubmitEditFormAsync() + { + ListView? selected = StorageLocations.FirstOrDefault(obj => obj.Integer64ID == DataObject.StorageLocationID); + DataObject.StorageLocationName = selected?.Name ?? string.Empty; + await base.OnSubmitEditFormAsync(); + } } From cf4a6d2cf72e4450af47356c1d5dcbbcd6d775ab Mon Sep 17 00:00:00 2001 From: jmayer913 <72579603+jmayer913@users.noreply.github.com> Date: Sat, 22 Nov 2025 15:49:44 -0500 Subject: [PATCH 16/20] Changed the parent autocomplete bindings Learned how to bind directly to the data object instead of binding to a property on the component. --- .../Pages/Assets/Cards/OverviewCard.razor | 2 +- .../Pages/Assets/Cards/OverviewCardBase.cs | 35 ++----------------- .../Pages/Assets/Dialogs/NewAssetDialog.razor | 2 +- .../Assets/Dialogs/NewAssetDialogBase.cs | 27 +++----------- .../Pages/Parts/Dialogs/StockDialogBase.cs | 4 +-- 5 files changed, 10 insertions(+), 60 deletions(-) diff --git a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Pages/Assets/Cards/OverviewCard.razor b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Pages/Assets/Cards/OverviewCard.razor index b94e5b0..ba68ac9 100644 --- a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Pages/Assets/Cards/OverviewCard.razor +++ b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Pages/Assets/Cards/OverviewCard.razor @@ -23,7 +23,7 @@ - + diff --git a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Pages/Assets/Cards/OverviewCardBase.cs b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Pages/Assets/Cards/OverviewCardBase.cs index 0611ddd..ab05fb7 100644 --- a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Pages/Assets/Cards/OverviewCardBase.cs +++ b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Pages/Assets/Cards/OverviewCardBase.cs @@ -10,11 +10,6 @@ namespace JMayer.Example.WebAssemblyBlazor.Client.Pages.Assets.Cards; /// public class OverviewCardBase : Components.Base.OverviewCardBase { - /// - /// The selected asset parent. - /// - private ListView? _selectedAssetParent; - /// /// The property gets/sets the categories for the parts. /// @@ -25,20 +20,6 @@ public class OverviewCardBase : Components.Base.OverviewCardBase protected List ParentAssets { get; set; } = []; - /// - /// The property gets/sets the parent asset which the user selected. - /// - protected ListView? SelectedAssetParent - { - get => _selectedAssetParent; - set - { - _selectedAssetParent = value; - //Map any selection changes to the ParentID property. - DataObject.ParentID = value?.Integer64ID ?? 0; - } - } - /// /// The method sets up the component after the parameters are set. /// @@ -59,16 +40,6 @@ protected override async Task OnParametersSetAsync() Categories = categoryTask.Result ?? []; ParentAssets = parentAssetTask.Result ?? []; - - if (DataObject.ParentID is not null) - { - ListView? parent = ParentAssets.FirstOrDefault(obj => obj.Integer64ID == DataObject.ParentID); - - if (parent is not null) - { - SelectedAssetParent = parent; - } - } await base.OnParametersSetAsync(); } @@ -79,15 +50,15 @@ protected override async Task OnParametersSetAsync() /// The value to search for. /// Used to cancel the task. /// A list of acceptable categories. - protected async Task> OnAssetParentAutoCompleteSearchAsync(string value, CancellationToken cancellationToken) + protected async Task> OnAssetParentAutoCompleteSearchAsync(string value, CancellationToken cancellationToken) { if (string.IsNullOrWhiteSpace(value)) { - return await Task.FromResult(ParentAssets); + return await Task.FromResult(ParentAssets.Select(obj => (long?)obj.Integer64ID)); } else { - return await Task.FromResult(ParentAssets.Where(obj => obj.Name.Contains(value))); + return await Task.FromResult(ParentAssets.Where(obj => obj.Name.Contains(value)).Select(obj => (long?)obj.Integer64ID)); } } diff --git a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Pages/Assets/Dialogs/NewAssetDialog.razor b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Pages/Assets/Dialogs/NewAssetDialog.razor index b84e4f4..79da723 100644 --- a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Pages/Assets/Dialogs/NewAssetDialog.razor +++ b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Pages/Assets/Dialogs/NewAssetDialog.razor @@ -16,7 +16,7 @@ Group Equipment - + diff --git a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Pages/Assets/Dialogs/NewAssetDialogBase.cs b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Pages/Assets/Dialogs/NewAssetDialogBase.cs index 102ec14..3d758f4 100644 --- a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Pages/Assets/Dialogs/NewAssetDialogBase.cs +++ b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Pages/Assets/Dialogs/NewAssetDialogBase.cs @@ -11,11 +11,6 @@ namespace JMayer.Example.WebAssemblyBlazor.Client.Pages.Assets.Dialogs; /// public class NewAssetDialogBase : NewDialogBase { - /// - /// The selected asset parent. - /// - private ListView? _selectedAssetParent; - /// /// The property gets/sets the categories for the parts. /// @@ -26,20 +21,6 @@ public class NewAssetDialogBase : NewDialogBase /// protected List ParentAssets { get; set; } = []; - /// - /// The property gets/sets the parent asset which the user selected. - /// - protected ListView? SelectedAssetParent - { - get => _selectedAssetParent; - set - { - _selectedAssetParent = value; - //Map any selection changes to the ParentID property. - DataObject.ParentID = value?.Integer64ID ?? 0; - } - } - /// /// The method sets up the component after the parameters are set. /// @@ -69,16 +50,16 @@ protected override async Task OnParametersSetAsync() /// /// The value to search for. /// Used to cancel the task. - /// A list of acceptable categories. - protected async Task> OnAssetParentAutoCompleteSearchAsync(string value, CancellationToken cancellationToken) + /// A list of acceptable parent assets. + protected async Task> OnAssetParentAutoCompleteSearchAsync(string value, CancellationToken cancellationToken) { if (string.IsNullOrWhiteSpace(value)) { - return await Task.FromResult(ParentAssets); + return await Task.FromResult(ParentAssets.Select(obj => (long?)obj.Integer64ID)); } else { - return await Task.FromResult(ParentAssets.Where(obj => obj.Name.Contains(value))); + return await Task.FromResult(ParentAssets.Where(obj => obj.Name.Contains(value)).Select(obj => (long?)obj.Integer64ID)); } } diff --git a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Pages/Parts/Dialogs/StockDialogBase.cs b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Pages/Parts/Dialogs/StockDialogBase.cs index 98938a6..0ee118b 100644 --- a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Pages/Parts/Dialogs/StockDialogBase.cs +++ b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Pages/Parts/Dialogs/StockDialogBase.cs @@ -47,11 +47,9 @@ protected override async Task OnParametersSetAsync() /// /// The value to search for. /// Used to cancel the task. - /// A list of acceptable categories. + /// A list of acceptable storage locations. protected async Task> OnStorageLocationAutoCompleteSearchAsync(string value, CancellationToken cancellationToken) { - await Task.Delay(1); - if (string.IsNullOrWhiteSpace(value)) { return await Task.FromResult(StorageLocations.Select(obj => obj.Integer64ID)); From 9bbbfbe8871b3a38ea241088a7f7ed4734389477 Mon Sep 17 00:00:00 2001 From: jmayer913 <72579603+jmayer913@users.noreply.github.com> Date: Sat, 22 Nov 2025 15:58:06 -0500 Subject: [PATCH 17/20] Fixed validation not clearing on reset --- .../Components/Base/OverviewCardBase.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Components/Base/OverviewCardBase.cs b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Components/Base/OverviewCardBase.cs index 2e46171..b3cf707 100644 --- a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Components/Base/OverviewCardBase.cs +++ b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/Components/Base/OverviewCardBase.cs @@ -75,8 +75,9 @@ protected override void OnParametersSet() /// protected virtual void OnResetClick() { + //For some reason, EditContext.MarkAsUnmodified() does not work and I need to recreate the EditContext. DataObject.MapProperties(OriginalDataObject); - EditContext.MarkAsUnmodified(); + EditContext = new EditContext(DataObject); } /// From 74f76c45a29ebf825b2054a0ec5cae6aa95f6a06 Mon Sep 17 00:00:00 2001 From: jmayer913 <72579603+jmayer913@users.noreply.github.com> Date: Mon, 24 Nov 2025 15:26:48 -0500 Subject: [PATCH 18/20] Fixed storage location doesn't exist test To fix a UI validation required issue, I had to add a range data annotation to Stock.StorageLocationID which made 0 invalid. The unit test which tests the storage location not existing is setting the property to 0 so had to use a different number. --- TestProject/Test/WebRequest/Parts/StockUnitTest.cs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/TestProject/Test/WebRequest/Parts/StockUnitTest.cs b/TestProject/Test/WebRequest/Parts/StockUnitTest.cs index fc1f84d..5a9d6d7 100644 --- a/TestProject/Test/WebRequest/Parts/StockUnitTest.cs +++ b/TestProject/Test/WebRequest/Parts/StockUnitTest.cs @@ -18,6 +18,11 @@ namespace TestProject.Test.WebRequest.Parts; /// public class StockUnitTest : IClassFixture> { + /// + /// The constant for the bad storage location ID. + /// + private const int BadStorageLocationID = 99; + /// /// The factory for the web application. /// @@ -142,7 +147,7 @@ public async Task VerifyAddStockDependenciesNotExists() HttpClient client = _factory.CreateClient(); StockDataLayer dataLayer = new(client); - OperationResult operationResult = await dataLayer.CreateAsync(new Stock() { Amount = 0, Name = "Add Dependencies Not Exists Stock Test", OwnerInteger64ID = 0, StorageLocationID = 0 }); + OperationResult operationResult = await dataLayer.CreateAsync(new Stock() { Amount = 0, Name = "Add Dependencies Not Exists Stock Test", OwnerInteger64ID = 0, StorageLocationID = BadStorageLocationID }); //The operation must have failed. Assert.False(operationResult.IsSuccessStatusCode, "The operation should have failed."); @@ -645,7 +650,7 @@ public async Task VerifyUpdateStockDependenciesNotExists() if (operationResult.IsSuccessStatusCode && operationResult.DataObject is Stock stock) { stock.OwnerInteger64ID = 0; - stock.StorageLocationID = 0; + stock.StorageLocationID = BadStorageLocationID; operationResult = await dataLayer.UpdateAsync(stock); //The operation must have failed. From af7b643143c939e658a988f90141a45834f44222 Mon Sep 17 00:00:00 2001 From: jmayer913 <72579603+jmayer913@users.noreply.github.com> Date: Mon, 24 Nov 2025 15:35:48 -0500 Subject: [PATCH 19/20] Updated the Packages --- .../JMayer.Example.WebAssemblyBlazor.Client.csproj | 6 +++--- .../JMayer.Example.WebAssemblyBlazor.csproj | 6 +++--- TestProject/TestProject.csproj | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/JMayer.Example.WebAssemblyBlazor.Client.csproj b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/JMayer.Example.WebAssemblyBlazor.Client.csproj index c57f068..db25016 100644 --- a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/JMayer.Example.WebAssemblyBlazor.Client.csproj +++ b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.Client/JMayer.Example.WebAssemblyBlazor.Client.csproj @@ -13,9 +13,9 @@ - - - + + + diff --git a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.csproj b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.csproj index 1fe4333..d1d640b 100644 --- a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.csproj +++ b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.csproj @@ -14,9 +14,9 @@ - - - + + + diff --git a/TestProject/TestProject.csproj b/TestProject/TestProject.csproj index 0e14ef6..8b7c67e 100644 --- a/TestProject/TestProject.csproj +++ b/TestProject/TestProject.csproj @@ -11,8 +11,8 @@ - - + + runtime; build; native; contentfiles; analyzers; buildtransitive From 45adb5f238e8aaa9b86211ea903f45cd39c3de5d Mon Sep 17 00:00:00 2001 From: jmayer913 <72579603+jmayer913@users.noreply.github.com> Date: Tue, 23 Dec 2025 14:50:36 -0500 Subject: [PATCH 20/20] Switched back to package reference --- .../JMayer.Example.WebAssemblyBlazor.Shared.csproj | 2 +- JMayer.Example.WebAssemblyBlazor.sln | 12 ------------ .../JMayer.Example.WebAssemblyBlazor.csproj | 2 +- 3 files changed, 2 insertions(+), 14 deletions(-) diff --git a/JMayer.Example.WebAssemblyBlazor.Shared/JMayer.Example.WebAssemblyBlazor.Shared.csproj b/JMayer.Example.WebAssemblyBlazor.Shared/JMayer.Example.WebAssemblyBlazor.Shared.csproj index 9f439cb..4533e2c 100644 --- a/JMayer.Example.WebAssemblyBlazor.Shared/JMayer.Example.WebAssemblyBlazor.Shared.csproj +++ b/JMayer.Example.WebAssemblyBlazor.Shared/JMayer.Example.WebAssemblyBlazor.Shared.csproj @@ -11,7 +11,7 @@ - + diff --git a/JMayer.Example.WebAssemblyBlazor.sln b/JMayer.Example.WebAssemblyBlazor.sln index 2fba71e..6e5eddd 100644 --- a/JMayer.Example.WebAssemblyBlazor.sln +++ b/JMayer.Example.WebAssemblyBlazor.sln @@ -11,10 +11,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JMayer.Example.WebAssemblyB EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestProject", "TestProject\TestProject.csproj", "{C0DD761B-7F78-45DF-A25D-6D022212C839}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JMayer.Data", "..\JMayer-Data-Library\JMayer.Data\JMayer.Data.csproj", "{5E2E9979-417E-9AC0-DE5B-ED439D651066}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JMayer.Web.Mvc", "..\JMayer-Web-Mvc-Library\JMayer.Web.Mvc\JMayer.Web.Mvc.csproj", "{185EFF51-282E-8F0A-7CE5-41B2029C51D3}" -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -37,14 +33,6 @@ Global {C0DD761B-7F78-45DF-A25D-6D022212C839}.Debug|Any CPU.Build.0 = Debug|Any CPU {C0DD761B-7F78-45DF-A25D-6D022212C839}.Release|Any CPU.ActiveCfg = Release|Any CPU {C0DD761B-7F78-45DF-A25D-6D022212C839}.Release|Any CPU.Build.0 = Release|Any CPU - {5E2E9979-417E-9AC0-DE5B-ED439D651066}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {5E2E9979-417E-9AC0-DE5B-ED439D651066}.Debug|Any CPU.Build.0 = Debug|Any CPU - {5E2E9979-417E-9AC0-DE5B-ED439D651066}.Release|Any CPU.ActiveCfg = Release|Any CPU - {5E2E9979-417E-9AC0-DE5B-ED439D651066}.Release|Any CPU.Build.0 = Release|Any CPU - {185EFF51-282E-8F0A-7CE5-41B2029C51D3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {185EFF51-282E-8F0A-7CE5-41B2029C51D3}.Debug|Any CPU.Build.0 = Debug|Any CPU - {185EFF51-282E-8F0A-7CE5-41B2029C51D3}.Release|Any CPU.ActiveCfg = Release|Any CPU - {185EFF51-282E-8F0A-7CE5-41B2029C51D3}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.csproj b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.csproj index d1d640b..a513fd0 100644 --- a/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.csproj +++ b/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor/JMayer.Example.WebAssemblyBlazor.csproj @@ -11,9 +11,9 @@ - +