Erweiterung der DTOs und Implementierung der Lokalisierungsdienste
- Neue DTO-Extension-Methoden hinzugefügt, um die Verarbeitung und Zuweisung von Nachrichten und Benachrichtigungen in Ergebnisobjekten zu vereinfachen. - Lokalisierungsunterstützung in der API-Schicht implementiert, einschließlich Cookie-basierter Lokalisierung und Konfiguration unterstützter Kulturen. - Die Integration von StringLocalizer in die API-Schicht wurde durchgeführt, um eine nahtlose Mehrsprachigkeit zu ermöglichen. - Fehlerbehandlung für fehlende Konfigurationseinstellungen verbessert. Die Änderungen verbessern die Flexibilität und Wartbarkeit des Codes und unterstützen eine effizientere Internationalisierung der Anwendung.
This commit is contained in:
22
DigitalData.Core.DTO/AutoMapperExtension.cs
Normal file
22
DigitalData.Core.DTO/AutoMapperExtension.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
using AutoMapper;
|
||||
|
||||
namespace DigitalData.Core.DTO
|
||||
{
|
||||
public static class AutoMapperExtension
|
||||
{
|
||||
/// <summary>
|
||||
/// Maps a source object to a destination object, or throws an exception if the mapping result is null.
|
||||
/// </summary>
|
||||
/// <typeparam name="TSource">The source object type.</typeparam>
|
||||
/// <typeparam name="TDestination">The destination object type.</typeparam>
|
||||
/// <param name="source">The source object to map from.</param>
|
||||
/// <returns>The mapped destination object.</returns>
|
||||
/// <exception cref="MappingResultNullException">Thrown when the mapping result is null.</exception>
|
||||
public static TDestination MapOrThrow<TDestination>(this IMapper mapper, object source)
|
||||
{
|
||||
return mapper.Map<TDestination>(source) ?? throw new AutoMapperMappingException(
|
||||
$"Mapping to {typeof(TDestination).FullName} resulted in a null object. " +
|
||||
"Hint: Ensure that the AutoMapper profile configuration for this mapping is correct.");
|
||||
}
|
||||
}
|
||||
}
|
||||
74
DigitalData.Core.DTO/CookieConsentSettings.cs
Normal file
74
DigitalData.Core.DTO/CookieConsentSettings.cs
Normal file
@@ -0,0 +1,74 @@
|
||||
namespace DigitalData.Core.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>
|
||||
/// URL to the privacy policy page.
|
||||
/// </summary>
|
||||
public string? PrivacyPolicyUrl { 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>
|
||||
/// 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 'Save' button.
|
||||
/// </summary>
|
||||
public string? ButtonSaveClass { 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>
|
||||
/// 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>
|
||||
/// 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>
|
||||
/// List of categories for cookie consent.
|
||||
/// </summary>
|
||||
public List<string>? Categories { get; set; }
|
||||
}
|
||||
}
|
||||
22
DigitalData.Core.DTO/DIExtensions.cs
Normal file
22
DigitalData.Core.DTO/DIExtensions.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using System.Configuration;
|
||||
|
||||
namespace DigitalData.Core.DTO
|
||||
{
|
||||
public static class DIExtensions
|
||||
{
|
||||
public static IServiceCollection AddCookieConsentSettings(this IServiceCollection services)
|
||||
{
|
||||
services.AddSingleton(sp =>
|
||||
{
|
||||
var configuration = sp.GetRequiredService<IConfiguration>();
|
||||
var settings = configuration.GetSection("CookieConsentSettings").Get<CookieConsentSettings>();
|
||||
return settings is null
|
||||
? throw new ConfigurationErrorsException("The 'CookieConsentSettings' section is missing or improperly configured in appsettings.json.")
|
||||
: settings;
|
||||
});
|
||||
return services;
|
||||
}
|
||||
}
|
||||
}
|
||||
110
DigitalData.Core.DTO/DTOExtensions.cs
Normal file
110
DigitalData.Core.DTO/DTOExtensions.cs
Normal file
@@ -0,0 +1,110 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.Text;
|
||||
|
||||
namespace DigitalData.Core.DTO
|
||||
{
|
||||
public static class DTOExtensions
|
||||
{
|
||||
public static T Message<T>(this T result, string message) where T : Result
|
||||
{
|
||||
result.Messages.Add(message);
|
||||
return result;
|
||||
}
|
||||
|
||||
public static T Message<T>(this T result, params string[] messages) where T : Result
|
||||
{
|
||||
result.Messages.AddRange(messages);
|
||||
return result;
|
||||
}
|
||||
|
||||
public static T Notice<T>(this T result, Notice notice) where T : Result
|
||||
{
|
||||
result.Notices.Add(notice);
|
||||
return result;
|
||||
}
|
||||
|
||||
public static T Notice<T>(this T result, params Notice[] notices) where T : Result
|
||||
{
|
||||
result.Notices.AddRange(notices);
|
||||
return result;
|
||||
}
|
||||
|
||||
public static T Notice<T>(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;
|
||||
}
|
||||
|
||||
public static T Notice<T>(this T result, LogLevel level, Enum flag, params string[] messages) where T : Result
|
||||
{
|
||||
result.Notices.Add(new Notice()
|
||||
{
|
||||
Flag = flag,
|
||||
Level = level,
|
||||
Messages = messages.ToList()
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
public static T Notice<T>(this T result, LogLevel level, params string[] messages) where T : Result
|
||||
{
|
||||
result.Notices.Add(new Notice()
|
||||
{
|
||||
Flag = null,
|
||||
Level = level,
|
||||
Messages = messages.ToList()
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
public static I Then<I>(this Result result, Func<I> Try, Func<List<string>, List<Notice>, I> Catch)
|
||||
{
|
||||
return result.IsSuccess ? Try() : Catch(result.Messages, result.Notices);
|
||||
}
|
||||
|
||||
public static I Then<T, I>(this DataResult<T> result, Func<T, I> Try, Func<List<string>, List<Notice>, I> Catch)
|
||||
{
|
||||
return result.IsSuccess ? Try(result.Data) : Catch(result.Messages, result.Notices);
|
||||
}
|
||||
|
||||
public static async Task<I> Then<I>(this Task<Result> tResult, Func<I> Try, Func<List<string>, List<Notice>, I> Catch)
|
||||
{
|
||||
Result result = await tResult;
|
||||
return result.IsSuccess ? Try() : Catch(result.Messages, result.Notices);
|
||||
}
|
||||
|
||||
public static async Task<I> Then<T, I>(this Task<DataResult<T>> tResult, Func<T, I> Try, Func<List<string>, List<Notice>, I> Catch)
|
||||
{
|
||||
DataResult<T> result = await tResult;
|
||||
return result.IsSuccess ? Try(result.Data) : Catch(result.Messages, result.Notices);
|
||||
}
|
||||
|
||||
public static void LogNotice<T>(this ILogger<T> logger, IEnumerable<Notice> 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());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
10
DigitalData.Core.DTO/DataResult.cs
Normal file
10
DigitalData.Core.DTO/DataResult.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace DigitalData.Core.DTO
|
||||
{
|
||||
public class DataResult<T> : Result
|
||||
{
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public required T Data { get; init; }
|
||||
}
|
||||
}
|
||||
17
DigitalData.Core.DTO/DigitalData.Core.DTO.csproj
Normal file
17
DigitalData.Core.DTO/DigitalData.Core.DTO.csproj
Normal file
@@ -0,0 +1,17 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="AutoMapper" Version="13.0.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="7.0.4" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="7.0.0" />
|
||||
<PackageReference Include="System.Configuration.ConfigurationManager" Version="7.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
44
DigitalData.Core.DTO/Flag.cs
Normal file
44
DigitalData.Core.DTO/Flag.cs
Normal file
@@ -0,0 +1,44 @@
|
||||
namespace DigitalData.Core.DTO
|
||||
{
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public enum Flag
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates a security breach or vulnerability has been detected during the service operation.
|
||||
/// </summary>
|
||||
SecurityBreach,
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
DataIntegrityIssue,
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
SecurityBreachOrDataIntegrity,
|
||||
|
||||
/// <summary>
|
||||
/// Indicates a possible security breach during the service operation.
|
||||
/// </summary>
|
||||
PossibleSecurityBreach,
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
PossibleDataIntegrityIssue,
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
PossibleSecurityBreachOrDataIntegrity
|
||||
}
|
||||
}
|
||||
11
DigitalData.Core.DTO/Notice.cs
Normal file
11
DigitalData.Core.DTO/Notice.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace DigitalData.Core.DTO
|
||||
{
|
||||
public class Notice
|
||||
{
|
||||
public Enum? Flag { get; init; } = null;
|
||||
public LogLevel Level { get; init; } = LogLevel.None;
|
||||
public List<string> Messages { get; init; } = new();
|
||||
}
|
||||
}
|
||||
40
DigitalData.Core.DTO/Result.cs
Normal file
40
DigitalData.Core.DTO/Result.cs
Normal file
@@ -0,0 +1,40 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace DigitalData.Core.DTO
|
||||
{
|
||||
public class Result
|
||||
{
|
||||
public bool IsSuccess { get; set; } = false;
|
||||
|
||||
public List<string> Messages { get; init; } = new();
|
||||
|
||||
[JsonIgnore]
|
||||
public List<Notice> Notices = new();
|
||||
|
||||
public DataResult<T> Data<T>(T data) => new()
|
||||
{
|
||||
IsSuccess = IsSuccess,
|
||||
Messages = Messages,
|
||||
Notices = Notices,
|
||||
Data = data
|
||||
};
|
||||
|
||||
public static Result Success() => new() { IsSuccess = true };
|
||||
|
||||
public static Result Fail() => new() { IsSuccess = false };
|
||||
|
||||
public static DataResult<T> Success<T>(T data) => new()
|
||||
{
|
||||
IsSuccess = true,
|
||||
Data = data
|
||||
};
|
||||
|
||||
#pragma warning disable CS8601 // Possible null reference assignment.
|
||||
public static DataResult<T> Fail<T>() => new()
|
||||
{
|
||||
IsSuccess = false,
|
||||
Data = default
|
||||
};
|
||||
#pragma warning restore CS8601 // Possible null reference assignment.
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user