MailQueue

This commit is contained in:
2026-01-20 16:47:24 +01:00
parent a5fe908034
commit d40e2e8daa
13 changed files with 181 additions and 71 deletions

View File

@ -16,5 +16,6 @@ public class MailQueue : EntitaBase
public enum MailFrom
{
Invitation = 0,
Confirmation = 1
Confirmation,
Registrazione
}

View File

@ -1,20 +1,18 @@
using System.Net.Http.Headers;
using System.Net.Http.Json;
using System.Text;
using System.Text.Json;
using StandManager.Domain.DTO;
using StandManager.MailProcessor.Mail;
using StandManager.Service.Interfaces;
using StandManager.Service.Resolver;
public class MailProcessor
{
private readonly IManagerService _managerService;
private readonly EmailConfig _config;
private readonly IMailProcessorResolver _resolver;
public MailProcessor(IManagerService managerService, EmailConfig config)
public MailProcessor(IManagerService managerService, EmailConfig config, IMailProcessorResolver resolver)
{
_managerService = managerService;
_config = config;
_resolver = resolver;
}
public async Task Process()
@ -23,54 +21,11 @@ public class MailProcessor
x.Eliminato == false && x.Sent == false && string.IsNullOrEmpty(x.Error), solaLettura:false);
using var httpClient = new HttpClient();
foreach (var mailQueue in list)
foreach (var mailQueueByFrom in list.GroupBy(x => x.From))
{
var email = new Email()
{
From = _config.From,
Body = string.IsNullOrEmpty(mailQueue.Args) ? mailQueue.Body : string.Format(mailQueue.Body, mailQueue.Args?.Split(_config.MailSplitChar) ?? [""]),
Cc = null,
Subject = mailQueue.Subject,
To = new(){"g.vitari@oaservice.it"} // mailQueue.ToList.Split(";").ToList()
};
var messageJson = JsonSerializer.Serialize(email);
// multipart
using var form = new MultipartFormDataContent();
form.Add(
new StringContent(messageJson, Encoding.UTF8, "application/json"),
"messageJson"
);
//Attachments
/*var filePath = @"C:\temp\test.pdf";
var fileBytes = await File.ReadAllBytesAsync(filePath);
var processor = _resolver.Resolve(mailQueueByFrom.Key);
var fileContent = new ByteArrayContent(fileBytes);
fileContent.Headers.ContentType = MediaTypeHeaderValue.Parse("application/pdf");
form.Add(
fileContent,
"attachments",
Path.GetFileName(filePath)
);*/
try
{
var response = await httpClient.PostAsync(
_config.ServerAddress,
form
);
response.EnsureSuccessStatusCode();
mailQueue.Sent = true;
await _managerService.MailQueueService.Salva(mailQueue);
}
catch (Exception e)
{
mailQueue.Sent = false;
mailQueue.Error = e.Message;
await _managerService.MailQueueService.Salva(mailQueue);
}
await processor.ProcessAsync(mailQueueByFrom.ToList(), _config, httpClient);
}
var a = list;

View File

@ -5,10 +5,10 @@ using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using StandManager.Domain.DTO;
using StandManager.Infrastructure.DAL.Context;
using StandManager.MailProcessor.Mail;
using StandManager.Service;
using StandManager.Service.Interfaces;
using StandManager.Service.Repository;
using StandManager.Service.Resolver;
var host = Host.CreateDefaultBuilder(args)
.ConfigureServices((context, services) =>
@ -36,6 +36,9 @@ var host = Host.CreateDefaultBuilder(args)
services.AddScoped<IManagerService, ManagerService>();
services.AddScoped<MailProcessor>();
//MailProcessor
services.AddScoped<IMailProcessor, RegistrazioneMailProcessor>();
services.AddScoped<IMailProcessorResolver, MailProcessorResolver>();
})
.Build();

View File

@ -0,0 +1,10 @@
using StandManager.Domain.DTO;
using StandManager.Domain.Entita;
namespace StandManager.Service.Interfaces;
public interface IMailProcessor
{
MailFrom MailFrom { get; }
Task ProcessAsync(List<MailQueue> mailQueueList, EmailConfig config, HttpClient httpClient);
}

View File

@ -1,4 +1,4 @@
namespace StandManager.MailProcessor.Mail;
namespace StandManager.Service.Mail;
public class Email
{

View File

@ -0,0 +1,72 @@
using System.Text;
using System.Text.Json;
using StandManager.Domain.DTO;
using StandManager.Domain.Entita;
using StandManager.Service.Interfaces;
using StandManager.Service.Mail;
namespace StandManager.Service;
public class RegistrazioneMailProcessor : IMailProcessor
{
private readonly IManagerService _managerService;
public RegistrazioneMailProcessor(IManagerService managerService)
{
_managerService = managerService;
}
public MailFrom MailFrom => MailFrom.Registrazione;
public async Task ProcessAsync(List<MailQueue> mailQueueList, EmailConfig _config, HttpClient httpClient)
{
foreach (var mailQueue in mailQueueList)
{
var email = new Email()
{
From = _config.From,
Body = string.IsNullOrEmpty(mailQueue.Args) ? mailQueue.Body : string.Format(mailQueue.Body, mailQueue.Args?.Split(_config.MailSplitChar) ?? [""]),
Cc = null,
Subject = mailQueue.Subject,
To = new(){"g.vitari@oaservice.it"} // mailQueue.ToList.Split(";").ToList()
};
var messageJson = JsonSerializer.Serialize(email);
// multipart
using var form = new MultipartFormDataContent();
form.Add(
new StringContent(messageJson, Encoding.UTF8, "application/json"),
"messageJson"
);
//Attachments
/*var filePath = @"C:\temp\test.pdf";
var fileBytes = await File.ReadAllBytesAsync(filePath);
var fileContent = new ByteArrayContent(fileBytes);
fileContent.Headers.ContentType = MediaTypeHeaderValue.Parse("application/pdf");
form.Add(
fileContent,
"attachments",
Path.GetFileName(filePath)
);*/
try
{
var response = await httpClient.PostAsync(
_config.ServerAddress,
form
);
response.EnsureSuccessStatusCode();
mailQueue.Sent = true;
await _managerService.MailQueueService.Salva(mailQueue);
}
catch (Exception e)
{
mailQueue.Sent = false;
mailQueue.Error = e.Message;
await _managerService.MailQueueService.Salva(mailQueue);
}
}
}
}

View File

@ -0,0 +1,9 @@
using StandManager.Domain.Entita;
using StandManager.Service.Interfaces;
namespace StandManager.Service.Resolver;
public interface IMailProcessorResolver
{
IMailProcessor Resolve(MailFrom mailFrom);
}

View File

@ -0,0 +1,22 @@
using StandManager.Domain.Entita;
using StandManager.Service.Interfaces;
namespace StandManager.Service.Resolver;
public class MailProcessorResolver : IMailProcessorResolver
{
private readonly Dictionary<MailFrom, IMailProcessor> _processors;
public MailProcessorResolver(IEnumerable<IMailProcessor> processors)
{
_processors = processors.ToDictionary(p => p.MailFrom);
}
public IMailProcessor Resolve(MailFrom mailFrom)
{
if (!_processors.TryGetValue(mailFrom, out var processor))
throw new NotSupportedException($"MailFrom {mailFrom} non supportato");
return processor;
}
}

View File

@ -15,7 +15,7 @@
<AuthorizeView>
<Authorized>
<AppHeader />
<AppHeader ShowNavigation="false" />
</Authorized>
<NotAuthorized>

View File

@ -88,6 +88,14 @@
Mail = iscrizione.Mail
};
await _managerService.IscrizioneEventoPerMailService.Salva(model);
var queue = new MailQueue()
{
ToList = iscrizione.Mail,
From = MailFrom.Registrazione
};
await _managerService.MailQueueService.Salva(queue);
_navManager.NavigateTo("/Grazie");
}
}

View File

@ -9,7 +9,8 @@
@rendermode InteractiveServer
<PageTitle>Iscrizione Evento</PageTitle>
<AppHeader />
<AppHeader ShowNavigation="false"/>
<div class="container my-5 py-3">
<ClienteToggle ValueChanged="onClienteToggleChanged" />
@if (showCodiceCliente)

View File

@ -10,6 +10,7 @@ using StandManager.Service.Interfaces;
using StandManager.Service.Repository;
using StandManager.Utils;
using System.Reflection;
using StandManager.Service.Resolver;
var builder = WebApplication.CreateBuilder(args);
@ -50,6 +51,10 @@ builder.Services.AddScoped<IManagerService, ManagerService>();
builder.Services.AddScoped<BodyClassService>();
builder.Services.AddScoped<LayoutState>();
//MailProcessor
builder.Services.AddScoped<IMailProcessor, RegistrazioneMailProcessor>();
builder.Services.AddScoped<IMailProcessorResolver, MailProcessorResolver>();
builder.Services.AddRadzenComponents();
builder.Services.AddHttpContextAccessor();

View File

@ -1,27 +1,51 @@
BEGIN TRANSACTION;
ALTER TABLE [Destinazione] ADD [ComuneIstatId] uniqueidentifier NULL;
CREATE TABLE [MailQueue] (
[Id] uniqueidentifier NOT NULL,
[Subject] nvarchar(max) NOT NULL,
[Body] nvarchar(max) NOT NULL,
[ToList] nvarchar(max) NOT NULL,
[Args] nvarchar(max) NULL,
[From] int NOT NULL,
[Sent] bit NOT NULL,
[Error] nvarchar(max) NULL,
[DataCreazione] datetime2 NOT NULL,
[DataModifica] datetime2 NULL,
[Eliminato] bit NOT NULL,
[IdUtenteCreazione] uniqueidentifier NULL,
[IdUtenteModifica] uniqueidentifier NULL,
CONSTRAINT [PK_MailQueue] PRIMARY KEY ([Id]),
CONSTRAINT [FK_MailQueue_Utente_IdUtenteCreazione] FOREIGN KEY ([IdUtenteCreazione]) REFERENCES [Utente] ([Id]),
CONSTRAINT [FK_MailQueue_Utente_IdUtenteModifica] FOREIGN KEY ([IdUtenteModifica]) REFERENCES [Utente] ([Id])
);
ALTER TABLE [Destinazione] ADD [ProvinciaIstatId] uniqueidentifier NULL;
CREATE INDEX [IX_MailQueue_IdUtenteCreazione] ON [MailQueue] ([IdUtenteCreazione]);
CREATE INDEX [IX_Destinazione_ComuneIstatId] ON [Destinazione] ([ComuneIstatId]);
CREATE INDEX [IX_Destinazione_ProvinciaIstatId] ON [Destinazione] ([ProvinciaIstatId]);
ALTER TABLE [Destinazione] ADD CONSTRAINT [FK_Destinazione_ComuneIstat_ComuneIstatId] FOREIGN KEY ([ComuneIstatId]) REFERENCES [ComuneIstat] ([Id]);
ALTER TABLE [Destinazione] ADD CONSTRAINT [FK_Destinazione_Province_ProvinciaIstatId] FOREIGN KEY ([ProvinciaIstatId]) REFERENCES [Province] ([Id]);
CREATE INDEX [IX_MailQueue_IdUtenteModifica] ON [MailQueue] ([IdUtenteModifica]);
INSERT INTO [__EFMigrationsHistory] ([MigrationId], [ProductVersion])
VALUES (N'20260107093044_CittaEProv', N'9.0.11');
VALUES (N'20260109133732_MailQueue', N'9.0.11');
ALTER TABLE [ComuneIstat] ADD [ProvinciaIstatId] uniqueidentifier NULL;
CREATE TABLE [IscrizioneEventoPerMail] (
[Id] uniqueidentifier NOT NULL,
[Mail] nvarchar(max) NOT NULL,
[Processata] bit NOT NULL,
[Inviata] bit NOT NULL,
[DataCreazione] datetime2 NOT NULL,
[DataModifica] datetime2 NULL,
[Eliminato] bit NOT NULL,
[IdUtenteCreazione] uniqueidentifier NULL,
[IdUtenteModifica] uniqueidentifier NULL,
CONSTRAINT [PK_IscrizioneEventoPerMail] PRIMARY KEY ([Id]),
CONSTRAINT [FK_IscrizioneEventoPerMail_Utente_IdUtenteCreazione] FOREIGN KEY ([IdUtenteCreazione]) REFERENCES [Utente] ([Id]),
CONSTRAINT [FK_IscrizioneEventoPerMail_Utente_IdUtenteModifica] FOREIGN KEY ([IdUtenteModifica]) REFERENCES [Utente] ([Id])
);
CREATE INDEX [IX_ComuneIstat_ProvinciaIstatId] ON [ComuneIstat] ([ProvinciaIstatId]);
CREATE INDEX [IX_IscrizioneEventoPerMail_IdUtenteCreazione] ON [IscrizioneEventoPerMail] ([IdUtenteCreazione]);
ALTER TABLE [ComuneIstat] ADD CONSTRAINT [FK_ComuneIstat_Province_ProvinciaIstatId] FOREIGN KEY ([ProvinciaIstatId]) REFERENCES [Province] ([Id]);
CREATE INDEX [IX_IscrizioneEventoPerMail_IdUtenteModifica] ON [IscrizioneEventoPerMail] ([IdUtenteModifica]);
INSERT INTO [__EFMigrationsHistory] ([MigrationId], [ProductVersion])
VALUES (N'20260107093529_ProvSuComune', N'9.0.11');
VALUES (N'20260120130758_IscrizioneEventoPerMail', N'9.0.11');
COMMIT;
GO