Skip to content

Commit 4a400c8

Browse files
OperationResults enhancements and Extensions
1 parent 28fd3d1 commit 4a400c8

4 files changed

Lines changed: 132 additions & 93 deletions

File tree

src/OneBitSoftware.Utilities.OperationResult.sln

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@ Microsoft Visual Studio Solution File, Format Version 12.00
33
# Visual Studio Version 17
44
VisualStudioVersion = 17.1.32228.430
55
MinimumVisualStudioVersion = 10.0.40219.1
6-
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OneBitSoftware.Utilities.OperationResult", "OneBitSoftware.Utilities.OperationResult\OneBitSoftware.Utilities.OperationResult.csproj", "{ACC326A2-84FE-4C2A-92C4-F785E34F9F60}"
6+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OneBitSoftware.Utilities.OperationResult", "OneBitSoftware.Utilities.OperationResult\OneBitSoftware.Utilities.OperationResult.csproj", "{ACC326A2-84FE-4C2A-92C4-F785E34F9F60}"
7+
EndProject
8+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OneBitSoftware.Utilities.OperationResultTests", "..\tests\OneBitSoftware.Utilities.OperationResultTests\OneBitSoftware.Utilities.OperationResultTests.csproj", "{142313C6-5DC0-4428-AE63-487B8D41552E}"
79
EndProject
810
Global
911
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -15,6 +17,10 @@ Global
1517
{ACC326A2-84FE-4C2A-92C4-F785E34F9F60}.Debug|Any CPU.Build.0 = Debug|Any CPU
1618
{ACC326A2-84FE-4C2A-92C4-F785E34F9F60}.Release|Any CPU.ActiveCfg = Release|Any CPU
1719
{ACC326A2-84FE-4C2A-92C4-F785E34F9F60}.Release|Any CPU.Build.0 = Release|Any CPU
20+
{142313C6-5DC0-4428-AE63-487B8D41552E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
21+
{142313C6-5DC0-4428-AE63-487B8D41552E}.Debug|Any CPU.Build.0 = Debug|Any CPU
22+
{142313C6-5DC0-4428-AE63-487B8D41552E}.Release|Any CPU.ActiveCfg = Release|Any CPU
23+
{142313C6-5DC0-4428-AE63-487B8D41552E}.Release|Any CPU.Build.0 = Release|Any CPU
1824
EndGlobalSection
1925
GlobalSection(SolutionProperties) = preSolution
2026
HideSolutionNode = FALSE

src/OneBitSoftware.Utilities.OperationResult/Errors/OperationError.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
namespace OneBitSoftware.Utilities.OperationResult.Errors;
1+
namespace OneBitSoftware.Utilities.Errors;
22

33
using System.Text;
44

src/OneBitSoftware.Utilities.OperationResult/OperationResult.cs

Lines changed: 28 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
namespace OneBitSoftware.Utilities.OperationResult
1+
namespace OneBitSoftware.Utilities
22
{
3-
using Microsoft.Extensions.Logging;
4-
using OneBitSoftware.Utilities.OperationResult.Errors;
53
using System;
64
using System.Collections.Generic;
75
using System.Linq;
6+
using Microsoft.Extensions.Logging;
7+
using OneBitSoftware.Utilities.Errors;
88

99
/// <summary>
1010
/// A class for a system operation result.
@@ -82,7 +82,7 @@ public void AppendErrors(OperationResult otherOperationResult)
8282
if (otherOperationResult is null) return;
8383

8484
// Append the error message without logging (presuming that there is already a log message).
85-
foreach (var error in otherOperationResult.Errors) this.AppendError(error);
85+
foreach (var error in otherOperationResult.Errors) this.AppendErrorInternal(error);
8686
}
8787

8888
/// <summary>
@@ -132,91 +132,6 @@ public OperationResult AppendException(Exception exception, int errorCode = 0, L
132132
return this;
133133
}
134134

135-
/// <summary>
136-
/// Use this method to check if a value is a valid string.
137-
/// If <paramref name="value"/> is null, empty or consists only of whitespace characters, an error message should be appended and a log of the passed <paramref name="level"/> severity would be created.
138-
/// </summary>
139-
/// <param name="value">The value that should be validated.</param>
140-
/// <param name="className">The name of the class where the <paramref name="methodName"/> is defined.</param>
141-
/// <param name="methodName">The name of he method where <paramref name="value"/> is used.</param>
142-
/// <param name="propertyName">The name of the property.</param>
143-
/// <param name="level">The logging severity.</param>
144-
public void ValidateNullOrWhitespace(string value, string className, string methodName, string propertyName, LogLevel level = LogLevel.Error)
145-
{
146-
// If the passed value is null, empty or consists only of whitespace characters, log and append an error message.
147-
if (string.IsNullOrWhiteSpace(value) == false) return;
148-
149-
var errorMessage = $"{className}, {methodName} - The {propertyName} is null, empty or consists only of whitespace characters.";
150-
this.AppendErrorMessage(errorMessage, logLevel: level);
151-
}
152-
153-
/// <summary>
154-
/// Use this method to check if a value is not null.
155-
/// If you want to validate that an entity exists, use the "ValidateExist" extension method.
156-
/// If you want to validate that the currently authenticated user is not null, use the "ValidateUser" extension method.
157-
/// If <paramref name="value"/> is null, an error message should be appended and a log of the passed <paramref name="level"/> severity would be created.
158-
/// </summary>
159-
/// <param name="value">The value that should be validated.</param>
160-
/// <param name="className">The name of the class where the <paramref name="methodName"/> is defined.</param>
161-
/// <param name="methodName">The name of he method where <paramref name="value"/> is used.</param>
162-
/// <param name="propertyName">The name of the property.</param>
163-
/// <param name="level">The logging severity.</param>
164-
public void ValidateNull(object value, string className, string methodName, string propertyName, LogLevel level = LogLevel.Error)
165-
{
166-
// If the passed value is null, log and append an error message.
167-
if (value != null) return;
168-
169-
var errorMessage = $"{className}, {methodName} - The {propertyName} is null.";
170-
this.AppendErrorMessage(errorMessage, logLevel: level);
171-
}
172-
173-
/// <summary>
174-
/// Use this method to check if a value is equal to its default value.
175-
/// If <paramref name="value"/> is equal to its default value, an error message should be appended and a log of the passed <paramref name="level"/> severity would be created.
176-
/// </summary>
177-
/// <typeparam name="TValue">The type of the <paramref name="value"/>.</typeparam>
178-
/// <param name="value">The value that should be validated.</param>
179-
/// <param name="className">The name of the class where the <paramref name="methodName"/> is defined.</param>
180-
/// <param name="methodName">The name of he method where <paramref name="value"/> is used.</param>
181-
/// <param name="propertyName">The name of the property.</param>
182-
/// <param name="level">The logging severity.</param>
183-
public void ValidateDefault<TValue>(TValue value, string className, string methodName, string propertyName, LogLevel level = LogLevel.Error)
184-
where TValue : struct, IEquatable<TValue>
185-
{
186-
// If the passed value is null, log and append an error message.
187-
if (value.Equals(default) == false) return;
188-
189-
var errorMessage = $"{className}, {methodName} - The {propertyName} has a default value.";
190-
this.AppendErrorMessage(errorMessage, logLevel: level);
191-
}
192-
193-
/// <summary>
194-
/// Use this method to check if a value is not null and not an empty collection.
195-
/// If <paramref name="value"/> is null or an empty collection, an error message should be appended and a log of the passed <paramref name="level"/> severity would be created.
196-
/// </summary>
197-
/// <typeparam name="T">The type of the underlying entities that are stored within the requested collection.</typeparam>
198-
/// <param name="value">The collection that should be validated.</param>
199-
/// <param name="className">The name of the class where the <paramref name="methodName"/> is defined.</param>
200-
/// <param name="methodName">The name of he method where <paramref name="value"/> is used.</param>
201-
/// <param name="identifierPropertyName">The name of the entity's unique identifier property.</param>
202-
/// <param name="level">The logging severity.</param>
203-
public void ValidateAny<T>(IEnumerable<T> value, string className, string methodName, string identifierPropertyName, LogLevel level = LogLevel.Error)
204-
{
205-
// If the passed value is null, log and append an error message.
206-
if (value == null)
207-
{
208-
var errorMessage = $"{className}, {methodName} - An object with that {identifierPropertyName} is null.";
209-
this.AppendErrorMessage(errorMessage, logLevel: level);
210-
}
211-
212-
// If the passed value is an empty collection, log and append an error message.
213-
else if (!value.Any())
214-
{
215-
var errorMessage = $"{className}, {methodName} - The collection with that {identifierPropertyName} is empty.";
216-
this.AppendErrorMessage(errorMessage, logLevel: level);
217-
}
218-
}
219-
220135
/// <summary>
221136
/// Use this method to get a string with all error messages.
222137
/// </summary>
@@ -227,15 +142,21 @@ public void ValidateAny<T>(IEnumerable<T> value, string className, string method
227142

228143
private void AppendError(OperationError error, LogLevel? logLevel)
229144
{
230-
this.AppendError(error);
145+
this.AppendErrorInternal(error);
231146

232147
if (this._logger is not null)
233148
{
149+
#pragma warning disable CA2254 // Template should be a static expression
234150
this._logger.Log(GetLogLevel(logLevel), error.Message);
151+
#pragma warning restore CA2254 // Template should be a static expression
235152
}
236153
}
237154

238-
private void AppendError(OperationError error) => this._errors.Add(error);
155+
/// <summary>
156+
/// Appends an <see cref="OperationError"/> to the internal Errors collection.
157+
/// </summary>
158+
/// <param name="error"></param>
159+
private void AppendErrorInternal(OperationError error) => this._errors.Add(error);
239160
}
240161

241162
/// <summary>
@@ -300,6 +221,22 @@ public OperationResult(TResult resultObject) : base()
300221
return this;
301222
}
302223

224+
/// <summary>
225+
/// Appends error messages from <paramref name="otherOperationResult"/> to <paramref name="originalOperationResult"/>.
226+
/// </summary>
227+
/// <param name="originalOperationResult">The <see cref="OperationResult"/> to append to.</param>
228+
/// <param name="otherOperationResult">The <see cref="OperationResult"/> to append from.</param>
229+
/// <typeparam name="TOriginal">A type that inherits from <see cref="OperationResult"/>.</typeparam>
230+
/// <typeparam name="TOther">A type that inherits from <see cref="OperationResult"/>.</typeparam>
231+
/// <returns>The original <see cref="OperationResult"/> with the appended messages from <paramref name="otherOperationResult"/>.</returns>
232+
public OperationResult<TResult> AppendErrorMessages<TOther>(TOther otherOperationResult)
233+
where TOther : OperationResult
234+
{
235+
base.AppendErrors(otherOperationResult);
236+
237+
return this;
238+
}
239+
303240
/// <summary>
304241
/// Appends an exception to the error message collection and logs the full exception as an Error <see cref="LogEventLevel"/> level. A call to this method will set the Success property to false.
305242
/// </summary>
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
using Microsoft.Extensions.Logging;
2+
3+
namespace OneBitSoftware.Utilities;
4+
5+
public static class OperationResultValidationExtensions
6+
{
7+
/// <summary>
8+
/// Use this method to check if a value is not null and not an empty collection.
9+
/// If <paramref name="value"/> is null or an empty collection, an error message should be appended and a log of the passed <paramref name="level"/> severity should be created.
10+
/// </summary>
11+
/// <typeparam name="T">The type of values that can be stored within the extended operation result.</typeparam>
12+
/// <typeparam name="TValue">The type of the underlying entities that are stored within the requested collection.</typeparam>
13+
/// <param name="operationResult">The <see cref="OperationResult"/> instance.</param>
14+
/// <param name="value">The collection that should be validated.</param>
15+
/// <param name="className">The name of the class where the <paramref name="methodName"/> is defined.</param>
16+
/// <param name="methodName">The name of the method where <paramref name="value"/> is used.</param>
17+
/// <param name="identifierPropertyName">The name of the entity's unique identifier property.</param>
18+
/// <param name="level">The logging severity.</param>
19+
public static void ValidateAny<T, TValue>(this OperationResult<T> operationResult, IEnumerable<TValue> value, string className, string methodName, string identifierPropertyName, LogLevel level = LogLevel.Error)
20+
{
21+
// If the passed value is null, log and append an error message.
22+
if (value == null)
23+
{
24+
var errorMessage = $"{className}, {methodName} - An entity with that {identifierPropertyName} does not exist.";
25+
operationResult.AppendError(errorMessage, logLevel: level);
26+
}
27+
28+
// If the passed value is an empty collection, log and append an error message.
29+
else if (!value.Any())
30+
{
31+
var errorMessage = $"{className}, {methodName} - The collection with that {identifierPropertyName} is empty which is not permitted.";
32+
operationResult.AppendError(errorMessage, logLevel: level);
33+
}
34+
}
35+
36+
/// <summary>
37+
/// Use this method to check if a value is equal to its default value.
38+
/// If <paramref name="value"/> is equal to its default value, an error message should be appended and a log of the passed <paramref name="level"/> severity would be created.
39+
/// </summary>
40+
/// <typeparam name="T">The type of values that can be stored within the extended operation result.</typeparam>
41+
/// <typeparam name="TValue">The type of the <paramref name="value"/>.</typeparam>
42+
/// <param name="value">The value that should be validated.</param>
43+
/// <param name="className">The name of the class where the <paramref name="methodName"/> is defined.</param>
44+
/// <param name="methodName">The name of he method where <paramref name="value"/> is used.</param>
45+
/// <param name="propertyName">The name of the property.</param>
46+
/// <param name="level">The logging severity.</param>
47+
public static void ValidateDefault<T, TValue>(this OperationResult<T> operationResult, TValue value, string className, string methodName, string propertyName, LogLevel level = LogLevel.Error)
48+
where TValue : struct, IEquatable<TValue>
49+
{
50+
// If the passed value is null, log and append an error message.
51+
if (value.Equals(default) == false) return;
52+
53+
var errorMessage = $"{className}, {methodName} - The {propertyName} has a default value.";
54+
operationResult.AppendErrorMessage(errorMessage, logLevel: level);
55+
}
56+
57+
/// <summary>
58+
/// Use this method to check if a value is a valid string.
59+
/// If <paramref name="value"/> is null, empty or consists only of whitespace characters, an error message should be appended and a log of the passed <paramref name="level"/> severity would be created.
60+
/// </summary>
61+
/// <typeparam name="T">The type of values that can be stored within the extended operation result.</typeparam>
62+
/// <param name="value">The value that should be validated.</param>
63+
/// <param name="className">The name of the class where the <paramref name="methodName"/> is defined.</param>
64+
/// <param name="methodName">The name of he method where <paramref name="value"/> is used.</param>
65+
/// <param name="propertyName">The name of the property.</param>
66+
/// <param name="level">The logging severity.</param>
67+
public static void ValidateNullOrWhitespace<T>(this OperationResult<T> operationResult, string value, string className, string methodName, string propertyName, LogLevel level = LogLevel.Error)
68+
{
69+
// If the passed value is null, empty or consists only of whitespace characters, log and append an error message.
70+
if (string.IsNullOrWhiteSpace(value) == false) return;
71+
72+
var errorMessage = $"{className}, {methodName} - The {propertyName} is null, empty or consists only of whitespace characters.";
73+
operationResult.AppendErrorMessage(errorMessage, logLevel: level);
74+
}
75+
76+
/// <summary>
77+
/// Use this method to check if a value is not null.
78+
/// If you want to validate that an entity exists, use the "ValidateExist" extension method.
79+
/// If you want to validate that the currently authenticated user is not null, use the "ValidateUser" extension method.
80+
/// If <paramref name="value"/> is null, an error message should be appended and a log of the passed <paramref name="level"/> severity would be created.
81+
/// </summary>
82+
/// <typeparam name="T">The type of values that can be stored within the extended operation result.</typeparam>
83+
/// <param name="value">The value that should be validated.</param>
84+
/// <param name="className">The name of the class where the <paramref name="methodName"/> is defined.</param>
85+
/// <param name="methodName">The name of he method where <paramref name="value"/> is used.</param>
86+
/// <param name="propertyName">The name of the property.</param>
87+
/// <param name="level">The logging severity.</param>
88+
public static void ValidateNull<T>(this OperationResult<T> operationResult, object value, string className, string methodName, string propertyName, LogLevel level = LogLevel.Error)
89+
{
90+
// If the passed value is null, log and append an error message.
91+
if (value != null) return;
92+
93+
var errorMessage = $"{className}, {methodName} - The {propertyName} is null.";
94+
operationResult.AppendErrorMessage(errorMessage, logLevel: level);
95+
}
96+
}

0 commit comments

Comments
 (0)