Skip to content

Commit 89ee077

Browse files
committed
Added more examples.
1 parent c126635 commit 89ee077

File tree

27 files changed

+748
-34
lines changed

27 files changed

+748
-34
lines changed

Directory.Packages.props

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
<PackageVersion Include="Microsoft.EntityFrameworkCore.Sqlite" Version="9.0.3" />
1515
<PackageVersion Include="Microsoft.EntityFrameworkCore.SqlServer" Version="9.0.3" />
1616
<PackageVersion Include="Microsoft.EntityFrameworkCore.Relational" Version="9.0.3" />
17+
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="9.0.3" />
1718
<PackageVersion Include="Microsoft.Extensions.Logging.Console" Version="9.0.3" />
1819
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.13.0" />
1920
<PackageVersion Include="Microsoft.SourceLink.GitHub" Version="8.0.0" />

docs

Submodule docs updated from 54f216e to e92bf0f

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

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
using System;
2+
using System.Linq;
3+
using System.Threading.Tasks;
24
using Microsoft.AspNetCore.Mvc;
35
using Microsoft.Extensions.Logging;
46
using Thinktecture.SmartEnums;
@@ -150,4 +152,24 @@ private IActionResult RoundTripInternal<T>(T value)
150152

151153
return Json(value);
152154
}
155+
156+
[HttpGet("notification/channels")]
157+
public IActionResult GetAvailableChannels()
158+
{
159+
// Return all available notification channels
160+
var channels = NotificationChannelTypeDto.Items.Select(c => c.Name);
161+
return Ok(channels);
162+
}
163+
164+
[HttpPost("notification/channels/{type}")]
165+
public async Task<IActionResult> SendNotificationAsync(
166+
NotificationChannelTypeDto type,
167+
[FromBody] string message,
168+
[FromServices] IServiceProvider serviceProvider)
169+
{
170+
var notificationSender = type.GetNotificationSender(serviceProvider);
171+
await notificationSender.SendAsync(message);
172+
173+
return Ok();
174+
}
153175
}

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

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Linq;
23
using System.Net.Http;
34
using System.Net.Http.Json;
45
using System.Text;
@@ -13,6 +14,7 @@
1314
using Serilog;
1415
using Serilog.Events;
1516
using Thinktecture.AspNetCore.ModelBinding;
17+
using Thinktecture.Helpers;
1618
using Thinktecture.SmartEnums;
1719
using Thinktecture.Text.Json.Serialization;
1820
using Thinktecture.Validation;
@@ -79,6 +81,9 @@ private static async Task DoHttpRequestsAsync(ILogger logger, bool forMinimalWeb
7981

8082
await DoRequestAsync(logger, client, $"enddate/{DateOnly.FromDateTime(DateTime.Now):O}");
8183
await DoRequestAsync(logger, client, "enddate", DateOnly.FromDateTime(DateTime.Now));
84+
85+
await DoRequestAsync(logger, client, "notification/channels");
86+
await DoRequestAsync(logger, client, "notification/channels/email", "Test email");
8287
}
8388

8489
private static async Task DoRequestAsync(ILogger logger, HttpClient client, string url, object? body = null, string? jsonBody = null)
@@ -121,7 +126,9 @@ private static Task StartServerAsync(ILoggerFactory loggerFactory)
121126
})
122127
.ConfigureServices(collection =>
123128
{
124-
collection.AddSingleton(loggerFactory);
129+
collection.AddSingleton(loggerFactory)
130+
.AddSingleton<EmailNotificationSender>()
131+
.AddSingleton<SmsNotificationSender>();
125132
collection.AddControllers(options => options.ModelBinderProviders.Insert(0, new ValueObjectModelBinderProvider()))
126133
.AddJsonOptions(options => options.JsonSerializerOptions.Converters.Add(new ValueObjectJsonConverterFactory()));
127134
})
@@ -135,6 +142,8 @@ private static Task StartMinimalWebApiAsync(ILoggerFactory loggerFactory)
135142
var builder = WebApplication.CreateBuilder();
136143
builder.Services
137144
.AddSingleton(loggerFactory)
145+
.AddSingleton<EmailNotificationSender>()
146+
.AddSingleton<SmsNotificationSender>()
138147
.ConfigureHttpJsonOptions(options =>
139148
{
140149
options.SerializerOptions.Converters.Add(new ValueObjectJsonConverterFactory());
@@ -170,6 +179,21 @@ private static Task StartMinimalWebApiAsync(ILoggerFactory loggerFactory)
170179
routeGroup.MapGet("enddate/{date}", (OpenEndDate date) => date);
171180
routeGroup.MapPost("enddate", ([FromBody] OpenEndDate date) => date);
172181

182+
routeGroup.MapGet("notification/channels", () =>
183+
{
184+
var channels = NotificationChannelTypeDto.Items.Select(c => c.Name);
185+
return Results.Ok(channels);
186+
});
187+
routeGroup.MapPost("notification/channels/{type}",
188+
async (
189+
NotificationChannelTypeDto type,
190+
[FromBody] string message,
191+
[FromServices] IServiceProvider serviceProvider) =>
192+
{
193+
var notificationSender = type.GetNotificationSender(serviceProvider);
194+
await notificationSender.SendAsync(message);
195+
});
196+
173197
return app.StartAsync();
174198
}
175199

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
using Microsoft.EntityFrameworkCore;
2+
using Microsoft.EntityFrameworkCore.Metadata.Builders;
3+
4+
namespace Thinktecture.EntityConfigurations;
5+
6+
public class MessageEntityTypeConfiguration : IEntityTypeConfiguration<Message>
7+
{
8+
public void Configure(EntityTypeBuilder<Message> builder)
9+
{
10+
builder.ToTable("Messages");
11+
12+
builder.HasMany(m => m.States)
13+
.WithOne()
14+
.HasForeignKey("MessageId");
15+
16+
builder.Navigation(m => m.States).AutoInclude();
17+
}
18+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
using System;
2+
using Microsoft.EntityFrameworkCore;
3+
using Microsoft.EntityFrameworkCore.Metadata.Builders;
4+
5+
namespace Thinktecture.EntityConfigurations;
6+
7+
public class MessageStateEntityTypeConfiguration
8+
: IEntityTypeConfiguration<MessageState>,
9+
IEntityTypeConfiguration<MessageState.Parsed>,
10+
IEntityTypeConfiguration<MessageState.Processed>
11+
{
12+
public void Configure(EntityTypeBuilder<MessageState> builder)
13+
{
14+
builder.ToTable("MessageStates");
15+
16+
builder.HasKey(s => s.Order);
17+
18+
builder.Property(s => s.Order).ValueGeneratedOnAdd(); // auto-increment
19+
builder.Property<Guid>("MessageId"); // FK to the message table (as a shadow property)
20+
21+
builder
22+
.HasDiscriminator<string>("Type")
23+
.HasValue<MessageState.Initial>("Initial")
24+
.HasValue<MessageState.Parsed>("Parsed")
25+
.HasValue<MessageState.Processed>("Processed")
26+
.HasValue<MessageState.Error>("Error");
27+
}
28+
29+
public void Configure(EntityTypeBuilder<MessageState.Parsed> builder)
30+
{
31+
builder.Property(s => s.CreatedAt).HasColumnName("CreatedAt");
32+
}
33+
34+
public void Configure(EntityTypeBuilder<MessageState.Processed> builder)
35+
{
36+
builder.Property(s => s.CreatedAt).HasColumnName("CreatedAt");
37+
}
38+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
using System;
2+
using System.Collections.Generic;
3+
4+
namespace Thinktecture;
5+
6+
public class Message
7+
{
8+
public required Guid Id { get; init; }
9+
public required List<MessageState> States { get; set; }
10+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
using System;
2+
3+
namespace Thinktecture;
4+
5+
[Union]
6+
public abstract partial record MessageState
7+
{
8+
public int Order { get; }
9+
10+
public record Initial : MessageState;
11+
12+
public record Parsed(DateTime CreatedAt) : MessageState;
13+
14+
public record Processed(DateTime CreatedAt) : MessageState;
15+
16+
public record Error(string Message) : MessageState;
17+
}

samples/Thinktecture.Runtime.Extensions.EntityFrameworkCore.Samples/Product.cs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,27 +11,36 @@ public class Product
1111
public ProductCategory Category { get; private set; }
1212
public ProductType ProductType { get; private set; }
1313
public OpenEndDate EndDate { get; set; }
14+
public DayMonth ScheduledDeliveryDate { get; set; }
1415

1516
private Boundary? _boundary;
1617
public Boundary Boundary => _boundary ?? throw new InvalidOperationException("Boundary is not loaded.");
1718

18-
private Product(Guid id, ProductName name, ProductCategory category, ProductType productType, OpenEndDate endDate)
19+
private Product(
20+
Guid id,
21+
ProductName name,
22+
ProductCategory category,
23+
ProductType productType,
24+
OpenEndDate endDate,
25+
DayMonth scheduledDeliveryDate)
1926
{
2027
Id = id;
2128
Name = name;
2229
Category = category;
2330
ProductType = productType;
2431
EndDate = endDate;
32+
ScheduledDeliveryDate = scheduledDeliveryDate;
2533
}
2634

2735
public Product(
2836
Guid id,
2937
ProductName name,
3038
ProductCategory category,
3139
ProductType productType,
40+
DayMonth scheduledDeliveryDate,
3241
Boundary boundary,
3342
OpenEndDate endDate = default)
34-
: this(id, name, category, productType, endDate)
43+
: this(id, name, category, productType, endDate, scheduledDeliveryDate)
3544
{
3645
_boundary = boundary;
3746
}

samples/Thinktecture.Runtime.Extensions.EntityFrameworkCore.Samples/ProductsDbContext.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ namespace Thinktecture;
55
public class ProductsDbContext : DbContext
66
{
77
public DbSet<Product> Products => Set<Product>();
8+
public DbSet<Message> Messages => Set<Message>();
89

910
public ProductsDbContext(DbContextOptions<ProductsDbContext> options)
1011
: base(options)
@@ -34,5 +35,7 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)
3435
// if (property.ClrType == typeof(ProductType))
3536
// property.SetMaxLength(20);
3637
// });
38+
39+
modelBuilder.ApplyConfigurationsFromAssembly(typeof(ProductsDbContext).Assembly);
3740
}
3841
}

0 commit comments

Comments
 (0)