Skip to content

Commit 045712c

Browse files
Lots of tweaking to get send mail service working with ionos. Fixed bug where no reports coudl be created from public site.
1 parent ddaad75 commit 045712c

File tree

5 files changed

+67
-17
lines changed

5 files changed

+67
-17
lines changed

src/DotNetElements.Core/Core/EntityBase.cs

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -124,8 +124,21 @@ public void Delete(Guid deleterId, DateTimeOffset deletionTime)
124124
}
125125

126126
[EditorBrowsable(EditorBrowsableState.Never)]
127-
public void Delete(DateTimeOffset deletionTime) => throw new NotImplementedException();
127+
public void Delete(DateTimeOffset deletionTime)
128+
{
129+
if (IsDeleted)
130+
throw new InvalidOperationException("Can not delete an already deleted entity");
131+
132+
IsDeleted = true;
133+
DeletionTime = deletionTime;
134+
}
128135

129136
[EditorBrowsable(EditorBrowsableState.Never)]
130-
public void Delete() => throw new NotImplementedException();
137+
public void Delete()
138+
{
139+
if (IsDeleted)
140+
throw new InvalidOperationException("Can not delete an already deleted entity");
141+
142+
IsDeleted = true;
143+
}
131144
}

src/DotNetElements.Core/Outbox/OutboxMessageProcessor.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,18 @@
22

33
public interface IOutboxMessageProcessor
44
{
5-
Task<Result> ProcessAsync(object message);
5+
Task<Result> ProcessAsync(object message, CancellationToken cancellation);
66
}
77

88
public abstract class OutboxMessageProcessor<T> : IOutboxMessageProcessor
99
{
10-
public Task<Result> ProcessAsync(object message)
10+
public Task<Result> ProcessAsync(object message, CancellationToken cancellation)
1111
{
1212
if (message is not T tMessage)
1313
throw new ArgumentException("Invalid message type");
1414

15-
return ProcessAsync(tMessage);
15+
return ProcessAsync(tMessage, cancellation);
1616
}
1717

18-
protected abstract Task<Result> ProcessAsync(T message);
18+
protected abstract Task<Result> ProcessAsync(T message, CancellationToken cancellation);
1919
}

src/DotNetElements.Core/Outbox/OutboxService.cs

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using Microsoft.Extensions.Logging;
33
using Microsoft.Extensions.Options;
44
using System.Text.Json;
5+
using System.Text.Json.Serialization;
56

67
namespace DotNetElements.Core;
78

@@ -19,6 +20,13 @@ public sealed class OutboxService<TDbContext> : IOutboxService
1920
private readonly OutboxOptions outboxOptions;
2021
private readonly ILogger<OutboxService<TDbContext>> logger;
2122

23+
private readonly JsonSerializerOptions jsonOptions = new()
24+
{
25+
UnmappedMemberHandling = JsonUnmappedMemberHandling.Disallow,
26+
PropertyNameCaseInsensitive = true
27+
};
28+
29+
2230
public OutboxService(
2331
TDbContext dbContext,
2432
TimeProvider timeProvider,
@@ -37,12 +45,18 @@ public OutboxService(
3745

3846
public async Task RunAsync(CancellationToken cancellation)
3947
{
40-
IReadOnlyList<OutboxMessage> messages = await GetPendingMessages();
48+
IReadOnlyList<OutboxMessage> messages = await GetPendingMessages(cancellation);
4149

4250
logger.LogInformation("Started processing {MessageCount} messages", messages.Count);
4351

4452
foreach (var messagesByType in messages.GroupBy(m => m.Type))
4553
{
54+
if (cancellation.IsCancellationRequested)
55+
{
56+
logger.LogWarning("Processing was cancelled");
57+
break;
58+
}
59+
4660
logger.LogInformation("Started processing {MessageCount} messages of type {MessageType}", messagesByType.Count(), messagesByType.Key);
4761

4862
Type? messageType = outboxOptions.MessagesAssembly!.GetType(messagesByType.Key);
@@ -66,17 +80,31 @@ public async Task RunAsync(CancellationToken cancellation)
6680

6781
foreach (OutboxMessage message in messagesByType)
6882
{
83+
if (cancellation.IsCancellationRequested)
84+
{
85+
logger.LogWarning("Processing was cancelled");
86+
break;
87+
}
88+
6989
try
7090
{
71-
object? deserializedMessage = JsonSerializer.Deserialize(message.Content, messageType);
91+
object? deserializedMessage = JsonSerializer.Deserialize(message.Content, messageType, jsonOptions);
7292

7393
if (deserializedMessage is null)
7494
{
7595
logger.LogError("Failed to process message {MessageId} of type {MessageType}. Failed to read content", message.Id, message.Type);
7696
continue;
7797
}
7898

79-
await messageProcessor.ProcessAsync(deserializedMessage);
99+
Result processMessageResult = await messageProcessor.ProcessAsync(deserializedMessage, cancellation);
100+
101+
if (processMessageResult.IsFail)
102+
{
103+
logger.LogError("Failed to process message {MessageId} of type {MessageType}. Error: {Error}", message.Id, message.Type, processMessageResult.ErrorMessage);
104+
105+
await HandleFailedMessage(message, processMessageResult.ErrorMessage);
106+
continue;
107+
}
80108

81109
bool updateSuccess = await UpdateMessageStatus(message, processedOnUtc: timeProvider.GetUtcNow());
82110

@@ -102,14 +130,14 @@ public async Task RunAsync(CancellationToken cancellation)
102130
logger.LogInformation("Finished processing messages");
103131
}
104132

105-
private async Task<IReadOnlyList<OutboxMessage>> GetPendingMessages()
133+
private async Task<IReadOnlyList<OutboxMessage>> GetPendingMessages(CancellationToken cancellation)
106134
{
107135
try
108136
{
109137
return await dbContext.OutboxMessages
110138
.Where(m => m.ProcessedOnUtc == null)
111139
.OrderBy(m => m.OccurredOnUtc)
112-
.ToListAsync();
140+
.ToListAsync(cancellation);
113141
}
114142
catch (Exception ex)
115143
{
@@ -131,7 +159,7 @@ private async Task HandleFailedMessage(OutboxMessage message, string error)
131159
{
132160
logger.LogError("Failed to process message {MessageId} of type {MessageType}. Error: Max retry count reached", message.Id, message.Type);
133161

134-
bool updateSuccess = await UpdateMessageStatus(message, processedOnUtc: timeProvider.GetUtcNow(), error: error, retryCount: message.RetryCount + 1);
162+
bool updateSuccess = await UpdateMessageStatus(message, processedOnUtc: timeProvider.GetUtcNow(), error: error, retryCount: message.RetryCount);
135163

136164
// todo check what to do if update fails here
137165
}
@@ -148,8 +176,6 @@ private async Task<bool> UpdateMessageStatus(OutboxMessage message, DateTimeOffs
148176
if (retryCount is not null)
149177
message.RetryCount = retryCount.Value;
150178

151-
//dbContext.OutboxMessages.Update(message); // todo remove, should not be needed as EF already tracks the entity
152-
153179
int numRowsUpdated = await dbContext.SaveChangesAsync();
154180

155181
bool success = numRowsUpdated == 1;

src/DotNetElements.Core/Outbox/ServiceCollectionExtensions.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,4 +37,12 @@ public static IServiceCollection AddOutbox<TDbContext>(this IServiceCollection s
3737

3838
return services;
3939
}
40+
41+
public static IServiceCollection AddOutboxMessageProcessor<TService, TMessage>(this IServiceCollection services)
42+
where TService : OutboxMessageProcessor<TMessage>
43+
{
44+
services.AddScoped<OutboxMessageProcessor<TMessage>, TService>();
45+
46+
return services;
47+
}
4048
}

src/DotNetElements.Web.Blazor/Extensions/EditContextExtensions.cs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,14 @@ public static void LogDebugInfo(this EditContext? editContext)
1010
if (editContext is null)
1111
return;
1212

13+
IEnumerable<string> messages = editContext.GetValidationMessages();
14+
15+
if (!messages.Any())
16+
return;
17+
1318
Console.WriteLine($"DEBUG EditContext validation messages. Context: {editContext.Model.GetType()}");
1419

15-
foreach (string message in editContext.GetValidationMessages())
16-
{
20+
foreach (string message in messages)
1721
Console.WriteLine(message);
18-
}
1922
}
2023
}

0 commit comments

Comments
 (0)