Sto pianificando di scrivere una libreria net-core per l'utilizzo con un'architettura n-tier. In questa architettura, voglio gestire i problemi trasversali (audit, gestione degli errori, registrazione, convalida, gestione delle transazioni, ecc.) Per i comandi (significa il comando di cqrs).
Attualmente sto usando mvc5 con la seguente architettura dell'applicazione (il livello cqrs è simile al livello servizio / applicazione):
- Sample.Core (Business)
- Sample.Data (Entity Framework)
- Sample.Cqrs (comandi, query, gestori di comandi, gestori di query)
- Sample.Web
Questa struttura mi consente di gestire i problemi trasversali del dispatcher generico come di seguito:
public CommandResult Dispatch<TParameter>(TParameter command) where TParameter : ICommand
{
ValidateCommand(command); // if command is not valid throw exception
var handler = _serviceLocator.Resolve<ICommandHandler<TParameter>>(); // resolve handler for command
var auditService = _serviceLocator.Resolve<IAuditService>();
using (var unitOfWork = new UnitOfWork())
{
try
{
var result = handler.Execute(command);
if (result != null)
{
return result;// business validation
}
auditService.CreateAudit(command);//create audit for command
unitOfWork.Commit();
return new CommandResult(true);// success
}
catch
{
unitOfWork.Rollback();
HandleException(e);
throw;
}
}
}
Questo codice funziona come previsto. Ma per ragioni di semplicità ho deciso di ridefinire l'architettura con le seguenti modifiche:
- Rimozione del livello Sample.Cqrs
- Trasportare il codice CommandHandlers nei metodi di azione
- Esecuzione di comandi e query per visualizzare modelli
Quindi, sto cercando qualsiasi modello per gestire i problemi trasversali nei metodi di azione invece di dispatcher. Due opzioni possibili che mi vengono in mente (ho eliminato il pattern di decoratore e l'intercettazione del metodo):
Uso di ActionFilter Uso del delegato (la mia domanda è per questa opzione) Per la seconda opzione il codice di esempio è come di seguito:
public CommandResult Execute(object command, Func<CommandContainer, CommandResult> handle)
{
var container = new CommandContainer();// CommandContainer is for carrying audit data
ValidateCommand(command); // if command is not valid throw exception
using(var unitOfWork = new UnitOfWork())
{
try
{
var result = handle(container);
if (result != null)
{
return result;// business validation
}
_auditService.Save(command);
unitOfWork.Commit();
return new CommandResult(true);// success
}
catch(Exception ex)
{
unitOfWork.Rollback();
_logger.Log(ex);
throw;
}
}
}
Quindi nel metodo action:
var result = _handler.Execute(command, (container) =>
{
container.Comment = "dfsdf";
// Application logic
//return result;
});
Domanda : se la mia decisione (rimozione del livello cqrs) non è negativa, la seconda opzione è l'approccio accettabile? Qualche altro suggerimento?