diff --git a/DigitalData.Core.API/BasicCRUDControllerBase.cs b/DigitalData.Core.API/BasicCRUDControllerBase.cs
index d8feb17..16e071e 100644
--- a/DigitalData.Core.API/BasicCRUDControllerBase.cs
+++ b/DigitalData.Core.API/BasicCRUDControllerBase.cs
@@ -1,5 +1,5 @@
using DigitalData.Core.Abstractions;
-using DigitalData.Core.Abstractions.Application;
+using DigitalData.Core.Application.Interfaces;
using Microsoft.AspNetCore.Mvc;
namespace DigitalData.Core.API
diff --git a/DigitalData.Core.API/CRUDControllerBase.cs b/DigitalData.Core.API/CRUDControllerBase.cs
index 58fe6bc..de61856 100644
--- a/DigitalData.Core.API/CRUDControllerBase.cs
+++ b/DigitalData.Core.API/CRUDControllerBase.cs
@@ -1,7 +1,7 @@
using DigitalData.Core.Abstractions;
-using DigitalData.Core.Abstractions.Application;
-using DigitalData.Core.DTO;
+using DigitalData.Core.Application.Interfaces;
using Microsoft.AspNetCore.Mvc;
+using DigitalData.Core.Application.DTO;
namespace DigitalData.Core.API
{
diff --git a/DigitalData.Core.API/CRUDControllerBaseWithErrorHandling.cs b/DigitalData.Core.API/CRUDControllerBaseWithErrorHandling.cs
index 644a405..1692c95 100644
--- a/DigitalData.Core.API/CRUDControllerBaseWithErrorHandling.cs
+++ b/DigitalData.Core.API/CRUDControllerBaseWithErrorHandling.cs
@@ -1,7 +1,7 @@
using DigitalData.Core.Abstractions;
-using DigitalData.Core.Abstractions.Application;
-using DigitalData.Core.DTO;
+using DigitalData.Core.Application.Interfaces;
using Microsoft.AspNetCore.Mvc;
+using DigitalData.Core.Application.DTO;
namespace DigitalData.Core.API
{
diff --git a/DigitalData.Core.API/ControllerExtensions.cs b/DigitalData.Core.API/ControllerExtensions.cs
index 900cc32..26296b7 100644
--- a/DigitalData.Core.API/ControllerExtensions.cs
+++ b/DigitalData.Core.API/ControllerExtensions.cs
@@ -1,4 +1,4 @@
-using DigitalData.Core.DTO;
+using DigitalData.Core.Application.DTO;
using Microsoft.AspNetCore.Mvc;
using System.Text;
diff --git a/DigitalData.Core.API/DigitalData.Core.API.csproj b/DigitalData.Core.API/DigitalData.Core.API.csproj
index 5a4a3b4..22ad268 100644
--- a/DigitalData.Core.API/DigitalData.Core.API.csproj
+++ b/DigitalData.Core.API/DigitalData.Core.API.csproj
@@ -32,8 +32,7 @@
-
-
+
diff --git a/DigitalData.Core.API/ReadControllerBase.cs b/DigitalData.Core.API/ReadControllerBase.cs
index 9ce9446..973e94a 100644
--- a/DigitalData.Core.API/ReadControllerBase.cs
+++ b/DigitalData.Core.API/ReadControllerBase.cs
@@ -1,6 +1,6 @@
-using DigitalData.Core.Abstractions.Application;
-using DigitalData.Core.DTO;
+using DigitalData.Core.Application.Interfaces;
using Microsoft.AspNetCore.Mvc;
+using DigitalData.Core.Application.DTO;
namespace DigitalData.Core.API
{
diff --git a/DigitalData.Core.API/ReadControllerBaseWithErrorHandling.cs b/DigitalData.Core.API/ReadControllerBaseWithErrorHandling.cs
index b2c3502..928ddf9 100644
--- a/DigitalData.Core.API/ReadControllerBaseWithErrorHandling.cs
+++ b/DigitalData.Core.API/ReadControllerBaseWithErrorHandling.cs
@@ -1,5 +1,5 @@
-using DigitalData.Core.Abstractions.Application;
-using DigitalData.Core.DTO;
+using DigitalData.Core.Application.DTO;
+using DigitalData.Core.Application.Interfaces;
using Microsoft.AspNetCore.Mvc;
namespace DigitalData.Core.API
diff --git a/DigitalData.Core.Abstractions/DigitalData.Core.Abstractions.csproj b/DigitalData.Core.Abstractions/DigitalData.Core.Abstractions.csproj
index ffa5526..9feaf38 100644
--- a/DigitalData.Core.Abstractions/DigitalData.Core.Abstractions.csproj
+++ b/DigitalData.Core.Abstractions/DigitalData.Core.Abstractions.csproj
@@ -37,8 +37,4 @@
-
-
-
-
\ No newline at end of file
diff --git a/DigitalData.Core.Application/BasicCRUDService.cs b/DigitalData.Core.Application/BasicCRUDService.cs
index 514a3d4..d781549 100644
--- a/DigitalData.Core.Application/BasicCRUDService.cs
+++ b/DigitalData.Core.Application/BasicCRUDService.cs
@@ -1,7 +1,7 @@
using AutoMapper;
using DigitalData.Core.Abstractions;
-using DigitalData.Core.Abstractions.Application;
-using DigitalData.Core.Abstractions.Infrastructure;
+using DigitalData.Core.Application.Interfaces;
+using DigitalData.Core.Application.Interfaces.Repository;
namespace DigitalData.Core.Application
{
diff --git a/DigitalData.Core.Application/CRUDService.cs b/DigitalData.Core.Application/CRUDService.cs
index 77256fc..5b2dd39 100644
--- a/DigitalData.Core.Application/CRUDService.cs
+++ b/DigitalData.Core.Application/CRUDService.cs
@@ -1,9 +1,9 @@
-using DigitalData.Core.Abstractions.Application;
-using DigitalData.Core.Abstractions.Infrastructure;
-using AutoMapper;
-using DigitalData.Core.DTO;
+using AutoMapper;
using DigitalData.Core.Abstractions;
using Microsoft.Extensions.Logging;
+using DigitalData.Core.Application.Interfaces.Repository;
+using DigitalData.Core.Application.Interfaces;
+using DigitalData.Core.Application.DTO;
namespace DigitalData.Core.Application
{
diff --git a/DigitalData.Core.Application/DIExtensions.cs b/DigitalData.Core.Application/DIExtensions.cs
index 49a30e7..dfa78cd 100644
--- a/DigitalData.Core.Application/DIExtensions.cs
+++ b/DigitalData.Core.Application/DIExtensions.cs
@@ -1,4 +1,4 @@
-using DigitalData.Core.Abstractions.Application;
+using DigitalData.Core.Application.Interfaces;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
diff --git a/DigitalData.Core.Application/DTO/BaseDto.cs b/DigitalData.Core.Application/DTO/BaseDto.cs
new file mode 100644
index 0000000..f670271
--- /dev/null
+++ b/DigitalData.Core.Application/DTO/BaseDto.cs
@@ -0,0 +1,17 @@
+namespace DigitalData.Core.Application.DTO
+{
+ ///
+ /// Represents a base Data Transfer Object (DTO) with an identifier.
+ ///
+ /// The type of the identifier.
+ /// The identifier of the DTO.
+ public record BaseDTO(TId Id) where TId : notnull
+ {
+ ///
+ /// Returns the hash code for this instance, based on the identifier.
+ /// This override ensures that the hash code is derived consistently from the identifier.
+ ///
+ /// A hash code for the current object, derived from the identifier.
+ public override int GetHashCode() => Id.GetHashCode();
+ }
+}
\ No newline at end of file
diff --git a/DigitalData.Core.Application/DTO/CookieConsentSettings.cs b/DigitalData.Core.Application/DTO/CookieConsentSettings.cs
new file mode 100644
index 0000000..9243cd1
--- /dev/null
+++ b/DigitalData.Core.Application/DTO/CookieConsentSettings.cs
@@ -0,0 +1,74 @@
+namespace DigitalData.Core.Application.DTO
+{
+ ///
+ /// Represents settings related to user cookie consent dialogs. Designed to be serialized into JSON format for use with JavaScript frontend libraries,
+ /// such as the bootstrap-cookie-consent-settings at the GitHub repository: https://github.com/shaack/bootstrap-cookie-consent-settings
+ ///
+ public class CookieConsentSettings
+ {
+ ///
+ /// URL to the privacy policy page.
+ ///
+ public string? PrivacyPolicyUrl { get; set; }
+
+ ///
+ /// URL to the legal notice page.
+ ///
+ public string? LegalNoticeUrl { get; set; }
+
+ ///
+ /// URL to the content of the dialog box.
+ ///
+ public string? ContentURL { get; set; }
+
+ ///
+ /// CSS class for the 'Agree' button.
+ ///
+ public string? ButtonAgreeClass { get; set; }
+
+ ///
+ /// CSS class for the 'Don't Agree' button.
+ ///
+ public string? ButtonDontAgreeClass { get; set; }
+
+ ///
+ /// CSS class for the 'Save' button.
+ ///
+ public string? ButtonSaveClass { get; set; }
+
+ ///
+ /// Language in which the modal is displayed.
+ ///
+ public string? Lang { get; set; }
+
+ ///
+ /// Default language for the modal if the user's browser language is not supported.
+ ///
+ public string? DefaultLang { get; set; }
+
+ ///
+ /// Name of the cookie used to store the consent status.
+ ///
+ public string? CookieName { get; set; }
+
+ ///
+ /// Number of days the cookie will be stored.
+ ///
+ public int CookieStorageDays { get; set; }
+
+ ///
+ /// Identifier for the modal dialog element.
+ ///
+ public string? ModalId { get; set; }
+
+ ///
+ /// Indicates whether to also store the settings in the browser's localStorage.
+ ///
+ public bool AlsoUseLocalStorage { get; set; }
+
+ ///
+ /// List of categories for cookie consent.
+ ///
+ public List? Categories { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/DigitalData.Core.Application/DTO/DIExtensions.cs b/DigitalData.Core.Application/DTO/DIExtensions.cs
new file mode 100644
index 0000000..f536a8c
--- /dev/null
+++ b/DigitalData.Core.Application/DTO/DIExtensions.cs
@@ -0,0 +1,33 @@
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using System.Configuration;
+
+namespace DigitalData.Core.Application.DTO
+{
+ ///
+ /// Provides extension methods for dependency injection.
+ ///
+ public static class DIExtensions
+ {
+ ///
+ /// Adds the to the service collection.
+ ///
+ /// The service collection to add the settings to.
+ /// The updated service collection.
+ ///
+ /// Thrown if the 'CookieConsentSettings' section is missing or improperly configured in appsettings.json.
+ ///
+ public static IServiceCollection AddCookieConsentSettings(this IServiceCollection services)
+ {
+ services.AddSingleton(sp =>
+ {
+ var configuration = sp.GetRequiredService();
+ var settings = configuration.GetSection("CookieConsentSettings").Get();
+ return settings is null
+ ? throw new ConfigurationErrorsException("The 'CookieConsentSettings' section is missing or improperly configured in appsettings.json.")
+ : settings;
+ });
+ return services;
+ }
+ }
+}
\ No newline at end of file
diff --git a/DigitalData.Core.Application/DTO/DTOExtensions.cs b/DigitalData.Core.Application/DTO/DTOExtensions.cs
new file mode 100644
index 0000000..f018bc7
--- /dev/null
+++ b/DigitalData.Core.Application/DTO/DTOExtensions.cs
@@ -0,0 +1,367 @@
+using Microsoft.Extensions.Logging;
+using System.Text;
+
+namespace DigitalData.Core.Application.DTO
+{
+ ///
+ /// Provides extension methods for data transfer objects (DTOs).
+ ///
+ public static class DTOExtensions
+ {
+ ///
+ /// Adds a single message to the result, if not null.
+ ///
+ /// The type of the result.
+ /// The result to add the message to.
+ /// The message to add.
+ /// The updated result.
+ public static T Message(this T result, string? message) where T : Result
+ {
+ if(message is not null)
+ result.Messages.Add(message);
+ return result;
+ }
+
+ internal static IEnumerable FilterNull(this IEnumerable list)
+ {
+ foreach (var item in list)
+ if(item is not null)
+ yield return item;
+ }
+
+ ///
+ /// Adds multiple messages to the result, after removing nulls.
+ ///
+ /// The type of the result.
+ /// The result to add the messages to.
+ /// The messages to add.
+ /// The updated result.
+ public static T Message(this T result, params string?[] messages) where T : Result
+ {
+ result.Messages.AddRange(messages.FilterNull());
+ return result;
+ }
+
+ ///
+ /// Adds a collection of messages to the result.
+ ///
+ /// The type of the result.
+ /// The result to add the messages to.
+ /// The collection of messages to add.
+ /// The updated result.
+ public static T Message(this T result, IEnumerable messages) where T : Result
+ {
+ result.Messages.AddRange(messages.FilterNull());
+ return result;
+ }
+
+ ///
+ /// Adds a notice to the result.
+ ///
+ /// The type of the result.
+ /// The result to add the notice to.
+ /// The notice to add.
+ /// The updated result.
+ public static T Notice(this T result, Notice notice) where T : Result
+ {
+ result.Notices.Add(notice);
+ return result;
+ }
+
+ ///
+ /// Adds a collection of notices to the result.
+ ///
+ /// The type of the result.
+ /// The result to add the notices to.
+ /// The collection of notices to add.
+ /// The updated result.
+ public static T Notice(this T result, IEnumerable notices) where T : Result
+ {
+ result.Notices.AddRange(notices);
+ return result;
+ }
+
+ ///
+ /// Adds notices with a specific log level and flags to the result.
+ ///
+ /// The type of the result.
+ /// The result to add the notices to.
+ /// The log level of the notices.
+ /// The flags associated with the notices.
+ /// The updated result.
+ public static T Notice(this T result, LogLevel level, params Enum[] flags) where T : Result
+ {
+ var notices = flags.Select(flag => new Notice()
+ {
+ Flag = flag,
+ Level = level
+ });
+ result.Notices.AddRange(notices);
+ return result;
+ }
+
+ ///
+ /// Adds a notice with a specific log level, flag, and messages to the result.
+ ///
+ /// The type of the result.
+ /// The result to add the notice to.
+ /// The log level of the notice.
+ /// The flag associated with the notice.
+ /// The messages to add to the notice.
+ /// The updated result.
+ public static T Notice(this T result, LogLevel level, Enum flag, params string?[] messages) where T : Result
+ {
+ result.Notices.Add(new Notice()
+ {
+ Flag = flag,
+ Level = level,
+ Messages = messages.FilterNull().ToList()
+ });
+ return result;
+ }
+
+ ///
+ /// Adds a notice with a specific log level and messages to the result.
+ ///
+ /// The type of the result.
+ /// The result to add the notice to.
+ /// The log level of the notice.
+ /// The messages to add to the notice.
+ /// The updated result.
+ public static T Notice(this T result, LogLevel level, params string[] messages) where T : Result
+ {
+ result.Notices.Add(new Notice()
+ {
+ Flag = null,
+ Level = level,
+ Messages = messages.FilterNull().ToList()
+ });
+ return result;
+ }
+
+ ///
+ /// Checks if any notice has the specified flag.
+ ///
+ /// The collection of notices to check.
+ /// The flag to check for.
+ /// True if any notice has the specified flag; otherwise, false.
+ public static bool HasFlag(this IEnumerable notices, Enum flag) => notices.Any(n => n.Flag?.ToString() == flag.ToString());
+
+ ///
+ /// Checks if any notice has any of the specified flags.
+ ///
+ /// The collection of notices to check.
+ /// The flags to check for.
+ /// True if any notice has any of the specified flags; otherwise, false.
+ public static bool HasAnyFlag(this IEnumerable notices, params Enum[] flags) => flags.Any(f => notices.HasFlag(f));
+
+ ///
+ /// Executes a function based on the success or failure of the task result,
+ /// without using result data.
+ ///
+ /// The type of the return value.
+ /// The task returning a result to evaluate.
+ /// The function to execute if the result is successful.
+ /// The function to execute if the result is a failure.
+ /// The result of the executed function.
+ public static I? Then(this Result result, Func Success)
+ {
+ return result.IsSuccess ? Success() : default;
+ }
+
+ ///
+ /// Executes a function based on the success or failure of the task result,
+ /// using the data in the result.
+ ///
+ /// The type of the data in the result.
+ /// The type of the return value.
+ /// The task returning a data result to evaluate.
+ /// The function to execute if the data result is successful.
+ /// The function to execute if the data result is a failure.
+ /// The result of the executed function.
+ public static async Task ThenAsync(this Result result, Func> SuccessAsync)
+ {
+ return result.IsSuccess ? await SuccessAsync() : default;
+ }
+
+ ///
+ /// Executes a function based on the success or failure of the result.
+ ///
+ /// The type of the return value.
+ /// The result to evaluate.
+ /// The function to execute if the result is successful.
+ /// The function to execute if the result is a failure.
+ /// The result of the executed function.
+ public static I Then(this Result result, Func Success, Func, List, I> Fail)
+ {
+ return result.IsSuccess ? Success() : Fail(result.Messages, result.Notices);
+ }
+
+ ///
+ /// Asynchronously executes a function based on the success or failure of the result.
+ ///
+ /// The type of the return value.
+ /// The result to evaluate.
+ /// The asynchronous function to execute if the result is successful.
+ /// The function to execute if the result is a failure.
+ /// The result of the executed function.
+ public static async Task ThenAsync(this Result result, Func> SuccessAsync, Func, List, I> Fail)
+ {
+ return result.IsSuccess ? await SuccessAsync() : Fail(result.Messages, result.Notices);
+ }
+
+ ///
+ /// Executes a function based on the success or failure of the data result.
+ ///
+ /// The type of the data in the result.
+ /// The type of the return value.
+ /// The data result to evaluate.
+ /// The function to execute if the data result is successful.
+ /// The function to execute if the data result is a failure.
+ /// The result of the executed function.
+ public static I Then(this DataResult result, Func Success, Func, List, I> Fail)
+ {
+ return result.IsSuccess ? Success(result.Data) : Fail(result.Messages, result.Notices);
+ }
+
+ ///
+ /// Asynchronously executes a function based on the success or failure of the data result.
+ ///
+ /// The type of the data in the result.
+ /// The type of the return value.
+ /// The data result to evaluate.
+ /// The asynchronous function to execute if the data result is successful.
+ /// The function to execute if the data result is a failure.
+ /// The result of the executed function.
+ public static async Task ThenAsync(this DataResult result, Func> SuccessAsync, Func, List, I> Fail)
+ {
+ return result.IsSuccess ? await SuccessAsync(result.Data) : Fail(result.Messages, result.Notices);
+ }
+
+ ///
+ /// Asynchronously executes a function based on the success or failure of a task returning a result.
+ ///
+ /// The type of the return value.
+ /// The task returning a result to evaluate.
+ /// The function to execute if the result is successful.
+ /// The function to execute if the result is a failure.
+ /// The result of the executed function.
+ public static async Task ThenAsync(this Task tResult, Func Success, Func, List, I> Fail)
+ {
+ Result result = await tResult;
+ return result.IsSuccess ? Success() : Fail(result.Messages, result.Notices);
+ }
+
+ ///
+ /// Asynchronously executes a function based on the success or failure of a task returning a result.
+ ///
+ /// The type of the return value.
+ /// The task returning a result to evaluate.
+ /// The asynchronous function to execute if the result is successful.
+ /// The function to execute if the result is a failure.
+ /// The result of the executed function.
+ public static async Task ThenAsync(this Task tResult, Func> SuccessAsync, Func, List, I> Fail)
+ {
+ Result result = await tResult;
+ return result.IsSuccess ? await SuccessAsync() : Fail(result.Messages, result.Notices);
+ }
+
+ ///
+ /// Asynchronously executes a function based on the success or failure of a task returning a data result.
+ ///
+ /// The type of the data in the result.
+ /// The type of the return value.
+ /// The task returning a data result to evaluate.
+ /// The function to execute if the data result is successful.
+ /// The function to execute if the data result is a failure.
+ /// The result of the executed function.
+ public static async Task ThenAsync(this Task> tResult, Func Success, Func, List, I> Fail)
+ {
+ DataResult result = await tResult;
+ return result.IsSuccess ? Success(result.Data) : Fail(result.Messages, result.Notices);
+ }
+
+ ///
+ /// Asynchronously executes a function based on the success or failure of a task returning a data result.
+ ///
+ /// The type of the data in the result.
+ /// The type of the return value.
+ /// The task returning a data result to evaluate.
+ /// The asynchronous function to execute if the data result is successful.
+ /// The function to execute if the data result is a failure.
+ /// The result of the executed function.
+ public static async Task ThenAsync(this Task> tResult, Func> SuccessAsync, Func, List, I> Fail)
+ {
+ DataResult result = await tResult;
+ return result.IsSuccess ? await SuccessAsync(result.Data) : Fail(result.Messages, result.Notices);
+ }
+
+ ///
+ /// Joins the values into a single string with optional start, separator, and end strings.
+ ///
+ /// The type of the values.
+ /// The values to join.
+ /// The starting string.
+ /// The separator string.
+ /// The ending string.
+ /// The joined string.
+ public static string Join(this IEnumerable values, string start = "", string seperator = ". ", string end = ".")
+ => new StringBuilder(start).Append(string.Join(seperator, values)).Append(end).ToString();
+
+ ///
+ /// Logs the notices using the specified logger.
+ ///
+ /// The logger to use.
+ /// The collection of notices to log.
+ /// The starting string for each notice.
+ /// The separator string for messages in each notice.
+ /// The ending string for each notice.
+ public static void LogNotice(this ILogger logger, IEnumerable notices, string start = ": ", string seperator = ". ", string end = ".\n")
+ {
+ foreach(LogLevel level in Enum.GetValues(typeof(LogLevel)))
+ {
+ var logNotices = notices.Where(n => n.Level == level);
+
+ if (!logNotices.Any())
+ continue;
+
+ var sb = new StringBuilder();
+ foreach(Notice notice in logNotices)
+ {
+ if (notice.Flag is not null)
+ sb.Append(notice.Flag);
+
+ if (notice.Messages.Any())
+ sb.Append(start).Append(string.Join(seperator, notice.Messages)).AppendLine(end);
+ else sb.Append(end);
+ }
+ logger.Log(level, sb.ToString());
+ }
+ }
+
+ ///
+ /// Logs the notices from a result using the specified logger.
+ ///
+ /// The logger to use.
+ /// The result containing the notices to log.
+ /// The starting string for each notice.
+ /// The separator string for messages in each notice.
+ /// The ending string for each notice.
+ public static void LogNotice(this ILogger logger, Result result, string start = ": ", string seperator = ". ", string end = ".\n")
+ => logger.LogNotice(notices: result.Notices, start: start, seperator: seperator, end: end);
+
+ ///
+ /// Determines if the data result is right (true).
+ ///
+ /// The data result to evaluate.
+ /// True if the data result is true; otherwise, false.
+ public static bool IsRight(this DataResult bResult) => bResult.Data;
+
+ ///
+ /// Determines if the data result is wrong (false).
+ ///
+ /// The data result to evaluate.
+ /// True if the data result is false; otherwise, false.
+ public static bool IsWrong(this DataResult bResult) => !bResult.Data;
+ }
+}
\ No newline at end of file
diff --git a/DigitalData.Core.Application/DTO/DataResult.cs b/DigitalData.Core.Application/DTO/DataResult.cs
new file mode 100644
index 0000000..0d22520
--- /dev/null
+++ b/DigitalData.Core.Application/DTO/DataResult.cs
@@ -0,0 +1,26 @@
+using System.Text.Json.Serialization;
+
+namespace DigitalData.Core.Application.DTO
+{
+ ///
+ /// Represents a result of an operation that includes data, inheriting from .
+ ///
+ /// The type of the data included in the result.
+ public class DataResult : Result
+ {
+ ///
+ /// Gets or sets the data included in the result. This property is required.
+ /// It will be ignored during JSON serialization if the value is null.
+ ///
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public required T Data { get; set; }
+
+ ///
+ /// Converts the current to a failed ,
+ /// preserving the messages and notices.
+ ///
+ /// The type of the data in the new failed result.
+ /// A failed with the current messages and notices.
+ public DataResult ToFail() => Fail().Message(Messages).Notice(Notices);
+ }
+}
\ No newline at end of file
diff --git a/DigitalData.Core.Application/DTO/Flag.cs b/DigitalData.Core.Application/DTO/Flag.cs
new file mode 100644
index 0000000..82d75cb
--- /dev/null
+++ b/DigitalData.Core.Application/DTO/Flag.cs
@@ -0,0 +1,50 @@
+namespace DigitalData.Core.Application.DTO
+{
+ ///
+ /// Defines flags that indicate specific types of status or conditions in a service operation.
+ /// These flags help in categorizing and identifying specific circumstances or issues that may arise during execution.
+ ///
+ public enum Flag
+ {
+ ///
+ /// Indicates a security breach or vulnerability has been detected during the service operation.
+ ///
+ SecurityBreach,
+
+ ///
+ /// Indicates a potential issue with data integrity during the service operation.
+ /// This flag is used when data may have been altered, corrupted, or is otherwise unreliable,
+ /// which could impact the accuracy or trustworthiness of the operation's results.
+ ///
+ DataIntegrityIssue,
+
+ ///
+ /// Indicates that either a security breach, a data integrity issue, or both have been detected during the service operation.
+ /// This flag is used when it is not sure whether the problem is security or data integrity. In this case, data integrity should be checked first.
+ ///
+ SecurityBreachOrDataIntegrity,
+
+ ///
+ /// Indicates a possible security breach during the service operation.
+ ///
+ PossibleSecurityBreach,
+
+ ///
+ /// Indicates a possible issue with data integrity during the service operation.
+ /// This flag is used when there is a suspicion of data alteration, corruption, or unreliability.
+ ///
+ PossibleDataIntegrityIssue,
+
+ ///
+ /// Indicates that either a possible security breach, a possible data integrity issue, or both have been detected during the service operation.
+ /// This flag is used when it is uncertain whether the issue is related to security, data integrity, or both.
+ ///
+ PossibleSecurityBreachOrDataIntegrity,
+
+ ///
+ /// Indicates that the requested resource or operation could not be found.
+ /// This flag is used when the specified item or condition does not exist or is unavailable.
+ ///
+ NotFound
+ }
+}
\ No newline at end of file
diff --git a/DigitalData.Core.Application/DTO/Notice.cs b/DigitalData.Core.Application/DTO/Notice.cs
new file mode 100644
index 0000000..019d811
--- /dev/null
+++ b/DigitalData.Core.Application/DTO/Notice.cs
@@ -0,0 +1,25 @@
+using Microsoft.Extensions.Logging;
+
+namespace DigitalData.Core.Application.DTO
+{
+ ///
+ /// Represents a notice for logging purposes, containing a flag, log level, and associated messages.
+ ///
+ public class Notice
+ {
+ ///
+ /// Gets or sets an optional flag associated with the notice.
+ ///
+ public Enum? Flag { get; init; } = null;
+
+ ///
+ /// Gets or sets the log level for the notice.
+ ///
+ public LogLevel Level { get; init; } = LogLevel.None;
+
+ ///
+ /// Gets a list of messages associated with the notice.
+ ///
+ public List Messages { get; init; } = new();
+ }
+}
\ No newline at end of file
diff --git a/DigitalData.Core.Application/DTO/Result.cs b/DigitalData.Core.Application/DTO/Result.cs
new file mode 100644
index 0000000..cce8934
--- /dev/null
+++ b/DigitalData.Core.Application/DTO/Result.cs
@@ -0,0 +1,97 @@
+using System.Text.Json.Serialization;
+
+namespace DigitalData.Core.Application.DTO
+{
+ ///
+ /// Represents the result of an operation, containing information about its success or failure,
+ /// messages for the client, and notices for logging.
+ ///
+ public class Result
+ {
+ ///
+ /// Gets or sets a value indicating whether the operation was successful.
+ ///
+ public bool IsSuccess { get; set; } = false;
+
+ ///
+ /// Gets a value indicating whether the operation failed.
+ ///
+ public bool IsFailed => !IsSuccess;
+
+ ///
+ /// Gets a list of messages intended for the client.
+ ///
+ public List Messages { get; init; } = new();
+
+ ///
+ /// Gets a list of notices intended for logging purposes. This property is ignored during JSON serialization.
+ ///
+ [JsonIgnore]
+ public List Notices = new();
+
+ ///
+ /// Creates a with the specified data.
+ ///
+ /// The type of the data.
+ /// The data to include in the result.
+ /// A new instance.
+ public DataResult Data(T data) => new()
+ {
+ IsSuccess = IsSuccess,
+ Messages = Messages,
+ Notices = Notices,
+ Data = data
+ };
+
+ ///
+ /// Checks if any notice has the specified flag.
+ ///
+ /// The flag to check.
+ /// True if any notice has the specified flag; otherwise, false.
+ public bool HasFlag(Enum flag) => Notices.Any(n => n.Flag?.ToString() == flag.ToString());
+
+ ///
+ /// Checks if any notice has any of the specified flags.
+ ///
+ /// The flags to check.
+ /// True if any notice has any of the specified flags; otherwise, false.
+ public bool HasAnyFlag(params Enum[] flags) => flags.Any(HasFlag);
+
+ ///
+ /// Creates a new successful .
+ ///
+ /// A new successful .
+ public static Result Success() => new() { IsSuccess = true };
+
+ ///
+ /// Creates a new failed .
+ ///
+ /// A new failed .
+ public static Result Fail() => new() { IsSuccess = false };
+
+ ///
+ /// Creates a new successful with the specified data.
+ ///
+ /// The type of the data.
+ /// The data to include in the result.
+ /// A new successful with the specified data.
+ public static DataResult Success(T data) => new()
+ {
+ IsSuccess = true,
+ Data = data
+ };
+
+ ///
+ /// Creates a new failed with no data.
+ ///
+ /// The type of the data.
+ /// A new failed with no data.
+#pragma warning disable CS8601 // Possible null reference assignment.
+ public static DataResult Fail() => new()
+ {
+ IsSuccess = false,
+ Data = default
+ };
+#pragma warning restore CS8601 // Possible null reference assignment.
+ }
+}
\ No newline at end of file
diff --git a/DigitalData.Core.Application/DirectorySearchService.cs b/DigitalData.Core.Application/DirectorySearchService.cs
index 19ad47f..39e202a 100644
--- a/DigitalData.Core.Application/DirectorySearchService.cs
+++ b/DigitalData.Core.Application/DirectorySearchService.cs
@@ -1,10 +1,10 @@
-using DigitalData.Core.Abstractions.Application;
-using System.Diagnostics.CodeAnalysis;
+using System.Diagnostics.CodeAnalysis;
using System.DirectoryServices;
using Microsoft.Extensions.Caching.Memory;
using System.DirectoryServices.AccountManagement;
-using DigitalData.Core.DTO;
using Microsoft.Extensions.Options;
+using DigitalData.Core.Application.Interfaces;
+using DigitalData.Core.Application.DTO;
namespace DigitalData.Core.Application
{
diff --git a/DigitalData.Core.Abstractions/Application/IBasicCRUDService.cs b/DigitalData.Core.Application/Interfaces/IBasicCRUDService.cs
similarity index 92%
rename from DigitalData.Core.Abstractions/Application/IBasicCRUDService.cs
rename to DigitalData.Core.Application/Interfaces/IBasicCRUDService.cs
index d967df8..93339e2 100644
--- a/DigitalData.Core.Abstractions/Application/IBasicCRUDService.cs
+++ b/DigitalData.Core.Application/Interfaces/IBasicCRUDService.cs
@@ -1,6 +1,6 @@
-using DigitalData.Core.Abstractions.Infrastructure;
+using DigitalData.Core.Abstractions;
-namespace DigitalData.Core.Abstractions.Application
+namespace DigitalData.Core.Application.Interfaces
{
///
/// Implements a simplified CRUD service interface that uses a single Data Transfer Object (DTO) type for all CRUD operations,
diff --git a/DigitalData.Core.Abstractions/Application/ICRUDService.cs b/DigitalData.Core.Application/Interfaces/ICRUDService.cs
similarity index 92%
rename from DigitalData.Core.Abstractions/Application/ICRUDService.cs
rename to DigitalData.Core.Application/Interfaces/ICRUDService.cs
index d360b59..36da7b6 100644
--- a/DigitalData.Core.Abstractions/Application/ICRUDService.cs
+++ b/DigitalData.Core.Application/Interfaces/ICRUDService.cs
@@ -1,6 +1,7 @@
-using DigitalData.Core.DTO;
+using DigitalData.Core.Abstractions;
+using DigitalData.Core.Application.DTO;
-namespace DigitalData.Core.Abstractions.Application
+namespace DigitalData.Core.Application.Interfaces
{
public interface ICRUDService : IReadService
where TCreateDto : class where TReadDto : class where TEntity : class, IUnique
diff --git a/DigitalData.Core.Abstractions/Application/IDirectorySearchService.cs b/DigitalData.Core.Application/Interfaces/IDirectorySearchService.cs
similarity index 98%
rename from DigitalData.Core.Abstractions/Application/IDirectorySearchService.cs
rename to DigitalData.Core.Application/Interfaces/IDirectorySearchService.cs
index 74f410c..3f1f288 100644
--- a/DigitalData.Core.Abstractions/Application/IDirectorySearchService.cs
+++ b/DigitalData.Core.Application/Interfaces/IDirectorySearchService.cs
@@ -1,7 +1,7 @@
-using DigitalData.Core.DTO;
+using DigitalData.Core.Application.DTO;
using System.DirectoryServices;
-namespace DigitalData.Core.Abstractions.Application
+namespace DigitalData.Core.Application.Interfaces
{
public interface IDirectorySearchService
{
diff --git a/DigitalData.Core.Abstractions/Application/IJWTService.cs b/DigitalData.Core.Application/Interfaces/IJWTService.cs
similarity index 96%
rename from DigitalData.Core.Abstractions/Application/IJWTService.cs
rename to DigitalData.Core.Application/Interfaces/IJWTService.cs
index b47bc45..6420b4b 100644
--- a/DigitalData.Core.Abstractions/Application/IJWTService.cs
+++ b/DigitalData.Core.Application/Interfaces/IJWTService.cs
@@ -2,7 +2,7 @@
using System.IdentityModel.Tokens.Jwt;
using System.Security.Cryptography;
-namespace DigitalData.Core.Application
+namespace DigitalData.Core.Application.Interfaces
{
///
/// Defines the operations for JWT service handling claims of type .
diff --git a/DigitalData.Core.Abstractions/Application/IReadService.cs b/DigitalData.Core.Application/Interfaces/IReadService.cs
similarity index 95%
rename from DigitalData.Core.Abstractions/Application/IReadService.cs
rename to DigitalData.Core.Application/Interfaces/IReadService.cs
index 132054b..fa1ee7a 100644
--- a/DigitalData.Core.Abstractions/Application/IReadService.cs
+++ b/DigitalData.Core.Application/Interfaces/IReadService.cs
@@ -1,6 +1,6 @@
-using DigitalData.Core.DTO;
+using DigitalData.Core.Application.DTO;
-namespace DigitalData.Core.Abstractions.Application
+namespace DigitalData.Core.Application.Interfaces
{
public interface IReadService
where TReadDto : class where TEntity : class
diff --git a/DigitalData.Core.Abstractions/Infrastructure/Extensions.cs b/DigitalData.Core.Application/Interfaces/Repository/Extensions.cs
similarity index 96%
rename from DigitalData.Core.Abstractions/Infrastructure/Extensions.cs
rename to DigitalData.Core.Application/Interfaces/Repository/Extensions.cs
index d916c85..38aad40 100644
--- a/DigitalData.Core.Abstractions/Infrastructure/Extensions.cs
+++ b/DigitalData.Core.Application/Interfaces/Repository/Extensions.cs
@@ -1,6 +1,6 @@
using System.Linq.Expressions;
-namespace DigitalData.Core.Abstractions.Infrastructure;
+namespace DigitalData.Core.Application.Interfaces.Repository;
public static class Extensions
{
diff --git a/DigitalData.Core.Abstractions/Infrastructure/ICRUDRepository.cs b/DigitalData.Core.Application/Interfaces/Repository/ICRUDRepository.cs
similarity index 96%
rename from DigitalData.Core.Abstractions/Infrastructure/ICRUDRepository.cs
rename to DigitalData.Core.Application/Interfaces/Repository/ICRUDRepository.cs
index c5562ff..af16ad3 100644
--- a/DigitalData.Core.Abstractions/Infrastructure/ICRUDRepository.cs
+++ b/DigitalData.Core.Application/Interfaces/Repository/ICRUDRepository.cs
@@ -1,4 +1,6 @@
-namespace DigitalData.Core.Abstractions.Infrastructure
+using DigitalData.Core.Abstractions;
+
+namespace DigitalData.Core.Application.Interfaces.Repository
{
///
/// Defines the contract for CRUD operations on a repository for entities of type TEntity.
diff --git a/DigitalData.Core.Abstractions/Infrastructure/IEntityMapper.cs b/DigitalData.Core.Application/Interfaces/Repository/IEntityMapper.cs
similarity index 96%
rename from DigitalData.Core.Abstractions/Infrastructure/IEntityMapper.cs
rename to DigitalData.Core.Application/Interfaces/Repository/IEntityMapper.cs
index d37bf92..37348dc 100644
--- a/DigitalData.Core.Abstractions/Infrastructure/IEntityMapper.cs
+++ b/DigitalData.Core.Application/Interfaces/Repository/IEntityMapper.cs
@@ -1,4 +1,4 @@
-namespace DigitalData.Core.Abstractions.Infrastructure
+namespace DigitalData.Core.Application.Interfaces.Repository
{
///
/// Defines methods for mapping between entities and Data Transfer Objects (DTOs).
diff --git a/DigitalData.Core.Abstractions/Infrastructure/IRepository.cs b/DigitalData.Core.Application/Interfaces/Repository/IRepository.cs
similarity index 94%
rename from DigitalData.Core.Abstractions/Infrastructure/IRepository.cs
rename to DigitalData.Core.Application/Interfaces/Repository/IRepository.cs
index c64cc02..885a055 100644
--- a/DigitalData.Core.Abstractions/Infrastructure/IRepository.cs
+++ b/DigitalData.Core.Application/Interfaces/Repository/IRepository.cs
@@ -1,6 +1,6 @@
using System.Linq.Expressions;
-namespace DigitalData.Core.Abstractions.Infrastructure;
+namespace DigitalData.Core.Application.Interfaces.Repository;
public interface IRepository
{
diff --git a/DigitalData.Core.Application/JWTService.cs b/DigitalData.Core.Application/JWTService.cs
index 20854e3..f55505d 100644
--- a/DigitalData.Core.Application/JWTService.cs
+++ b/DigitalData.Core.Application/JWTService.cs
@@ -1,4 +1,5 @@
-using Microsoft.IdentityModel.Tokens;
+using DigitalData.Core.Application.Interfaces;
+using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Cryptography;
diff --git a/DigitalData.Core.Application/ReadService.cs b/DigitalData.Core.Application/ReadService.cs
index 35499cb..245f24b 100644
--- a/DigitalData.Core.Application/ReadService.cs
+++ b/DigitalData.Core.Application/ReadService.cs
@@ -1,8 +1,8 @@
-using DigitalData.Core.Abstractions.Application;
-using DigitalData.Core.Abstractions.Infrastructure;
-using AutoMapper;
-using DigitalData.Core.DTO;
+using AutoMapper;
using DigitalData.Core.Abstractions;
+using DigitalData.Core.Application.DTO;
+using DigitalData.Core.Application.Interfaces;
+using DigitalData.Core.Application.Interfaces.Repository;
namespace DigitalData.Core.Application
{
diff --git a/DigitalData.Core.Client/BaseHttpClientService.cs b/DigitalData.Core.Client/BaseHttpClientService.cs
index f6a541a..211cad0 100644
--- a/DigitalData.Core.Client/BaseHttpClientService.cs
+++ b/DigitalData.Core.Client/BaseHttpClientService.cs
@@ -1,4 +1,4 @@
-using DigitalData.Core.Abstractions.Client;
+using DigitalData.Core.Client.Interface;
using System.Diagnostics.CodeAnalysis;
using System.Net;
using System.Web;
diff --git a/DigitalData.Core.Client/DIExtensions.cs b/DigitalData.Core.Client/DIExtensions.cs
index b7d4b64..85dcf08 100644
--- a/DigitalData.Core.Client/DIExtensions.cs
+++ b/DigitalData.Core.Client/DIExtensions.cs
@@ -1,4 +1,4 @@
-using DigitalData.Core.Abstractions.Client;
+using DigitalData.Core.Client.Interface;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
diff --git a/DigitalData.Core.Client/HttpClientService.cs b/DigitalData.Core.Client/HttpClientService.cs
index e007957..be89980 100644
--- a/DigitalData.Core.Client/HttpClientService.cs
+++ b/DigitalData.Core.Client/HttpClientService.cs
@@ -1,4 +1,4 @@
-using DigitalData.Core.Abstractions.Client;
+using DigitalData.Core.Client.Interface;
using Microsoft.Extensions.Options;
using System.Net;
diff --git a/DigitalData.Core.Abstractions/Client/IBaseHttpClientService.cs b/DigitalData.Core.Client/Interface/IBaseHttpClientService.cs
similarity index 93%
rename from DigitalData.Core.Abstractions/Client/IBaseHttpClientService.cs
rename to DigitalData.Core.Client/Interface/IBaseHttpClientService.cs
index 058944a..682151c 100644
--- a/DigitalData.Core.Abstractions/Client/IBaseHttpClientService.cs
+++ b/DigitalData.Core.Client/Interface/IBaseHttpClientService.cs
@@ -1,6 +1,6 @@
using System.Net;
-namespace DigitalData.Core.Abstractions.Client
+namespace DigitalData.Core.Client.Interface
{
public interface IBaseHttpClientService
{
diff --git a/DigitalData.Core.Abstractions/Client/IHttpClientOptions.cs b/DigitalData.Core.Client/Interface/IHttpClientOptions.cs
similarity index 83%
rename from DigitalData.Core.Abstractions/Client/IHttpClientOptions.cs
rename to DigitalData.Core.Client/Interface/IHttpClientOptions.cs
index 23c4f35..c471cea 100644
--- a/DigitalData.Core.Abstractions/Client/IHttpClientOptions.cs
+++ b/DigitalData.Core.Client/Interface/IHttpClientOptions.cs
@@ -1,4 +1,4 @@
-namespace DigitalData.Core.Abstractions.Client
+namespace DigitalData.Core.Client.Interface
{
public interface IHttpClientOptions
{
diff --git a/DigitalData.Core.Abstractions/Client/IHttpClientService.cs b/DigitalData.Core.Client/Interface/IHttpClientService.cs
similarity index 72%
rename from DigitalData.Core.Abstractions/Client/IHttpClientService.cs
rename to DigitalData.Core.Client/Interface/IHttpClientService.cs
index fc186ee..47b9ae2 100644
--- a/DigitalData.Core.Abstractions/Client/IHttpClientService.cs
+++ b/DigitalData.Core.Client/Interface/IHttpClientService.cs
@@ -1,4 +1,4 @@
-namespace DigitalData.Core.Abstractions.Client
+namespace DigitalData.Core.Client.Interface
{
public interface IHttpClientService : IBaseHttpClientService where TClientOptions : IHttpClientOptions
{
diff --git a/DigitalData.Core.Client/ServiceFactory.cs b/DigitalData.Core.Client/ServiceFactory.cs
index 7a114ec..3cf4bd9 100644
--- a/DigitalData.Core.Client/ServiceFactory.cs
+++ b/DigitalData.Core.Client/ServiceFactory.cs
@@ -1,4 +1,4 @@
-using DigitalData.Core.Abstractions.Client;
+using DigitalData.Core.Client.Interface;
using Microsoft.Extensions.DependencyInjection;
namespace DigitalData.Core.Client
diff --git a/DigitalData.Core.Infrastructure.AutoMapper/EntityAutoMapper.cs b/DigitalData.Core.Infrastructure.AutoMapper/EntityAutoMapper.cs
index b3e1106..29b4986 100644
--- a/DigitalData.Core.Infrastructure.AutoMapper/EntityAutoMapper.cs
+++ b/DigitalData.Core.Infrastructure.AutoMapper/EntityAutoMapper.cs
@@ -1,5 +1,5 @@
using AutoMapper;
-using DigitalData.Core.Abstractions.Infrastructure;
+using DigitalData.Core.Application.Interfaces.Repository;
namespace DigitalData.Core.Infrastructure.AutoMapper;
diff --git a/DigitalData.Core.Infrastructure/CRUDRepository.cs b/DigitalData.Core.Infrastructure/CRUDRepository.cs
index 93de22e..3724cf3 100644
--- a/DigitalData.Core.Infrastructure/CRUDRepository.cs
+++ b/DigitalData.Core.Infrastructure/CRUDRepository.cs
@@ -1,5 +1,5 @@
using DigitalData.Core.Abstractions;
-using DigitalData.Core.Abstractions.Infrastructure;
+using DigitalData.Core.Application.Interfaces.Repository;
using Microsoft.EntityFrameworkCore;
namespace DigitalData.Core.Infrastructure
diff --git a/DigitalData.Core.Infrastructure/DbRepository.cs b/DigitalData.Core.Infrastructure/DbRepository.cs
index 25c0185..b1d1216 100644
--- a/DigitalData.Core.Infrastructure/DbRepository.cs
+++ b/DigitalData.Core.Infrastructure/DbRepository.cs
@@ -1,4 +1,4 @@
-using DigitalData.Core.Abstractions.Infrastructure;
+using DigitalData.Core.Application.Interfaces.Repository;
using Microsoft.EntityFrameworkCore;
using System.Linq.Expressions;
diff --git a/DigitalData.Core.Infrastructure/DependencyInjection.cs b/DigitalData.Core.Infrastructure/DependencyInjection.cs
index ee55815..7ed67d5 100644
--- a/DigitalData.Core.Infrastructure/DependencyInjection.cs
+++ b/DigitalData.Core.Infrastructure/DependencyInjection.cs
@@ -1,4 +1,4 @@
-using DigitalData.Core.Abstractions.Infrastructure;
+using DigitalData.Core.Application.Interfaces.Repository;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
diff --git a/DigitalData.Core.Infrastructure/DigitalData.Core.Infrastructure.csproj b/DigitalData.Core.Infrastructure/DigitalData.Core.Infrastructure.csproj
index 9ade81c..ca6a5cf 100644
--- a/DigitalData.Core.Infrastructure/DigitalData.Core.Infrastructure.csproj
+++ b/DigitalData.Core.Infrastructure/DigitalData.Core.Infrastructure.csproj
@@ -41,6 +41,7 @@
+
diff --git a/DigitalData.Core.Infrastructure/EntityConfigurationOptions.cs b/DigitalData.Core.Infrastructure/EntityConfigurationOptions.cs
index c3ab1bb..af02d37 100644
--- a/DigitalData.Core.Infrastructure/EntityConfigurationOptions.cs
+++ b/DigitalData.Core.Infrastructure/EntityConfigurationOptions.cs
@@ -1,4 +1,4 @@
-using DigitalData.Core.Abstractions.Infrastructure;
+using DigitalData.Core.Application.Interfaces.Repository;
using Microsoft.Extensions.DependencyInjection;
namespace DigitalData.Core.Infrastructure;
diff --git a/DigitalData.Core.Tests/Client/BaseHttpClientServiceTest.cs b/DigitalData.Core.Tests/Client/BaseHttpClientServiceTest.cs
index b23d39f..d1d2b36 100644
--- a/DigitalData.Core.Tests/Client/BaseHttpClientServiceTest.cs
+++ b/DigitalData.Core.Tests/Client/BaseHttpClientServiceTest.cs
@@ -1,5 +1,5 @@
-using DigitalData.Core.Abstractions.Client;
-using DigitalData.Core.Client;
+using DigitalData.Core.Client;
+using DigitalData.Core.Client.Interface;
using Microsoft.Extensions.DependencyInjection;
namespace DigitalData.Core.Tests.Client
diff --git a/DigitalData.Core.Tests/Infrastructure/DbRepositoryTests.cs b/DigitalData.Core.Tests/Infrastructure/DbRepositoryTests.cs
index 507d6f0..6debe52 100644
--- a/DigitalData.Core.Tests/Infrastructure/DbRepositoryTests.cs
+++ b/DigitalData.Core.Tests/Infrastructure/DbRepositoryTests.cs
@@ -6,8 +6,8 @@ using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using System.Reflection;
-using DigitalData.Core.Abstractions.Infrastructure;
using DigitalData.Core.Infrastructure.AutoMapper;
+using DigitalData.Core.Application.Interfaces.Repository;
public class DbRepositoryTests
{