So che stai pensando (o forse stai urlando), "non un'altra domanda che chiede dove la validazione appartiene a un'architettura a strati?!?" Beh, sì, ma si spera che questo sia un po 'un approccio diverso sull'argomento.
Sono fermamente convinto che la convalida abbia molte forme, sia basata sul contesto e vari a ogni livello dell'architettura. Questa è la base per il post - aiutando a identificare quale tipo di convalida deve essere eseguita in ogni livello. Inoltre, una domanda che emerge spesso è dove i controlli di autorizzazione appartengono.
Lo scenario di esempio viene da un'applicazione per un'azienda di catering. Periodicamente durante il giorno, un conducente può consegnare all'ufficio qualsiasi somma in eccesso accumulata durante il trasporto del camion da un sito all'altro. L'applicazione consente a un utente di registrare il "contante" raccogliendo l'ID del conducente e l'importo. Ecco un codice di scheletro per illustrare gli strati coinvolti:
public class CashDropApi // This is in the Service Facade Layer
{
[WebInvoke(Method = "POST")]
public void AddCashDrop(NewCashDropContract contract)
{
// 1
Service.AddCashDrop(contract.Amount, contract.DriverId);
}
}
public class CashDropService // This is the Application Service in the Domain Layer
{
public void AddCashDrop(Decimal amount, Int32 driverId)
{
// 2
CommandBus.Send(new AddCashDropCommand(amount, driverId));
}
}
internal class AddCashDropCommand // This is a command object in Domain Layer
{
public AddCashDropCommand(Decimal amount, Int32 driverId)
{
// 3
Amount = amount;
DriverId = driverId;
}
public Decimal Amount { get; private set; }
public Int32 DriverId { get; private set; }
}
internal class AddCashDropCommandHandler : IHandle<AddCashDropCommand>
{
internal ICashDropFactory Factory { get; set; } // Set by IoC container
internal ICashDropRepository CashDrops { get; set; } // Set by IoC container
internal IEmployeeRepository Employees { get; set; } // Set by IoC container
public void Handle(AddCashDropCommand command)
{
// 4
var driver = Employees.GetById(command.DriverId);
// 5
var authorizedBy = CurrentUser as Employee;
// 6
var cashDrop = Factory.CreateCashDrop(command.Amount, driver, authorizedBy);
// 7
CashDrops.Add(cashDrop);
}
}
public class CashDropFactory
{
public CashDrop CreateCashDrop(Decimal amount, Employee driver, Employee authorizedBy)
{
// 8
return new CashDrop(amount, driver, authorizedBy, DateTime.Now);
}
}
public class CashDrop // The domain object (entity)
{
public CashDrop(Decimal amount, Employee driver, Employee authorizedBy, DateTime at)
{
// 9
...
}
}
public class CashDropRepository // The implementation is in the Data Access Layer
{
public void Add(CashDrop item)
{
// 10
...
}
}
Ho indicato 10 località in cui ho visto i controlli di convalida inseriti nel codice. La mia domanda è quali verifiche si eseguiranno, se del caso, ad ogni dato le seguenti regole aziendali (insieme ai controlli standard per lunghezza, intervallo, formato, tipo, ecc.):
- L'importo della caduta di denaro deve essere maggiore di zero.
- La caduta di denaro deve avere un Driver valido.
- L'utente corrente deve essere autorizzato ad aggiungere cash drop (l'utente corrente non è il driver).
Per favore condividi i tuoi pensieri, come hai o vorrebbe avvicinarti a questo scenario e i motivi delle tue scelte.