Skip to content

Commit fa7ce89

Browse files
committed
Merge branch 'releases/6.x.x'
2 parents 724838f + f61bb31 commit fa7ce89

File tree

125 files changed

+9836
-7069
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

125 files changed

+9836
-7069
lines changed

samples/Newtonsoft.Json.AspNetCore.Samples/Controllers/DemoController.cs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using System;
1+
using System;
22
using Microsoft.AspNetCore.Mvc;
33
using Microsoft.Extensions.Logging;
44
using Thinktecture.SmartEnums;
@@ -77,6 +77,17 @@ public IActionResult RoundTrip(ProductName name)
7777
return Json(name);
7878
}
7979

80+
[HttpPost("boundary")]
81+
public IActionResult RoundTrip([FromBody] BoundaryWithJsonConverter boundary)
82+
{
83+
if (!ModelState.IsValid)
84+
return BadRequest(ModelState);
85+
86+
_logger.LogInformation("Round trip test with {Type}: {Boundary}", boundary.GetType().Name, boundary);
87+
88+
return Json(boundary);
89+
}
90+
8091
private IActionResult RoundTripValidatableEnum<T, TKey>(T value)
8192
where T : IValidatableEnum, IEnum<TKey>
8293
where TKey : notnull

samples/Newtonsoft.Json.AspNetCore.Samples/Program.cs

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -23,19 +23,6 @@ public static async Task Main()
2323
var loggerFactory = CreateLoggerFactory();
2424
var server = StartServerAsync(loggerFactory);
2525

26-
// calls
27-
// http://localhost:5000/api/category/fruits
28-
// http://localhost:5000/api/categoryWithConverter/fruits
29-
// http://localhost:5000/api/group/1
30-
// http://localhost:5000/api/group/42
31-
// http://localhost:5000/api/groupWithConverter/1
32-
// http://localhost:5000/api/groupWithConverter/42
33-
// http://localhost:5000/api/productType/groceries
34-
// http://localhost:5000/api/productType/invalid
35-
// http://localhost:5000/api/productTypeWithJsonConverter/groceries
36-
// http://localhost:5000/api/productTypeWithJsonConverter/invalid
37-
// http://localhost:5000/api/productName/bread
38-
// http://localhost:5000/api/productName/a
3926
await DoHttpRequestsAsync(loggerFactory.CreateLogger<Program>());
4027

4128
await server;
@@ -59,6 +46,8 @@ private static async Task DoHttpRequestsAsync(ILogger logger)
5946
await DoRequestAsync(logger, client, "productTypeWithJsonConverter/invalid"); // invalid
6047
await DoRequestAsync(logger, client, "productName/bread");
6148
await DoRequestAsync(logger, client, "productName/a"); // invalid
49+
await DoRequestAsync(logger, client, "boundary", BoundaryWithJsonConverter.Create(1, 2));
50+
await DoRequestAsync(logger, client, "boundary", jsonBody: "{ \"lower\": 2, \"upper\": 1 }");
6251
}
6352

6453
private static async Task DoRequestAsync(ILogger logger, HttpClient client, string url, object? body = null, string? jsonBody = null)

samples/Thinktecture.Runtime.Extensions.AspNetCore.Samples/Controllers/DemoController.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,17 @@ public IActionResult RoundTripWithQueryString(ProductType productType)
5252
return RoundTrip<ProductType, string>(productType);
5353
}
5454

55+
[HttpGet("boundaryWithFactories/{boundary}")]
56+
public IActionResult RoundTrip(BoundaryWithFactories boundary)
57+
{
58+
if (!ModelState.IsValid)
59+
return BadRequest(ModelState);
60+
61+
_logger.LogInformation("Round trip test with {Type}: {Boundary}", boundary.GetType().Name, boundary);
62+
63+
return Json(boundary);
64+
}
65+
5566
[HttpPost("productType")]
5667
public IActionResult RoundTripPost([FromBody] ProductType productType)
5768
{

samples/Thinktecture.Runtime.Extensions.AspNetCore.Samples/DateOnlyConverter.cs

Lines changed: 0 additions & 25 deletions
This file was deleted.

samples/Thinktecture.Runtime.Extensions.AspNetCore.Samples/Program.cs

Lines changed: 3 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -35,20 +35,6 @@ public static async Task Main()
3535

3636
await app;
3737

38-
// calls
39-
// http://localhost:5000/api/category/fruits
40-
// http://localhost:5000/api/categoryWithConverter/fruits
41-
// http://localhost:5000/api/group/1
42-
// http://localhost:5000/api/group/42
43-
// http://localhost:5000/api/groupWithConverter/1
44-
// http://localhost:5000/api/groupWithConverter/42
45-
// http://localhost:5000/api/productType/groceries
46-
// http://localhost:5000/api/productType/invalid
47-
// http://localhost:5000/api/productTypeWithJsonConverter/groceries
48-
// http://localhost:5000/api/productTypeWithJsonConverter/invalid
49-
// http://localhost:5000/api/productName/bread
50-
// http://localhost:5000/api/productName/a
51-
// http://localhost:5000/api/boundary
5238
await DoHttpRequestsAsync(loggerFactory.CreateLogger<Program>(), startMinimalWebApi);
5339

5440
await Task.Delay(5000);
@@ -69,6 +55,8 @@ private static async Task DoHttpRequestsAsync(ILogger logger, bool forMinimalWeb
6955
await DoRequestAsync(logger, client, "productType?productType=groceries");
7056
await DoRequestAsync(logger, client, "productType", "groceries");
7157
await DoRequestAsync(logger, client, "productType/invalid"); // invalid
58+
await DoRequestAsync(logger, client, "boundaryWithFactories/1:2"); // uses custom factory "[ValueObjectFactory<string>]"
59+
await DoRequestAsync(logger, client, "boundaryWithFactories/invalid"); // invalid
7260

7361
if (forMinimalWebApi)
7462
await DoRequestAsync(logger, client, "productTypeWithFilter?productType=invalid"); // invalid
@@ -143,7 +131,6 @@ private static Task StartServerAsync(ILoggerFactory loggerFactory)
143131
.AddJsonOptions(options =>
144132
{
145133
options.JsonSerializerOptions.Converters.Add(new ValueObjectJsonConverterFactory());
146-
options.JsonSerializerOptions.Converters.Add(new DateOnlyConverter());
147134
});
148135
})
149136
.Build();
@@ -159,7 +146,6 @@ private static Task StartMinimalWebApiAsync(ILoggerFactory loggerFactory)
159146
.ConfigureHttpJsonOptions(options =>
160147
{
161148
options.SerializerOptions.Converters.Add(new ValueObjectJsonConverterFactory());
162-
options.SerializerOptions.Converters.Add(new DateOnlyConverter());
163149
});
164150

165151
var app = builder.Build();
@@ -182,6 +168,7 @@ private static Task StartMinimalWebApiAsync(ILoggerFactory loggerFactory)
182168

183169
return next(context);
184170
});
171+
routeGroup.MapGet("boundaryWithFactories/{boundary}", (BoundaryWithFactories boundary) => boundary);
185172
routeGroup.MapPost("productType", ([FromBody] ProductType productType) => productType);
186173
routeGroup.MapPost("productTypeWrapper", ([FromBody] ProductTypeWrapper productType) => productType);
187174
routeGroup.MapGet("productTypeWithJsonConverter/{productType}", (ProductTypeWithJsonConverter productType) => productType);

samples/Thinktecture.Runtime.Extensions.AspNetCore.Samples/Validation/BoundValueObject.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
namespace Thinktecture.Validation;
55

66
public class BoundValueObject<T, TKey> : IBoundParam
7-
where T : IKeyedValueObject<T, TKey>
7+
where T : IValueObjectFactory<T, TKey>
88
where TKey : IParsable<TKey>
99
{
1010
private readonly T? _item;
@@ -30,7 +30,7 @@ public static bool TryParse(string s, IFormatProvider? formatProvider, out Bound
3030
}
3131
else
3232
{
33-
var validationResult = T.Validate(key, out var item);
33+
var validationResult = T.Validate(key, formatProvider, out var item);
3434

3535
if (validationResult is null || item is IValidatableEnum)
3636
{
@@ -47,7 +47,7 @@ public static bool TryParse(string s, IFormatProvider? formatProvider, out Bound
4747
}
4848

4949
public class BoundValueObject<T> : IBoundParam
50-
where T : IKeyedValueObject<T, string>
50+
where T : IValueObjectFactory<T, string>
5151
{
5252
private readonly T? _item;
5353
public T? Value => Error is null ? _item : throw new ValidationException(Error);
@@ -66,7 +66,7 @@ private BoundValueObject(string error)
6666

6767
public static bool TryParse(string s, IFormatProvider? formatProvider, out BoundValueObject<T> value)
6868
{
69-
var validationResult = T.Validate(s, out var item);
69+
var validationResult = T.Validate(s, formatProvider, out var item);
7070

7171
if (validationResult is null || item is IValidatableEnum)
7272
{

samples/Thinktecture.Runtime.Extensions.Benchmarking/BenchmarkContext.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ public BenchmarkContext()
1616
var services = new ServiceCollection()
1717
.AddLogging(builder => builder.AddConsole())
1818
.AddDbContext<BenchmarkDbContext>(builder => builder
19-
.UseSqlServer("Server=localhost;Database=TT_RE_Benchmarking;Integrated Security=true;")
19+
.UseSqlServer("Server=localhost;Database=TT_RE_Benchmarking;Integrated Security=true;TrustServerCertificate=true;")
2020
.UseLoggerFactory(NullLoggerFactory.Instance)
2121
.UseValueObjectValueConverter());
2222

samples/Thinktecture.Runtime.Extensions.Benchmarking/Benchmarks/ItemSearch.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88

99
namespace Thinktecture.Benchmarks;
1010

11-
[MemoryDiagnoser]
1211
public class ItemSearch
1312
{
1413
public class SmartEnum

samples/Thinktecture.Runtime.Extensions.Benchmarking/Benchmarks/LoadingSmartEnums.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
namespace Thinktecture.Benchmarks;
1010

1111
// ReSharper disable InconsistentNaming
12-
[MemoryDiagnoser]
1312
public class LoadingSmartEnums
1413
{
1514
private BenchmarkContext? _benchmarkContext;

samples/Thinktecture.Runtime.Extensions.Benchmarking/Benchmarks/LoadingValueObjects.cs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
namespace Thinktecture.Benchmarks;
99

1010
// ReSharper disable InconsistentNaming
11-
[MemoryDiagnoser]
1211
public class LoadingValueObjects
1312
{
1413
private BenchmarkContext? _benchmarkContext;
@@ -19,6 +18,7 @@ public class LoadingValueObjects
1918

2019
private readonly Entity_with_ValueObjects[] _Entity_with_ValueObjects = Enumerable.Range(1, _NUMBER_OF_ENTITIES).Select(i => new Entity_with_ValueObjects(i)).ToArray();
2120
private readonly Entity_without_ValueObjects[] _Entity_without_ValueObjects = Enumerable.Range(1, _NUMBER_OF_ENTITIES).Select(i => new Entity_without_ValueObjects(i)).ToArray();
21+
private readonly Entity_with_StructValueObjects[] _Entity_with_StructValueObjects = Enumerable.Range(1, _NUMBER_OF_ENTITIES).Select(i => new Entity_with_StructValueObjects(i)).ToArray();
2222

2323
[GlobalSetup]
2424
public void Initialize()
@@ -36,6 +36,9 @@ public void Initialize()
3636
_dbContext.RemoveRange(_dbContext.Entity_without_ValueObjects);
3737
_dbContext.Entity_without_ValueObjects.AddRange(_Entity_without_ValueObjects);
3838

39+
_dbContext.RemoveRange(_dbContext.Entity_with_StructValueObjects);
40+
_dbContext.Entity_with_StructValueObjects.AddRange(_Entity_with_StructValueObjects);
41+
3942
_dbContext.SaveChanges();
4043
}
4144

@@ -63,4 +66,10 @@ public async Task Entity_without_ValueObjects()
6366
{
6467
await _dbContext!.Entity_without_ValueObjects.ToListAsync();
6568
}
69+
70+
[Benchmark]
71+
public async Task Entity_with_StructValueObjects()
72+
{
73+
await _dbContext!.Entity_with_StructValueObjects.ToListAsync();
74+
}
6675
}

samples/Thinktecture.Runtime.Extensions.Benchmarking/Benchmarks/SingleItemCollectionBenchmarks.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33

44
namespace Thinktecture.Benchmarks;
55

6-
[MemoryDiagnoser]
76
public class SingleItemCollectionBenchmarks
87
{
98
private readonly IReadOnlyList<int> _singleItemCollection = SingleItem.Collection(42);

samples/Thinktecture.Runtime.Extensions.Benchmarking/Benchmarks/SingleItemSetBenchmarks.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33

44
namespace Thinktecture.Benchmarks;
55

6-
[MemoryDiagnoser]
76
public class SingleItemSetBenchmarks
87
{
98
private readonly IReadOnlySet<int> _singleItemSet = SingleItem.Set(42);

samples/Thinktecture.Runtime.Extensions.Benchmarking/Database/BenchmarkDbContext.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ public class BenchmarkDbContext : DbContext
1414

1515
public DbSet<Entity_with_ValueObjects> Entity_with_ValueObjects { get; set; } = null!;
1616
public DbSet<Entity_without_ValueObjects> Entity_without_ValueObjects { get; set; } = null!;
17+
public DbSet<Entity_with_StructValueObjects> Entity_with_StructValueObjects { get; set; } = null!;
1718

1819
public BenchmarkDbContext(DbContextOptions<BenchmarkDbContext> options)
1920
: base(options)
@@ -66,5 +67,12 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)
6667
builder.Property(e => e.Name).HasMaxLength(100);
6768
builder.Property(e => e.Description).HasMaxLength(200);
6869
});
70+
71+
modelBuilder.Entity<Entity_with_StructValueObjects>(builder =>
72+
{
73+
builder.Property(e => e.Id).ValueGeneratedNever();
74+
builder.Property(e => e.Name).HasMaxLength(100);
75+
builder.Property(e => e.Description).HasMaxLength(200);
76+
});
6977
}
7078
}

samples/Thinktecture.Runtime.Extensions.Benchmarking/Database/Description.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ static partial void ValidateFactoryArguments(ref ValidationResult? validationRes
1212
{
1313
if (String.IsNullOrWhiteSpace(value))
1414
{
15+
value = null!;
1516
validationResult = new ValidationResult("Description cannot be empty.");
1617
return;
1718
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
using System;
2+
using System.ComponentModel.DataAnnotations;
3+
4+
namespace Thinktecture.Database;
5+
6+
[ValueObject]
7+
public readonly partial struct DescriptionStruct
8+
{
9+
private readonly string _value;
10+
11+
static partial void ValidateFactoryArguments(ref ValidationResult? validationResult, ref string value)
12+
{
13+
if (String.IsNullOrWhiteSpace(value))
14+
{
15+
value = null!;
16+
validationResult = new ValidationResult("Description cannot be empty.");
17+
return;
18+
}
19+
20+
value = value.Trim();
21+
22+
if (value.Length < 2)
23+
validationResult = new ValidationResult("Description cannot be less than 2 characters.");
24+
}
25+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
namespace Thinktecture.Database;
2+
3+
// ReSharper disable InconsistentNaming
4+
public class Entity_with_StructValueObjects
5+
{
6+
public int Id { get; set; }
7+
public NameStruct Name { get; set; }
8+
public DescriptionStruct Description { get; set; }
9+
10+
// ReSharper disable once UnusedMember.Local
11+
private Entity_with_StructValueObjects(int id, NameStruct name, DescriptionStruct description)
12+
{
13+
Id = id;
14+
Name = name;
15+
Description = description;
16+
}
17+
18+
public Entity_with_StructValueObjects(int index)
19+
{
20+
Id = index;
21+
Name = NameStruct.Create($"Name {index}");
22+
Description = DescriptionStruct.Create($"Description {index}");
23+
}
24+
}

samples/Thinktecture.Runtime.Extensions.Benchmarking/Database/Name.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ static partial void ValidateFactoryArguments(ref ValidationResult? validationRes
1212
{
1313
if (String.IsNullOrWhiteSpace(value))
1414
{
15+
value = null!;
1516
validationResult = new ValidationResult("Name cannot be empty.");
1617
return;
1718
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
using System;
2+
using System.ComponentModel.DataAnnotations;
3+
4+
namespace Thinktecture.Database;
5+
6+
[ValueObject]
7+
public readonly partial struct NameStruct
8+
{
9+
private readonly string _value;
10+
11+
static partial void ValidateFactoryArguments(ref ValidationResult? validationResult, ref string value)
12+
{
13+
if (String.IsNullOrWhiteSpace(value))
14+
{
15+
value = null!;
16+
validationResult = new ValidationResult("Name cannot be empty.");
17+
return;
18+
}
19+
20+
value = value.Trim();
21+
22+
if (value.Length < 2)
23+
validationResult = new ValidationResult("Name cannot be less than 2 characters.");
24+
}
25+
}

0 commit comments

Comments
 (0)