Skip to content

Commit

Permalink
Better nullability support and muti-targetting#
Browse files Browse the repository at this point in the history
  • Loading branch information
bdongus committed Dec 4, 2023
1 parent 167bc4e commit bdb7f9e
Show file tree
Hide file tree
Showing 51 changed files with 604 additions and 516 deletions.
4 changes: 3 additions & 1 deletion .github/workflows/dotnet.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ jobs:
- name: Setup .NET
uses: actions/setup-dotnet@v3
with:
dotnet-version: 7.0.x
dotnet-version: |
8.0.x
6.0.x
- name: Restore dependencies
run: |
dotnet nuget add source https://nuget.telerik.com/v3/index.json -n MyTelerikFeed -u api-key -p ${{secrets.TELERIK_API_KEY}} --store-password-in-clear-text
Expand Down
5 changes: 4 additions & 1 deletion idee5.Common.Data.Tests/ServiceCollectionTests.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Microsoft.Extensions.DependencyInjection;
#if !NETSTANDARD
using Microsoft.Extensions.DependencyInjection;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Collections.Generic;
using Telerik.JustMock;
Expand Down Expand Up @@ -41,3 +42,5 @@ public void CanAddAsyncQueryHandlers() {
Assert.AreEqual(1, serviceDescriptors.Count);
}
}

#endif
10 changes: 5 additions & 5 deletions idee5.Common.Data.Tests/ValidGLNTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ public class ValidGLNTests {
[TestMethod]
public void EmptyStringIsValid() {
// Arrange
var attribute = new ValidGLNAttribute();
var attribute = new IsValidGLNAttribute();

// Act
bool result = attribute.IsValid(string.Empty);
Expand All @@ -18,7 +18,7 @@ public void EmptyStringIsValid() {
[TestMethod]
public void NullIsValid() {
// Arrange
var attribute = new ValidGLNAttribute();
var attribute = new IsValidGLNAttribute();

// Act
bool result = attribute.IsValid(null);
Expand All @@ -30,7 +30,7 @@ public void NullIsValid() {
[TestMethod]
public void CanValidateGLN() {
// Arrange
var attribute = new ValidGLNAttribute();
var attribute = new IsValidGLNAttribute();

// Act
bool result = attribute.IsValid("4025692000004");
Expand All @@ -42,7 +42,7 @@ public void CanValidateGLN() {
[TestMethod]
public void CanDetectInvalidateGLN() {
// Arrange
var attribute = new ValidGLNAttribute();
var attribute = new IsValidGLNAttribute();

// Act
bool result = attribute.IsValid("4025692000014");
Expand All @@ -54,7 +54,7 @@ public void CanDetectInvalidateGLN() {
[TestMethod]
public void FailsOnNonString() {
// Arrange
var attribute = new ValidGLNAttribute();
var attribute = new IsValidGLNAttribute();

// Act
bool result = attribute.IsValid(42);
Expand Down
27 changes: 17 additions & 10 deletions idee5.Common.Data.Tests/idee5.Common.Data.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,29 +8,36 @@
</PropertyGroup>

<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>

<TargetFrameworks>net8.0;net6.0</TargetFrameworks>
<LangVersion>latest</LangVersion>
<IsPackable>false</IsPackable>

<AssemblyVersion>1.0.43.1055</AssemblyVersion>

<FileVersion>1.0.43.1055</FileVersion>
</PropertyGroup>

<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<DefineConstants>DEBUG;TRACE</DefineConstants>
</PropertyGroup>

<ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
<PackageReference Include="IsExternalInit" Version="1.0.3">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' != 'netstandard2.0'">
<PackageReference Include="JustMock.Commercial" Version="2023.3.1122.188" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="CqrsLite" Version="1.35.0" />
<PackageReference Include="JustMock.Commercial" Version="2023.2.719.137" />
<PackageReference Include="MELT" Version="0.8.0" />
<PackageReference Include="Microsoft.Extensions.Configuration" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="7.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.6.3" />
<PackageReference Include="MELT" Version="0.9.0" />
<PackageReference Include="Microsoft.Extensions.Configuration" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="8.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
<PackageReference Include="MSTest.TestAdapter" Version="3.1.1" />
<PackageReference Include="MSTest.TestFramework" Version="3.1.1" />
<PackageReference Include="System.Configuration.ConfigurationManager" Version="7.0.0" />
<PackageReference Include="System.Configuration.ConfigurationManager" Version="8.0.0" />
</ItemGroup>

<ItemGroup>
Expand Down
2 changes: 1 addition & 1 deletion idee5.Common.Data/ACompositeKeyRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public virtual void Add(IEnumerable<T> items) {
public abstract Task<IEnumerable<T>> GetAsync(Func<IQueryable<T>, IQueryable<T>> func, CancellationToken cancellationToken = default);

/// <inheritdoc />
public abstract Task<TResult> GetAsync<TResult>(Func<IQueryable<T>, TResult> func, CancellationToken cancellationToken = default);
public abstract Task<TResult?> GetAsync<TResult>(Func<IQueryable<T>, TResult> func, CancellationToken cancellationToken = default);

/// <inheritdoc />
public abstract void Remove(T item);
Expand Down
2 changes: 1 addition & 1 deletion idee5.Common.Data/ARepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public virtual void Add(IEnumerable<T> items) {
public abstract Task<IEnumerable<T>> GetAsync(Func<IQueryable<T>, IQueryable<T>> func, CancellationToken cancellationToken = default);

/// <inheritdoc />
public abstract Task<TResult> GetAsync<TResult>(Func<IQueryable<T>, TResult> func, CancellationToken cancellationToken = default);
public abstract Task<TResult?> GetAsync<TResult>(Func<IQueryable<T>, TResult> func, CancellationToken cancellationToken = default);

/// <inheritdoc />
public abstract void Remove(T item);
Expand Down
102 changes: 52 additions & 50 deletions idee5.Common.Data/AbstractEventStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,66 +21,68 @@ public abstract class AbstractEventStore<TEvent> {
/// </summary>
/// <param name="eventEntry"></param>
/// <returns>The event created from the event store</returns>
protected TEvent CreateEvent(EventEntry eventEntry) {
var eventType = ReflectionUtils.GetTypeFromName(eventEntry.EventName);
var eventProperyTypes = eventType.GetProperties().Select(ep => ep.PropertyType);
var cInfo = eventType.GetConstructors().First();
ParameterInfo[] paramsInfo = cInfo.GetParameters();
// create the event constructor
Delegate ctor;
lock (_locker) {
// check the cache
if (!_registeredTypes.TryGetValue(eventType, out ctor)) {
var argsExp = new Expression[paramsInfo.Length];
//create a single param of type object[] for the lambda expression
ParameterExpression param = Expression.Parameter(typeof(object[]), "args");
protected TEvent? CreateEvent(EventEntry eventEntry) {
Type? eventType = ReflectionUtils.GetTypeFromName(eventEntry.EventName);
TEvent? result = default;
if (eventType != null) {
ConstructorInfo cInfo = eventType.GetConstructors().First();
ParameterInfo[] paramsInfo = cInfo.GetParameters();
// create the event constructor
Delegate? ctor;
lock (_locker) {
// check the cache
if (!_registeredTypes.TryGetValue(eventType, out ctor)) {
var argsExp = new Expression[paramsInfo.Length];
//create a single param of type object[] for the lambda expression
ParameterExpression param = Expression.Parameter(typeof(object[]), "args");

for (int i = 0; i < paramsInfo.Length; i++) {
Expression index = Expression.Constant(i);
Type paramType = paramsInfo[i].ParameterType;
BinaryExpression paramAccessorExp = Expression.ArrayIndex(param, index);
argsExp[i] = Expression.Convert(paramAccessorExp, paramType);
}
for (int i = 0; i < paramsInfo.Length; i++) {
Expression index = Expression.Constant(i);
Type paramType = paramsInfo[i].ParameterType;
BinaryExpression paramAccessorExp = Expression.ArrayIndex(param, index);
argsExp[i] = Expression.Convert(paramAccessorExp, paramType);
}

NewExpression body = Expression.New(cInfo, argsExp);
//create a lambda with the New
//Expression as body and our param object[] as arg
var expr = Expression.Lambda(body, param);
ctor = expr.Compile();
_registeredTypes.Add(eventType, ctor);
NewExpression body = Expression.New(cInfo, argsExp);
//create a lambda with the New
//Expression as body and our param object[] as arg
var expr = Expression.Lambda(body, param);
ctor = expr.Compile();
_registeredTypes.Add(eventType, ctor);
}
}
}
// create the argument values
Dictionary<string, JsonElement>? dict = JsonSerializer.Deserialize<Dictionary<string, JsonElement>>(eventEntry.Data);
object?[] ps = new object[paramsInfo.Length];
for (int i = 0; i < paramsInfo.Length; i++) {
ParameterInfo item = paramsInfo[i];
Type paramType = item.ParameterType;
string paramName = item.Name;
object? p = null;
if (dict != null) {
JsonElement jsonElement = dict[paramName.CamelToPascalCase()];
if (jsonElement.ValueKind != JsonValueKind.Null) {
if (paramType == typeof(object)) {
p = jsonElement.GetRawText();
} else if (paramType == typeof(DateTimeRange)) {
p = jsonElement.Deserialize(paramType);
} else {
p = TypeDescriptor.GetConverter(paramType).ConvertFromInvariantString(jsonElement.ToString());
// create the argument values
Dictionary<string, JsonElement>? dict = JsonSerializer.Deserialize<Dictionary<string, JsonElement>>(eventEntry.Data);
object?[] ps = new object[paramsInfo.Length];
for (int i = 0; i < paramsInfo.Length; i++) {
ParameterInfo item = paramsInfo[i];
Type paramType = item.ParameterType;
string? paramName = item.Name;
object? p = null;
if (dict != null && paramName != null) {
JsonElement jsonElement = dict[paramName.CamelToPascalCase()];
if (jsonElement.ValueKind != JsonValueKind.Null) {
if (paramType == typeof(object)) {
p = jsonElement.GetRawText();
} else if (paramType == typeof(DateTimeRange)) {
p = jsonElement.Deserialize(paramType);
} else {
p = TypeDescriptor.GetConverter(paramType).ConvertFromInvariantString(jsonElement.ToString());
}
}
}
ps[i] = p;
}
ps[i] = p;
}
// create the event
TEvent result = (TEvent)ctor.DynamicInvoke(new object[] { ps });
if (dict != null) AdditionalMappings(ref result, dict);
return result;
// create the event
result = (TEvent?)ctor.DynamicInvoke(new object[] { ps });
if (dict != null) AdditionalMappings(ref result, dict);

} return result;
}
/// <summary>
/// Map properties not included in the event constructor. Eg. the timestamp or version
/// </summary>
/// <param name="ev">The newly created event.</param>
/// <param name="dict"><The dictionary of JSON elements/param>
protected abstract void AdditionalMappings(ref TEvent ev, Dictionary<string, JsonElement> dict);
protected abstract void AdditionalMappings(ref TEvent? ev, Dictionary<string, JsonElement> dict);
}
6 changes: 2 additions & 4 deletions idee5.Common.Data/AllowedValuesAttribute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,10 @@ public abstract class AllowedValuesAttribute : ValidationAttribute {
/// <param name="invalidValue">The invalid value.</param>
/// <param name="validValues">The list of valid values.</param>
/// <returns>The validation info/message.</returns>
protected abstract string GetInvalidValueMessage(object invalidValue, object[] validValues);
protected abstract string GetInvalidValueMessage(object? invalidValue, object[] validValues);

/// <inheritdoc/>
protected override ValidationResult IsValid(
object value,
ValidationContext validationContext) {
protected override ValidationResult? IsValid(object? value, ValidationContext validationContext) {
var values = GetValues(validationContext);
var exists = values.Contains(value);

Expand Down
8 changes: 5 additions & 3 deletions idee5.Common.Data/AppDomainExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@ public static class AppDomainExtensions {
/// <returns>Data directory path.</returns>
/// <exception cref="ArgumentNullException"><paramref name="appDomain"/> is <c>null</c>.</exception>
public static string GetDataDirectory(this AppDomain appDomain) {
if (appDomain == null)
throw new ArgumentNullException(nameof(appDomain));

#if NETSTANDARD2_0_OR_GREATER
if (appDomain == null) throw new ArgumentNullException(nameof(appDomain));
#else
ArgumentNullException.ThrowIfNull(appDomain);
#endif
var dataDirectory = appDomain.GetData("DataDirectory") as string;
if (!dataDirectory.HasValue()) {
dataDirectory = appDomain.BaseDirectory;
Expand Down
16 changes: 10 additions & 6 deletions idee5.Common.Data/AuditingRepositoryOfT.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,11 @@ protected AuditingRepository(ITimeProvider timeProvider, ICurrentUserIdProvider
/// <param name="item">The new item to add.</param>
/// <exception cref="ArgumentNullException"><paramref name="item"/> is <c>null</c>.</exception>
public override void Add(T item) {
if (item == null)
throw new ArgumentNullException(nameof(item));

#if NETSTANDARD2_0_OR_GREATER
if (item == null) throw new ArgumentNullException(nameof(item));
#else
ArgumentNullException.ThrowIfNull(item);
#endif
item.DateCreatedUTC = TimeProvider.UtcNow;
item.CreatedBy = CurrentUserProvider.GetCurrentUserId();
}
Expand All @@ -59,9 +61,11 @@ public override void Add(T item) {
/// <param name="item">The item to update.</param>
/// <exception cref="ArgumentNullException"><paramref name="item"/> is <c>null</c>.</exception>
public override void Update(T item) {
if (item == null)
throw new ArgumentNullException(nameof(item));

#if NETSTANDARD2_0_OR_GREATER
if (item == null) throw new ArgumentNullException(nameof(item));
#else
ArgumentNullException.ThrowIfNull(item);
#endif
item.DateModifiedUTC = TimeProvider.UtcNow;
item.ModifiedBy = CurrentUserProvider.GetCurrentUserId();
}
Expand Down
46 changes: 0 additions & 46 deletions idee5.Common.Data/CompositeValidationResult.cs

This file was deleted.

24 changes: 14 additions & 10 deletions idee5.Common.Data/DebugValidationReporter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,24 @@ namespace idee5.Common.Data;
public class DebugValidationReporter : IValidationResultReporter {
/// <inheritdoc/>
public void Report(ValidationResult validationResult) {
if (validationResult == null)
throw new ArgumentNullException(nameof(validationResult));

Console.WriteLine(String.Format(CultureInfo.InvariantCulture, Resources.MemberNames, validationResult.MemberNames.JoinAsString(",")));
Console.WriteLine(String.Format(CultureInfo.InvariantCulture, Resources.Error, validationResult.ErrorMessage));
#if NETSTANDARD2_0_OR_GREATER
if (validationResult == null) throw new ArgumentNullException(nameof(validationResult));
#else
ArgumentNullException.ThrowIfNull(validationResult);
#endif
Console.WriteLine(string.Format(CultureInfo.InvariantCulture, Resources.MemberNames, validationResult.MemberNames.JoinAsString(",")));
Console.WriteLine(string.Format(CultureInfo.InvariantCulture, Resources.Error, validationResult.ErrorMessage));
}

/// <inheritdoc/>
public Task ReportAsync(ValidationResult validationResult, CancellationToken cancellationToken = default) {
if (validationResult == null)
throw new ArgumentNullException(nameof(validationResult));

Console.WriteLine(String.Format(CultureInfo.InvariantCulture, Resources.MemberNames, validationResult.MemberNames.JoinAsString(",")));
Console.WriteLine(String.Format(CultureInfo.InvariantCulture, Resources.Error, validationResult.ErrorMessage));
#if NETSTANDARD2_0_OR_GREATER
if (validationResult == null) throw new ArgumentNullException(nameof(validationResult));
#else
ArgumentNullException.ThrowIfNull(validationResult);
#endif
Console.WriteLine(string.Format(CultureInfo.InvariantCulture, Resources.MemberNames, validationResult.MemberNames.JoinAsString(",")));
Console.WriteLine(string.Format(CultureInfo.InvariantCulture, Resources.Error, validationResult.ErrorMessage));
return Task.CompletedTask;
}
}
Loading

0 comments on commit bdb7f9e

Please sign in to comment.