17 Commits

Author SHA1 Message Date
Developer 02
fde0398c89 Bump version to 2.4.2 in project file
Updated the version number, assembly version, and file version from 2.4.1 to 2.4.2 in the DigitalData.Core.Infrastructure.csproj file.
2025-09-30 20:00:36 +02:00
Developer 02
ebf79309d1 Refactor Static class to be generic
Updated the `Static` class in the `DigitalData.Core.Infrastructure` namespace to a generic version `Static<TEntity>`. Removed the original non-generic class and the `GetRepository<TEntity>` method. The new generic class provides a method to retrieve a repository for a specific entity type `TEntity`, enhancing type safety and usability.
2025-09-30 19:58:22 +02:00
Developer 02
5a3cbe8ecf Improve exception message in Static.cs
Updated the exception message in the `Static` class to clarify that services cannot be accessed after the service provider has been created. This change enhances the clarity of the error for developers.
2025-09-30 19:56:58 +02:00
Developer 02
d5a8619b4d Add repository access methods to Static class
This commit introduces two new properties in the `Static` class: `Repository` and `GetRepository<TEntity>()`. The `Repository` property allows retrieval of an `IRepository` instance from the service provider, while `GetRepository<TEntity>()` provides access to a specific `IRepository<TEntity>`. These additions improve the ease of accessing repository instances for data operations.
2025-09-30 19:55:40 +02:00
Developer 02
7689005a14 Add conditional compilation for framework-specific code
Introduce framework-specific handling in `Static.cs` to support both NET and NETFRAMEWORK. Implement lazy initialization for service collection and provider, ensuring proper access and error handling.
2025-09-30 19:48:00 +02:00
Developer 02
05568b1551 Add conditional compilation for .NET Framework support
Updated code to support conditional compilation for .NET Framework and .NET.
Introduced nullable reference types in `DbRepository.cs` and ensured proper initialization of service registration queues in `DependencyInjection.cs`.
Modified `DbRepositoryFactory.cs` and `DbSetFactory.cs` to maintain consistent structure across frameworks.
These changes enhance compatibility and improve type safety.
2025-09-30 18:36:15 +02:00
Developer 02
e0ca11ffc0 Enhance CRUDRepository with conditional compilation
Added preprocessor directive for NET framework support.
Updated using directives to include repository and EF Core
namespaces. Adjusted code structure for improved compatibility.
2025-09-30 18:18:14 +02:00
Developer 02
f1ab8db710 Add support for .NET Framework 4.6.2 in project file
Updated `DigitalData.Core.Infrastructure.csproj` to include .NET Framework version 4.6.2 alongside net7.0, net8.0, and net9.0. Configured framework-specific settings for nullable reference types, implicit usings, and language versions. Added a new `<ItemGroup>` for net462 to reference `Microsoft.EntityFrameworkCore` version 3.1.32.
2025-09-30 18:11:38 +02:00
Developer 02
ca08709d99 Bump version to 1.3.2 in project configuration
Updated the version number, assembly version, and file version in DigitalData.Core.Abstraction.Application.csproj from 1.3.1 to 1.3.2 to reflect the new release of the application.
2025-09-30 17:52:24 +02:00
Developer 02
28e415dee1 Add .NET Framework support in Extensions.cs
Introduce conditional compilation directives for the .NET Framework, including necessary using statements and a modified namespace declaration. Add a closing brace for the class definition to ensure compatibility across different target frameworks.
2025-09-30 17:50:53 +02:00
Developer 02
2cedfbe91b Add conditional compilation for IRepositoryFactory
Updated the namespace declaration in `IRepositoryFactory.cs` to support conditional compilation for .NET and .NET Framework. The `Get<TEntity>()` method now conditionally includes the `public` access modifier based on the target framework. Adjusted the interface structure to ensure proper compilation and organization.
2025-09-30 17:49:26 +02:00
Developer 02
d4d1d2b69f Add conditional compilation for .NET Framework support
Introduce conditional compilation directives in the IRepository interface to support .NET Framework. Update method signatures to conditionally include the `public` access modifier for compatibility across frameworks. Adjust the Entity method to remove the `public` modifier, enhancing flexibility while maintaining existing functionality.
2025-09-30 17:47:24 +02:00
Developer 02
74a625a863 Enhance framework compatibility and code readability
Added preprocessor directives for .NET framework compatibility.
Modified `using` directives to be framework-specific.
Improved code formatting for better readability.
Introduced obsolete attributes for deprecated methods,
recommending `MediatR` as an alternative.
Added XML documentation for clarity and maintainability.
2025-09-30 17:33:51 +02:00
Developer 02
07ab7f0c62 refactor(DataResult): update to execute if NET 2025-09-30 17:03:39 +02:00
Developer 02
e74a740abd refactor(CookieConsentSettings): update to be executed only on NET 2025-09-30 16:57:54 +02:00
Developer 02
dfa3cd1a58 refactor(BaseDto): update to compile only in net 2025-09-30 16:57:05 +02:00
Developer 02
0dd4930f1b refactor(DigitalData.Core.Abstraction.Application): update to support net 462 2025-09-30 16:52:02 +02:00
28 changed files with 591 additions and 315 deletions

View File

@@ -1,4 +1,5 @@
namespace DigitalData.Core.Abstraction.Application.DTO;
#if NET
namespace DigitalData.Core.Abstraction.Application.DTO;
/// <summary>
/// Represents a base Data Transfer Object (DTO) with an identifier.
@@ -14,4 +15,5 @@ public record BaseDTO<TId>(TId Id) where TId : notnull
/// </summary>
/// <returns>A hash code for the current object, derived from the identifier.</returns>
public override int GetHashCode() => Id.GetHashCode();
}
}
#endif

View File

@@ -1,74 +1,75 @@
namespace DigitalData.Core.Abstraction.Application.DTO
#if NET
namespace DigitalData.Core.Abstraction.Application.DTO;
/// <summary>
/// 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
/// </summary>
public class CookieConsentSettings
{
/// <summary>
/// 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
/// URL to the privacy policy page.
/// </summary>
public class CookieConsentSettings
{
/// <summary>
/// URL to the privacy policy page.
/// </summary>
public string? PrivacyPolicyUrl { get; set; }
public string? PrivacyPolicyUrl { get; set; }
/// <summary>
/// URL to the legal notice page.
/// </summary>
public string? LegalNoticeUrl { get; set; }
/// <summary>
/// URL to the legal notice page.
/// </summary>
public string? LegalNoticeUrl { get; set; }
/// <summary>
/// URL to the content of the dialog box.
/// </summary>
public string? ContentURL { get; set; }
/// <summary>
/// URL to the content of the dialog box.
/// </summary>
public string? ContentURL { get; set; }
/// <summary>
/// CSS class for the 'Agree' button.
/// </summary>
public string? ButtonAgreeClass { get; set; }
/// <summary>
/// CSS class for the 'Agree' button.
/// </summary>
public string? ButtonAgreeClass { get; set; }
/// <summary>
/// CSS class for the 'Don't Agree' button.
/// </summary>
public string? ButtonDontAgreeClass { get; set; }
/// <summary>
/// CSS class for the 'Don't Agree' button.
/// </summary>
public string? ButtonDontAgreeClass { get; set; }
/// <summary>
/// CSS class for the 'Save' button.
/// </summary>
public string? ButtonSaveClass { get; set; }
/// <summary>
/// CSS class for the 'Save' button.
/// </summary>
public string? ButtonSaveClass { get; set; }
/// <summary>
/// Language in which the modal is displayed.
/// </summary>
public string? Lang { get; set; }
/// <summary>
/// Language in which the modal is displayed.
/// </summary>
public string? Lang { get; set; }
/// <summary>
/// Default language for the modal if the user's browser language is not supported.
/// </summary>
public string? DefaultLang { get; set; }
/// <summary>
/// Default language for the modal if the user's browser language is not supported.
/// </summary>
public string? DefaultLang { get; set; }
/// <summary>
/// Name of the cookie used to store the consent status.
/// </summary>
public string? CookieName { get; set; }
/// <summary>
/// Name of the cookie used to store the consent status.
/// </summary>
public string? CookieName { get; set; }
/// <summary>
/// Number of days the cookie will be stored.
/// </summary>
public int CookieStorageDays { get; set; }
/// <summary>
/// Number of days the cookie will be stored.
/// </summary>
public int CookieStorageDays { get; set; }
/// <summary>
/// Identifier for the modal dialog element.
/// </summary>
public string? ModalId { get; set; }
/// <summary>
/// Identifier for the modal dialog element.
/// </summary>
public string? ModalId { get; set; }
/// <summary>
/// Indicates whether to also store the settings in the browser's localStorage.
/// </summary>
public bool AlsoUseLocalStorage { get; set; }
/// <summary>
/// Indicates whether to also store the settings in the browser's localStorage.
/// </summary>
public bool AlsoUseLocalStorage { get; set; }
/// <summary>
/// List of categories for cookie consent.
/// </summary>
public List<string>? Categories { get; set; }
}
}
/// <summary>
/// List of categories for cookie consent.
/// </summary>
public List<string>? Categories { get; set; }
}
#endif

View File

@@ -1,4 +1,5 @@
using Microsoft.Extensions.Configuration;
#if NET
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using System.Configuration;
@@ -31,4 +32,5 @@ public static class DIExtensions
});
return services;
}
}
}
#endif

View File

@@ -1,4 +1,5 @@
using Microsoft.Extensions.Logging;
#if NET
using Microsoft.Extensions.Logging;
using System.Text;
namespace DigitalData.Core.Abstraction.Application.DTO;
@@ -19,7 +20,7 @@ public static class DTOExtensions
[Obsolete("Use DigitalData.Core.Exceptions and .Middleware")]
public static T Message<T>(this T result, string? message) where T : Result
{
if(message is not null)
if (message is not null)
result.Messages.Add(message);
return result;
}
@@ -28,7 +29,7 @@ public static class DTOExtensions
internal static IEnumerable<T> FilterNull<T>(this IEnumerable<T?> list)
{
foreach (var item in list)
if(item is not null)
if (item is not null)
yield return item;
}
@@ -328,7 +329,7 @@ public static class DTOExtensions
/// <param name="end">The ending string.</param>
/// <returns>The joined string.</returns>
[Obsolete("Use DigitalData.Core.Exceptions and .Middleware")]
public static string Join<T>(this IEnumerable<T> values, string start = "", string seperator = ". ", string end = ".")
public static string Join<T>(this IEnumerable<T> values, string start = "", string seperator = ". ", string end = ".")
=> new StringBuilder(start).Append(string.Join(seperator, values)).Append(end).ToString();
/// <summary>
@@ -342,7 +343,7 @@ public static class DTOExtensions
[Obsolete("Use DigitalData.Core.Exceptions and .Middleware")]
public static void LogNotice(this ILogger logger, IEnumerable<Notice> notices, string start = ": ", string seperator = ". ", string end = ".\n")
{
foreach(LogLevel level in Enum.GetValues(typeof(LogLevel)))
foreach (LogLevel level in Enum.GetValues(typeof(LogLevel)))
{
var logNotices = notices.Where(n => n.Level == level);
@@ -350,7 +351,7 @@ public static class DTOExtensions
continue;
var sb = new StringBuilder();
foreach(Notice notice in logNotices)
foreach (Notice notice in logNotices)
{
if (notice.Flag is not null)
sb.Append(notice.Flag);
@@ -390,4 +391,5 @@ public static class DTOExtensions
/// <returns>True if the data result is false; otherwise, false.</returns>
[Obsolete("Use DigitalData.Core.Exceptions and .Middleware")]
public static bool IsWrong(this DataResult<bool> bResult) => !bResult.Data;
}
}
#endif

View File

@@ -1,4 +1,5 @@
using System.Text.Json.Serialization;
#if NET
using System.Text.Json.Serialization;
namespace DigitalData.Core.Abstraction.Application.DTO;
@@ -25,4 +26,5 @@ public class DataResult<T> : Result
/// <returns>A failed <see cref="DataResult{I}"/> with the current messages and notices.</returns>
[Obsolete("Use DigitalData.Core.Exceptions and .Middleware")]
public DataResult<I> ToFail<I>() => Fail<I>().Message(Messages).Notice(Notices);
}
}
#endif

View File

@@ -1,4 +1,5 @@
namespace DigitalData.Core.Abstraction.Application.DTO;
#if NET
namespace DigitalData.Core.Abstraction.Application.DTO;
/// <summary>
/// Defines flags that indicate specific types of status or conditions in a service operation.
@@ -47,4 +48,5 @@ public enum Flag
/// This flag is used when the specified item or condition does not exist or is unavailable.
/// </summary>
NotFound
}
}
#endif

View File

@@ -1,4 +1,5 @@
using Microsoft.Extensions.Logging;
#if NET
using Microsoft.Extensions.Logging;
namespace DigitalData.Core.Abstraction.Application.DTO;
@@ -25,4 +26,5 @@ public class Notice
/// </summary>
[Obsolete("Use DigitalData.Core.Exceptions and .Middleware")]
public List<string> Messages { get; init; } = new();
}
}
#endif

View File

@@ -1,4 +1,5 @@
using System.Text.Json.Serialization;
#if NET
using System.Text.Json.Serialization;
namespace DigitalData.Core.Abstraction.Application.DTO;
@@ -105,4 +106,5 @@ public class Result
Data = default
};
#pragma warning restore CS8601 // Possible null reference assignment.
}
}
#endif

View File

@@ -1,9 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net7.0;net8.0;net9.0</TargetFrameworks>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<TargetFrameworks>net462;net7.0;net8.0;net9.0</TargetFrameworks>
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
<Description>This package defines the abstraction layer for the DigitalData.Core.Application module, providing interfaces and contracts for application services, repositories, and infrastructure components in alignment with Clean Architecture principles.</Description>
<PackageId>DigitalData.Core.Abstraction.Application</PackageId>
@@ -14,9 +12,9 @@
<PackageIcon>core_icon.png</PackageIcon>
<RepositoryUrl>http://git.dd:3000/AppStd/WebCoreModules.git</RepositoryUrl>
<PackageTags>digital data core application clean architecture abstraction</PackageTags>
<Version>1.3.1</Version>
<AssemblyVersion>1.3.1</AssemblyVersion>
<FileVersion>1.3.1</FileVersion>
<Version>1.3.2</Version>
<AssemblyVersion>1.3.2</AssemblyVersion>
<FileVersion>1.3.2</FileVersion>
</PropertyGroup>
<ItemGroup>
@@ -26,6 +24,20 @@
</None>
</ItemGroup>
<!-- disable for net462 -->
<PropertyGroup Condition="'$(TargetFramework)' == 'net462'">
<Nullable>disable</Nullable>
<ImplicitUsings>disable</ImplicitUsings>
<LangVersion>7.3</LangVersion>
</PropertyGroup>
<!-- enable for net7 and more -->
<PropertyGroup Condition="'$(TargetFramework)' == 'net7.0' Or '$(TargetFramework)' == 'net8.0' Or '$(TargetFramework)' == 'net9.0'">
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<LangVersion>latest</LangVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Configuration" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Localization.Abstractions" Version="7.0.16" />
@@ -36,6 +48,12 @@
<PackageReference Include="System.Security.Cryptography.Cng" Version="5.0.0" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net462'">
<PackageReference Include="AutoMapper" Version="10.1.1" />
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Caching.Abstractions" Version="7.0.0" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net7.0'">
<PackageReference Include="AutoMapper" Version="13.0.1" />
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="7.0.0" />

View File

@@ -1,4 +1,5 @@
namespace DigitalData.Core.Abstraction.Application;
#if NET
namespace DigitalData.Core.Abstraction.Application;
/// <summary>
/// Provides extension methods for retrieving the value of an 'Id' property from objects.
@@ -91,4 +92,5 @@ public static class EntityExtensions
#pragma warning restore CS8601
return id is not null;
}
}
}
#endif

View File

@@ -1,4 +1,5 @@
namespace DigitalData.Core.Abstraction.Application
#if NET
namespace DigitalData.Core.Abstraction.Application
{
/// <summary>
/// Implements a simplified CRUD service interface that uses a single Data Transfer Object (DTO) type for all CRUD operations,
@@ -18,4 +19,5 @@
where TDto : class where TEntity : class
{
}
}
}
#endif

View File

@@ -1,25 +1,26 @@
using DigitalData.Core.Abstraction.Application.DTO;
#if NET
using DigitalData.Core.Abstraction.Application.DTO;
namespace DigitalData.Core.Abstraction.Application
namespace DigitalData.Core.Abstraction.Application;
[Obsolete("Use MediatR")]
public interface ICRUDService<TCreateDto, TReadDto, TEntity, TId> : IReadService<TReadDto, TEntity, TId>
where TCreateDto : class where TReadDto : class where TEntity : class
{
[Obsolete("Use MediatR")]
public interface ICRUDService<TCreateDto, TReadDto, TEntity, TId> : IReadService<TReadDto, TEntity, TId>
where TCreateDto : class where TReadDto : class where TEntity : class
{
/// <summary>
/// Asynchronously creates a new entity based on the provided <paramref name="createDto"/> and returns the identifier of the created entity wrapped in a <see cref="DataResult{TId}"/>.
/// The <see cref="DataResult{TId}"/> contains the identifier of the newly created entity on success or an error message on failure.
/// </summary>
/// <param name="createDto">The data transfer object containing the information for the new entity.</param>
/// <returns>A task representing the asynchronous operation, with a <see cref="DataResult{TId}"/> containing the identifier of the created entity or an error message.</returns>
Task<DataResult<TReadDto>> CreateAsync(TCreateDto createDto);
/// <summary>
/// Asynchronously creates a new entity based on the provided <paramref name="createDto"/> and returns the identifier of the created entity wrapped in a <see cref="DataResult{TId}"/>.
/// The <see cref="DataResult{TId}"/> contains the identifier of the newly created entity on success or an error message on failure.
/// </summary>
/// <param name="createDto">The data transfer object containing the information for the new entity.</param>
/// <returns>A task representing the asynchronous operation, with a <see cref="DataResult{TId}"/> containing the identifier of the created entity or an error message.</returns>
Task<DataResult<TReadDto>> CreateAsync(TCreateDto createDto);
/// <summary>
/// Updates an existing entity based on the provided updateDTO and returns the result wrapped in an IServiceMessage,
/// indicating the success or failure of the operation, including the error messages on failure.
/// </summary>
/// <param name="updateDto">The updateDTO with updated values for the entity.</param>
/// <returns>An Result indicating the outcome of the update operation, with an appropriate message.</returns>
Task<Result> UpdateAsync<TUpdateDto>(TUpdateDto updateDto);
}
}
/// <summary>
/// Updates an existing entity based on the provided updateDTO and returns the result wrapped in an IServiceMessage,
/// indicating the success or failure of the operation, including the error messages on failure.
/// </summary>
/// <param name="updateDto">The updateDTO with updated values for the entity.</param>
/// <returns>An Result indicating the outcome of the update operation, with an appropriate message.</returns>
Task<Result> UpdateAsync<TUpdateDto>(TUpdateDto updateDto);
}
#endif

View File

@@ -1,94 +1,96 @@
using DigitalData.Core.Abstraction.Application.DTO;
#if NET
using DigitalData.Core.Abstraction.Application.DTO;
using System.DirectoryServices;
namespace DigitalData.Core.Abstraction.Application
namespace DigitalData.Core.Abstraction.Application;
[Obsolete("Use DigitalData.ActiveDirectory")]
public interface IDirectorySearchService
{
public interface IDirectorySearchService
{
public string ServerName { get; }
public string ServerName { get; }
public string Root { get; }
public string Root { get; }
string SearchRootPath { get; }
string SearchRootPath { get; }
Dictionary<string, string> CustomSearchFilters { get; }
Dictionary<string, string> CustomSearchFilters { get; }
/// <summary>
/// Creates the connections to the server and returns a Boolean value that specifies
/// whether the specified username and password are valid.
/// </summary>
/// <param name="userName">The username that is validated on the server. See the Remarks section
/// for more information on the format of userName.</param>
/// <param name="password">The password that is validated on the server.</param>
/// <returns>True if the credentials are valid; otherwise, false.</returns>
bool ValidateCredentials(string userName, string password);
/// <summary>
/// Creates the connections to the server and returns a Boolean value that specifies
/// whether the specified username and password are valid.
/// </summary>
/// <param name="userName">The username that is validated on the server. See the Remarks section
/// for more information on the format of userName.</param>
/// <param name="password">The password that is validated on the server.</param>
/// <returns>True if the credentials are valid; otherwise, false.</returns>
bool ValidateCredentials(string userName, string password);
/// <summary>
/// Creates the connections to the server asynchronously and returns a Boolean value that specifies
/// whether the specified username and password are valid.
/// </summary>
/// <param name="userName">The username that is validated on the server. See the Remarks section
/// for more information on the format of userName.</param>
/// <param name="password">The password that is validated on the server.</param>
/// <returns>True if the credentials are valid; otherwise, false.</returns>
Task<bool> ValidateCredentialsAsync(string userName, string password);
/// <summary>
/// Creates the connections to the server asynchronously and returns a Boolean value that specifies
/// whether the specified username and password are valid.
/// </summary>
/// <param name="userName">The username that is validated on the server. See the Remarks section
/// for more information on the format of userName.</param>
/// <param name="password">The password that is validated on the server.</param>
/// <returns>True if the credentials are valid; otherwise, false.</returns>
Task<bool> ValidateCredentialsAsync(string userName, string password);
/// <summary>
/// Finds all directory entries matching the specified filter.
/// </summary>
/// <param name="searchRoot">The search root.</param>
/// <param name="filter">The search filter.</param>
/// <param name="searchScope">The search scope.</param>
/// <param name="sizeLimit">The size limit.</param>
/// <param name="properties">The properties to load.</param>
/// <returns>A <see cref="DataResult{T}"/> containing the results.</returns>
DataResult<IEnumerable<ResultPropertyCollection>> FindAll(DirectoryEntry searchRoot, string filter, SearchScope searchScope = SearchScope.Subtree, int sizeLimit = 5000, params string[] properties);
/// <summary>
/// Finds all directory entries matching the specified filter.
/// </summary>
/// <param name="searchRoot">The search root.</param>
/// <param name="filter">The search filter.</param>
/// <param name="searchScope">The search scope.</param>
/// <param name="sizeLimit">The size limit.</param>
/// <param name="properties">The properties to load.</param>
/// <returns>A <see cref="DataResult{T}"/> containing the results.</returns>
DataResult<IEnumerable<ResultPropertyCollection>> FindAll(DirectoryEntry searchRoot, string filter, SearchScope searchScope = SearchScope.Subtree, int sizeLimit = 5000, params string[] properties);
/// <summary>
/// Finds all directory entries matching the specified filter asynchronously.
/// </summary>
/// <param name="searchRoot">The search root.</param>
/// <param name="filter">The search filter.</param>
/// <param name="searchScope">The search scope.</param>
/// <param name="sizeLimit">The size limit.</param>
/// <param name="properties">The properties to load.</param>
/// <returns>A <see cref="DataResult{T}"/> containing the results.</returns>
Task<DataResult<IEnumerable<ResultPropertyCollection>>> FindAllAsync(DirectoryEntry searchRoot, string filter, SearchScope searchScope = SearchScope.Subtree, int sizeLimit = 5000, params string[] properties);
/// <summary>
/// Finds all directory entries matching the specified filter asynchronously.
/// </summary>
/// <param name="searchRoot">The search root.</param>
/// <param name="filter">The search filter.</param>
/// <param name="searchScope">The search scope.</param>
/// <param name="sizeLimit">The size limit.</param>
/// <param name="properties">The properties to load.</param>
/// <returns>A <see cref="DataResult{T}"/> containing the results.</returns>
Task<DataResult<IEnumerable<ResultPropertyCollection>>> FindAllAsync(DirectoryEntry searchRoot, string filter, SearchScope searchScope = SearchScope.Subtree, int sizeLimit = 5000, params string[] properties);
/// <summary>
/// Finds all directory entries matching the specified filter, using the user cache.
/// </summary>
/// <param name="username">The username.</param>
/// <param name="filter">The search filter.</param>
/// <param name="searchScope">The search scope.</param>
/// <param name="sizeLimit">The size limit.</param>
/// <param name="properties">The properties to load.</param>
/// <returns>A <see cref="DataResult{T}"/> containing the results.</returns>
DataResult<IEnumerable<ResultPropertyCollection>> FindAllByUserCache(string username, string filter, SearchScope searchScope = SearchScope.Subtree, int sizeLimit = 5000, params string[] properties);
/// <summary>
/// Finds all directory entries matching the specified filter, using the user cache.
/// </summary>
/// <param name="username">The username.</param>
/// <param name="filter">The search filter.</param>
/// <param name="searchScope">The search scope.</param>
/// <param name="sizeLimit">The size limit.</param>
/// <param name="properties">The properties to load.</param>
/// <returns>A <see cref="DataResult{T}"/> containing the results.</returns>
DataResult<IEnumerable<ResultPropertyCollection>> FindAllByUserCache(string username, string filter, SearchScope searchScope = SearchScope.Subtree, int sizeLimit = 5000, params string[] properties);
/// <summary>
/// Finds all directory entries matching the specified filter asynchronously, using the user cache.
/// </summary>
/// <param name="username">The username.</param>
/// <param name="filter">The search filter.</param>
/// <param name="searchScope">The search scope.</param>
/// <param name="sizeLimit">The size limit.</param>
/// <param name="properties">The properties to load.</param>
/// <returns>A <see cref="DataResult{T}"/> containing the results.</returns>
Task<DataResult<IEnumerable<ResultPropertyCollection>>> FindAllByUserCacheAsync(string username, string filter, SearchScope searchScope = SearchScope.Subtree, int sizeLimit = 5000, params string[] properties);
/// <summary>
/// Finds all directory entries matching the specified filter asynchronously, using the user cache.
/// </summary>
/// <param name="username">The username.</param>
/// <param name="filter">The search filter.</param>
/// <param name="searchScope">The search scope.</param>
/// <param name="sizeLimit">The size limit.</param>
/// <param name="properties">The properties to load.</param>
/// <returns>A <see cref="DataResult{T}"/> containing the results.</returns>
Task<DataResult<IEnumerable<ResultPropertyCollection>>> FindAllByUserCacheAsync(string username, string filter, SearchScope searchScope = SearchScope.Subtree, int sizeLimit = 5000, params string[] properties);
/// <summary>
/// Sets the search root in the cache.
/// </summary>
/// <param name="username">The directory entry username.</param>
/// <param name="password">The directory entry password.</param>
void SetSearchRootCache(string username, string password);
/// <summary>
/// Sets the search root in the cache.
/// </summary>
/// <param name="username">The directory entry username.</param>
/// <param name="password">The directory entry password.</param>
void SetSearchRootCache(string username, string password);
/// <summary>
/// Gets the search root from the cache.
/// </summary>
/// <param name="username">The directory entry username.</param>
/// <returns>The cached <see cref="DirectoryEntry"/> if found; otherwise, null.</returns>
DirectoryEntry? GetSearchRootCache(string username);
}
}
/// <summary>
/// Gets the search root from the cache.
/// </summary>
/// <param name="username">The directory entry username.</param>
/// <returns>The cached <see cref="DirectoryEntry"/> if found; otherwise, null.</returns>
DirectoryEntry? GetSearchRootCache(string username);
}
#endif

View File

@@ -1,41 +1,42 @@
using Microsoft.IdentityModel.Tokens;
#if NET
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Cryptography;
namespace DigitalData.Core.Abstraction.Application
namespace DigitalData.Core.Abstraction.Application;
/// <summary>
/// Defines the operations for JWT service handling claims of type <typeparamref name="TClaimValue"/>.
/// </summary>
public interface IJWTService<TClaimValue>
{
/// <summary>
/// Defines the operations for JWT service handling claims of type <typeparamref name="TClaimValue"/>.
/// Generates a symmetric security key with the specified byte size.
/// </summary>
public interface IJWTService<TClaimValue>
/// <param name="byteSize">The size of the security key in bytes. Default is 32 bytes.</param>
/// <returns>A new instance of <see cref="SymmetricSecurityKey"/>.</returns>
public static SymmetricSecurityKey GenerateSecurityKey(int byteSize = 32)
{
/// <summary>
/// Generates a symmetric security key with the specified byte size.
/// </summary>
/// <param name="byteSize">The size of the security key in bytes. Default is 32 bytes.</param>
/// <returns>A new instance of <see cref="SymmetricSecurityKey"/>.</returns>
public static SymmetricSecurityKey GenerateSecurityKey(int byteSize = 32)
{
using var rng = RandomNumberGenerator.Create();
var randomBytes = new byte[byteSize];
rng.GetBytes(randomBytes);
var securityKey = new SymmetricSecurityKey(randomBytes);
using var rng = RandomNumberGenerator.Create();
var randomBytes = new byte[byteSize];
rng.GetBytes(randomBytes);
var securityKey = new SymmetricSecurityKey(randomBytes);
return securityKey;
}
/// <summary>
/// Generates a token based on the specified claim value.
/// </summary>
/// <param name="claimValue">The claim value to encode in the token.</param>
/// <returns>A JWT as a string.</returns>
string GenerateToken(TClaimValue claimValue);
/// <summary>
/// Reads and validates a security token from a string representation.
/// </summary>
/// <param name="token">The JWT to read.</param>
/// <returns>A <see cref="JwtSecurityToken"/> if the token is valid; otherwise, null.</returns>
JwtSecurityToken? ReadSecurityToken(string token);
return securityKey;
}
}
/// <summary>
/// Generates a token based on the specified claim value.
/// </summary>
/// <param name="claimValue">The claim value to encode in the token.</param>
/// <returns>A JWT as a string.</returns>
string GenerateToken(TClaimValue claimValue);
/// <summary>
/// Reads and validates a security token from a string representation.
/// </summary>
/// <param name="token">The JWT to read.</param>
/// <returns>A <see cref="JwtSecurityToken"/> if the token is valid; otherwise, null.</returns>
JwtSecurityToken? ReadSecurityToken(string token);
}
#endif

View File

@@ -1,39 +1,40 @@
using DigitalData.Core.Abstraction.Application.DTO;
#if NET
using DigitalData.Core.Abstraction.Application.DTO;
namespace DigitalData.Core.Abstraction.Application
namespace DigitalData.Core.Abstraction.Application;
[Obsolete("Use MediatR")]
public interface IReadService<TReadDto, TEntity, TId>
where TReadDto : class where TEntity : class
{
[Obsolete("Use MediatR")]
public interface IReadService<TReadDto, TEntity, TId>
where TReadDto : class where TEntity : class
{
/// <summary>
/// Retrieves an entity by its identifier and returns its readDTO representation wrapped in an IServiceResult,
/// including the readDTO on success or null and an error message on failure.
/// </summary>
/// <param name="id">The identifier of the entity to retrieve.</param>
/// <returns>An DataResult containing the readDTO representing the found entity or null, with an appropriate message.</returns>
Task<DataResult<TReadDto>> ReadByIdAsync(TId id);
/// <summary>
/// Retrieves an entity by its identifier and returns its readDTO representation wrapped in an IServiceResult,
/// including the readDTO on success or null and an error message on failure.
/// </summary>
/// <param name="id">The identifier of the entity to retrieve.</param>
/// <returns>An DataResult containing the readDTO representing the found entity or null, with an appropriate message.</returns>
Task<DataResult<TReadDto>> ReadByIdAsync(TId id);
/// <summary>
/// Retrieves all entities and returns their readDTO representations wrapped in an IServiceResult,
/// including a collection of readDTOs on success or an error message on failure.
/// </summary>
/// <returns>An DataResult containing a collection of readDTOs representing all entities or an error message.</returns>
Task<DataResult<IEnumerable<TReadDto>>> ReadAllAsync();
/// <summary>
/// Deletes an entity by its identifier and returns the result wrapped in an IServiceMessage,
/// indicating the success or failure of the operation, including the error messages on failure.
/// </summary>
/// <param name="id">The identifier of the entity to delete.</param>
/// <returns>An Result indicating the outcome of the delete operation, with an appropriate message.</returns>
Task<Result> DeleteAsyncById(TId id);
/// <summary>
/// Retrieves all entities and returns their readDTO representations wrapped in an IServiceResult,
/// including a collection of readDTOs on success or an error message on failure.
/// </summary>
/// <returns>An DataResult containing a collection of readDTOs representing all entities or an error message.</returns>
Task<DataResult<IEnumerable<TReadDto>>> ReadAllAsync();
/// <summary>
/// Asynchronously checks if an entity with the specified identifier exists within the data store.
/// </summary>
/// <param name="id">The identifier of the entity to check.</param>
/// <returns>A task that represents the asynchronous operation. The task result contains a boolean value indicating whether the entity exists.</returns>
Task<bool> HasEntity(TId id);
}
}
/// <summary>
/// Deletes an entity by its identifier and returns the result wrapped in an IServiceMessage,
/// indicating the success or failure of the operation, including the error messages on failure.
/// </summary>
/// <param name="id">The identifier of the entity to delete.</param>
/// <returns>An Result indicating the outcome of the delete operation, with an appropriate message.</returns>
Task<Result> DeleteAsyncById(TId id);
/// <summary>
/// Asynchronously checks if an entity with the specified identifier exists within the data store.
/// </summary>
/// <param name="id">The identifier of the entity to check.</param>
/// <returns>A task that represents the asynchronous operation. The task result contains a boolean value indicating whether the entity exists.</returns>
Task<bool> HasEntity(TId id);
}
#endif

View File

@@ -1,7 +1,19 @@
using System.Linq.Expressions;
using DigitalData.Core.Abstractions.Interfaces;
#if NETFRAMEWORK
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using System.Linq;
#endif
namespace DigitalData.Core.Abstraction.Application.Repository;
namespace DigitalData.Core.Abstraction.Application.Repository
#if NET
;
#elif NETFRAMEWORK
{
#endif
public static class Extensions
{
@@ -60,4 +72,8 @@ public static class Extensions
=> repository.Entity<TEntity>().DeleteAsync(query, cancel);
#endregion
#endregion
}
}
#if NETFRAMEWORK
}
#endif

View File

@@ -1,4 +1,5 @@
namespace DigitalData.Core.Abstraction.Application.Repository
#if NET
namespace DigitalData.Core.Abstraction.Application.Repository
{
/// <summary>
/// Defines the contract for CRUD operations on a repository for entities of type TEntity.
@@ -60,4 +61,5 @@
/// </remarks>
Task<int> CountAsync(TId id);
}
}
}
#endif

View File

@@ -1,4 +1,7 @@
namespace DigitalData.Core.Abstraction.Application.Repository
#if NETFRAMEWORK
using System.Collections.Generic;
#endif
namespace DigitalData.Core.Abstraction.Application.Repository
{
/// <summary>
/// Defines methods for mapping between entities and Data Transfer Objects (DTOs).

View File

@@ -1,50 +1,105 @@
using DigitalData.Core.Abstractions.Interfaces;
using System.Linq.Expressions;
#if NETFRAMEWORK
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using System.Linq;
#endif
namespace DigitalData.Core.Abstraction.Application.Repository;
namespace DigitalData.Core.Abstraction.Application.Repository
#if NET
;
#elif NETFRAMEWORK
{
#endif
public interface IRepository<TEntity>
{
#region Create
public Task<TEntity> CreateAsync(TEntity entity, CancellationToken cancel = default);
#if NET
public
#endif
Task<TEntity> CreateAsync(TEntity entity, CancellationToken cancel = default);
public Task<IEnumerable<TEntity>> CreateAsync(IEnumerable<TEntity> entities, CancellationToken cancel = default);
#if NET
public
#endif
Task<IEnumerable<TEntity>> CreateAsync(IEnumerable<TEntity> entities, CancellationToken cancel = default);
public Task<TEntity> CreateAsync<TDto>(TDto dto, CancellationToken cancel = default);
#if NET
public
#endif
Task<TEntity> CreateAsync<TDto>(TDto dto, CancellationToken cancel = default);
public Task<IEnumerable<TEntity>> CreateAsync<TDto>(IEnumerable<TDto> dtos, CancellationToken cancel = default);
#if NET
public
#endif
Task<IEnumerable<TEntity>> CreateAsync<TDto>(IEnumerable<TDto> dtos, CancellationToken cancel = default);
#endregion Create
#region Read
public IQueryable<TEntity> Where(Expression<Func<TEntity, bool>> expression);
#if NET
public
#endif
IQueryable<TEntity> Where(Expression<Func<TEntity, bool>> expression);
public IEnumerable<TEntity> GetAll();
#if NET
public
#endif
IEnumerable<TEntity> GetAll();
public Task<IEnumerable<TEntity>> GetAllAsync(CancellationToken cancel = default);
#if NET
public
#endif
Task<IEnumerable<TEntity>> GetAllAsync(CancellationToken cancel = default);
#endregion Read
#region Update
public Task UpdateAsync<TDto>(TDto dto, Expression<Func<TEntity, bool>> expression, CancellationToken cancel = default);
#if NET
public
#endif
Task UpdateAsync<TDto>(TDto dto, Expression<Func<TEntity, bool>> expression, CancellationToken cancel = default);
public Task UpdateAsync<TDto>(TDto dto, Func<IQueryable<TEntity>, IQueryable<TEntity>> query, CancellationToken cancel = default);
#if NET
public
#endif
Task UpdateAsync<TDto>(TDto dto, Func<IQueryable<TEntity>, IQueryable<TEntity>> query, CancellationToken cancel = default);
#endregion Update
#region Delete
public Task DeleteAsync(Expression<Func<TEntity, bool>> expression, CancellationToken cancel = default);
#if NET
public
#endif
Task DeleteAsync(Expression<Func<TEntity, bool>> expression, CancellationToken cancel = default);
public Task DeleteAsync(Func<IQueryable<TEntity>, IQueryable<TEntity>> query, CancellationToken cancel = default);
#if NET
public
#endif
Task DeleteAsync(Func<IQueryable<TEntity>, IQueryable<TEntity>> query, CancellationToken cancel = default);
#endregion Delete
#region Obsolete
[Obsolete("Use CreateAsync, UpdateAsync or DeleteAsync")]
public IQueryable<TEntity> Read();
#if NET
public
#endif
IQueryable<TEntity> Read();
[Obsolete("Use IRepository<TEntity>.Where")]
public IQueryable<TEntity> ReadOnly();
#if NET
public
#endif
IQueryable<TEntity> ReadOnly();
#endregion
}
public interface IRepository
{
public IRepository<TEntity> Entity<TEntity>() where TEntity : IEntity;
}
IRepository<TEntity> Entity<TEntity>() where TEntity : IEntity;
}
#if NETFRAMEWORK
}
#endif

View File

@@ -1,6 +1,18 @@
namespace DigitalData.Core.Abstraction.Application.Repository;
namespace DigitalData.Core.Abstraction.Application.Repository
#if NET
;
#elif NETFRAMEWORK
{
#endif
public interface IRepositoryFactory
{
public IRepository<TEntity> Get<TEntity>();
}
#if NET
public
#endif
IRepository<TEntity> Get<TEntity>();
}
#if NETFRAMEWORK
}
#endif

View File

@@ -21,6 +21,12 @@
<FileVersion>4.1.1</FileVersion>
</PropertyGroup>
<ItemGroup>
<None Include="..\Assets\core_icon.png">
<Pack>True</Pack>
<PackagePath>\</PackagePath>
</None>
</ItemGroup>
<!-- disable for net462 -->
<PropertyGroup Condition="'$(TargetFramework)' == 'net462'">
@@ -36,13 +42,6 @@
<LangVersion>latest</LangVersion>
</PropertyGroup>
<ItemGroup>
<None Include="..\..\nuget-package-icons\core_icon.png">
<Pack>True</Pack>
<PackagePath>\</PackagePath>
</None>
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net7.0'">
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="7.0.4" />

View File

@@ -1,4 +1,5 @@
using DigitalData.Core.Abstraction.Application;
#if NET
using DigitalData.Core.Abstraction.Application;
using DigitalData.Core.Abstraction.Application.Repository;
using Microsoft.EntityFrameworkCore;
@@ -110,4 +111,5 @@ namespace DigitalData.Core.Infrastructure
/// </remarks>
public virtual async Task<int> CountAsync(TId id) => await _dbSet.Where(e => e.GetId().Equals(id)).CountAsync();
}
}
}
#endif

View File

@@ -4,8 +4,20 @@ using DigitalData.Core.Abstractions.Interfaces;
using DigitalData.Core.Infrastructure.Factory;
using Microsoft.EntityFrameworkCore;
using System.Linq.Expressions;
#if NETFRAMEWORK
using System.Collections.Generic;
using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
#endif
namespace DigitalData.Core.Infrastructure;
namespace DigitalData.Core.Infrastructure
#if NET
;
#elif NETFRAMEWORK
{
#endif
public class DbRepository<TDbContext, TEntity> : IRepository<TEntity> where TDbContext : DbContext where TEntity : class
{
@@ -13,9 +25,17 @@ public class DbRepository<TDbContext, TEntity> : IRepository<TEntity> where TDbC
protected internal readonly DbSet<TEntity> Entities;
public IMapper? Mapper { get; }
public IMapper
#if NET
?
#endif
Mapper { get; }
public DbRepository(TDbContext context, DbSetFactory<TDbContext, TEntity> factory, IMapper? mapper = null)
public DbRepository(TDbContext context, DbSetFactory<TDbContext, TEntity> factory, IMapper
#if NET
?
#endif
mapper = null)
{
Context = context;
Entities = factory.Create(context);
@@ -37,10 +57,19 @@ public class DbRepository<TDbContext, TEntity> : IRepository<TEntity> where TDbC
return entities;
}
public virtual Task<TEntity> CreateAsync<TDto>(TDto dto, CancellationToken cancel = default) => CreateAsync(Mapper!.Map<TEntity>(dto), cancel);
public virtual Task<TEntity> CreateAsync<TDto>(TDto dto, CancellationToken cancel = default)
=> CreateAsync(Mapper
#if NET
!
#endif
.Map<TEntity>(dto), cancel);
public virtual Task<IEnumerable<TEntity>> CreateAsync<TDto>(IEnumerable<TDto> dtos, CancellationToken cancel = default)
=> CreateAsync(Mapper!.Map<IEnumerable<TEntity>>(dtos), cancel);
=> CreateAsync(Mapper
#if NET
!
#endif
.Map<IEnumerable<TEntity>>(dtos), cancel);
#endregion Create
#region Read
@@ -60,7 +89,11 @@ public class DbRepository<TDbContext, TEntity> : IRepository<TEntity> where TDbC
for (int i = entities.Count - 1; i >= 0; i--)
{
Mapper!.Map(dto, entities[i]);
Mapper
#if NET
!
#endif
.Map(dto, entities[i]);
Entities.Update(entities[i]);
}
@@ -103,4 +136,8 @@ public class DbRepository : IRepository
}
public IRepository<TEntity> Entity<TEntity>() where TEntity : IEntity => _factory.Get<TEntity>();
}
}
#if NETFRAMEWORK
}
#endif

View File

@@ -4,8 +4,18 @@ using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using System.ComponentModel.DataAnnotations.Schema;
using System.Reflection;
#if NETFRAMEWORK
using System.Collections.Generic;
using System;
using System.Linq;
#endif
namespace DigitalData.Core.Infrastructure;
namespace DigitalData.Core.Infrastructure
#if NET
;
#elif NETFRAMEWORK
{
#endif
public static class DependencyInjection
{
@@ -28,13 +38,13 @@ public static class DependencyInjection
public class RepositoryConfiguration
{
// 1. register from assembly
private readonly Queue<Action<IServiceCollection>> RegsFromAssembly = new();
private readonly Queue<Action<IServiceCollection>> RegsFromAssembly = new Queue<Action<IServiceCollection>>();
// 2. register entities (can overwrite)
private readonly Queue<Action<IServiceCollection>> RegsEntity = new();
private readonly Queue<Action<IServiceCollection>> RegsEntity = new Queue<Action<IServiceCollection>>();
// 3. register db set factories (can overwrite)
private readonly Queue<Action<IServiceCollection>> RegsDbSetFactory = new();
private readonly Queue<Action<IServiceCollection>> RegsDbSetFactory = new Queue<Action<IServiceCollection>>();
internal void RegisterAllServices(IServiceCollection services)
{
@@ -76,7 +86,11 @@ public static class DependencyInjection
.GetMethod(nameof(AddDbSetFactory),
BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public);
var genericMethod = addDbSetFactoryMethod!.MakeGenericMethod(typeof(TDbContext), entityType);
var genericMethod = addDbSetFactoryMethod
#if NET
!
#endif
.MakeGenericMethod(typeof(TDbContext), entityType);
genericMethod.Invoke(null, new [] { services, null });
#endregion DbSetFactory
}
@@ -85,7 +99,11 @@ public static class DependencyInjection
RegsFromAssembly.Enqueue(reg);
}
public void RegisterEntity<TDbContext, TEntity>(Func<TDbContext, DbSet<TEntity>>? dbSetFactory = null)
public void RegisterEntity<TDbContext, TEntity>(Func<TDbContext, DbSet<TEntity>>
#if NET
?
#endif
dbSetFactory = null)
where TDbContext : DbContext
where TEntity : class
{
@@ -109,12 +127,25 @@ public static class DependencyInjection
queue.Dequeue().Invoke(services);
}
internal static IServiceCollection AddDbSetFactory<TDbContext, TEntity>(this IServiceCollection services, Func<TDbContext, DbSet<TEntity>>? create = null)
internal static IServiceCollection AddDbSetFactory<TDbContext, TEntity>(this IServiceCollection services, Func<TDbContext, DbSet<TEntity>>
#if NET
?
#endif
create = null)
where TDbContext : DbContext
where TEntity : class
{
#if NET
create ??= ctx => ctx.Set<TEntity>();
#elif NETFRAMEWORK
if(create is null)
create = ctx => ctx.Set<TEntity>();
#endif
services.AddSingleton(_ => new DbSetFactory<TDbContext, TEntity>(create));
return services;
}
}
}
#if NETFRAMEWORK
}
#endif

View File

@@ -1,9 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net7.0;net8.0;net9.0</TargetFrameworks>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<TargetFrameworks>net462;net7.0;net8.0;net9.0</TargetFrameworks>
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
<PackageId>DigitalData.Core.Infrastructure</PackageId>
<Authors>Digital Data GmbH</Authors>
@@ -15,9 +13,9 @@
<RepositoryUrl>http://git.dd:3000/AppStd/WebCoreModules.git</RepositoryUrl>
<RepositoryType>digital data core abstractions clean architecture</RepositoryType>
<PackageTags>digital data core infrastructure clean architecture</PackageTags>
<Version>2.4.1</Version>
<AssemblyVersion>2.4.1</AssemblyVersion>
<FileVersion>2.4.1</FileVersion>
<Version>2.4.2</Version>
<AssemblyVersion>2.4.2</AssemblyVersion>
<FileVersion>2.4.2</FileVersion>
</PropertyGroup>
<ItemGroup>
@@ -27,6 +25,24 @@
</None>
</ItemGroup>
<!-- disable for net462 -->
<PropertyGroup Condition="'$(TargetFramework)' == 'net462'">
<Nullable>disable</Nullable>
<ImplicitUsings>disable</ImplicitUsings>
<LangVersion>7.3</LangVersion>
</PropertyGroup>
<!-- enable for net7 and more -->
<PropertyGroup Condition="'$(TargetFramework)' == 'net7.0' Or '$(TargetFramework)' == 'net8.0' Or '$(TargetFramework)' == 'net9.0'">
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<LangVersion>latest</LangVersion>
</PropertyGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net462'">
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="3.1.32" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net7.0'">
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="7.0.20" />
</ItemGroup>

View File

@@ -1,7 +1,15 @@
using DigitalData.Core.Abstraction.Application.Repository;
using Microsoft.Extensions.DependencyInjection;
#if NETFRAMEWORK
using System;
#endif
namespace DigitalData.Core.Infrastructure.Factory;
namespace DigitalData.Core.Infrastructure.Factory
#if NET
;
#elif NETFRAMEWORK
{
#endif
public class DbRepositoryFactory : IRepositoryFactory
{
@@ -13,4 +21,8 @@ public class DbRepositoryFactory : IRepositoryFactory
}
public IRepository<TEntity> Get<TEntity>() => _provider.GetRequiredService<IRepository<TEntity>>();
}
}
#if NETFRAMEWORK
}
#endif

View File

@@ -1,6 +1,14 @@
using Microsoft.EntityFrameworkCore;
#if NETFRAMEWORK
using System;
#endif
namespace DigitalData.Core.Infrastructure.Factory;
namespace DigitalData.Core.Infrastructure.Factory
#if NET
;
#elif NETFRAMEWORK
{
#endif
public class DbSetFactory<TDbContext,TEntity> where TDbContext : DbContext where TEntity : class
{
@@ -10,4 +18,8 @@ public class DbSetFactory<TDbContext,TEntity> where TDbContext : DbContext where
{
Create = create;
}
}
}
#if NETFRAMEWORK
}
#endif

View File

@@ -0,0 +1,37 @@
#if NETFRAMEWORK
using System;
#endif
using DigitalData.Core.Abstraction.Application.Repository;
using Microsoft.Extensions.DependencyInjection;
namespace DigitalData.Core.Infrastructure
#if NET
;
#elif NETFRAMEWORK
{
#endif
public static class Static
{
private readonly static Lazy<IServiceCollection> LazyServices = new Lazy<IServiceCollection>(() => new ServiceCollection());
public static IServiceCollection Services => LazyProvider.IsValueCreated
? LazyServices.Value
: throw new InvalidOperationException("Services cannot be accessed after the Provider has been created.");
private static readonly Lazy<IServiceProvider> LazyProvider = new Lazy<IServiceProvider>(Services.BuildServiceProvider);
public static IServiceProvider Provider => LazyProvider.Value;
public static IRepository Repository => Provider.GetRequiredService<IRepository>();
}
public static class Static<TEntity>
{
public static IRepository<TEntity> Repository() => Static.Provider.GetRequiredService<IRepository<TEntity>>();
}
#if NETFRAMEWORK
}
#endif