Non è una cattiva pratica per un controller chiamare direttamente un repository. Un "servizio" è solo un altro strumento, quindi usalo dove ha senso.
NikolaiDante ha commentato:
... Pick the right pattern for the right application. What I would say is that you should make your application consistent.
Non penso che la coerenza sia l'aspetto più importante. Una classe "service" ha lo scopo di incapsulare alcune logiche di livello superiore in modo che il controller non debba implementarlo. Se non è richiesta una "logica di livello superiore" per una determinata operazione, vai direttamente al repository.
Per promuovere il bene Separate of Concerns e testability, il repository dovrebbe essere una dipendenza che si inserisce nel servizio tramite un costruttore:
IFooRepository repository = new FooRepository();
FooService service = new FooService(repository);
service.DoSomething(...);
Se la ricerca di record nel database richiede una sorta di query con parametri, una classe di servizio potrebbe essere un buon posto per prendere il tuo modello di vista e creare una query che viene poi eseguita dal repository.
Allo stesso modo, se si dispone di un modello di vista complesso per un modulo, una classe di servizio può incapsulare la logica di creazione, aggiornamento ed eliminazione di record chiamando metodi sui propri Modelli / Entità di Dominio, quindi persistendoli utilizzando un repository.
Andando nella direzione opposta, se il tuo controller ha bisogno di ottenere un record con il suo ID, delegare a un oggetto di servizio è come colpire una puntina con un martello: è molto più del necessario.
Ho trovato che il controller è nella posizione migliore per gestire la transazione, o un Oggetto Unità di lavoro . Il controller o l'oggetto Unit Of Work delegherebbe quindi agli oggetti di servizio per operazioni complesse, o andrà direttamente al repository per operazioni semplici (come trovare un record con Id).
public class ShoppingCartsController : Controller
{
[HttpPost]
public ActionResult Edit(int id, ShoppingCartForm model)
{
// Controller initiates a database session and transaction
using (IStoreContext store = new StoreContext())
{
// Controller goes directly to a repository to find a record by Id
ShoppingCart cart = store.ShoppingCarts.Find(id);
// Controller creates the service, and passes the repository and/or
// the current transaction
ShoppingCartService service = new ShoppingCartService(store.ShoppingCarts);
if (cart == null)
return HttpNotFound();
if (ModelState.IsValid)
{
// Controller delegates to a service object to manipulate the
// Domain Model (ShoppingCart)
service.UpdateShoppingCart(model, cart);
// Controller decides to commit changes
store.SaveChanges();
return RedirectToAction("Index", "Home");
}
else
{
return View(model);
}
}
}
}
Penso che un mix di servizi e lavorare direttamente con gli archivi sia perfettamente accettabile. Potresti incapsulare ulteriormente la transazione in un oggetto Unit Of Work se ne hai sentito il bisogno.
La ripartizione delle responsabilità è la seguente:
- Il controller controlla il flusso dell'applicazione
- Restituisce "404 non trovato" se il carrello acquisti non si trova nel database
- Ri-rende il modulo con i messaggi di convalida se la convalida fallisce
- Salva il carrello degli acquisti se tutto viene eliminato
- Il controllore delega a una classe di servizio per eseguire la logica di business sui tuoi modelli di dominio (o entità). Gli oggetti servizio dovrebbero non implementare la logica aziendale! Loro eseguono la logica aziendale.
- I controllori possono delegare direttamente ai repository per operazioni semplici
- Gli oggetti servizio acquisiscono i dati nel modello di visualizzazione e delegano ai modelli di dominio per eseguire la logica aziendale (ad esempio, l'oggetto servizio chiama i metodi sui modelli di dominio prima di chiamare i metodi nel repository)
- Gli oggetti servizio delegano agli archivi per la persistenza dei dati
- I controller dovrebbero:
- Gestisci la durata di una transazione, o
- Crea un oggetto Unit Of Work per gestire la durata di una transazione