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:
... Scegli il modello giusto per l'applicazione giusta. Quello che direi è che dovresti rendere coerente la tua candidatura.
Non credo che la coerenza sia l'aspetto più importante. Una classe di "servizio" è intesa per incapsulare una logica di livello superiore in modo che il controller non debba implementarla. Se non è richiesta una "logica di livello superiore" per una determinata operazione, basta andare direttamente al repository.
Per promuovere una buona separazione delle preoccupazioni e della testabilità, il repository dovrebbe essere una dipendenza che si inietta 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 accettare il modello di visualizzazione e creare una query che viene quindi eseguita dal repository.
Allo stesso modo, se si dispone di un modello di visualizzazione complesso per un modulo, una classe di servizio può incapsulare la logica di creazione, aggiornamento ed eliminazione dei record chiamando metodi sui modelli / entità di dominio, quindi persistendoli utilizzando un repository.
Andando nella direzione opposta, se il controller ha bisogno di ottenere un record dal suo ID, delegare a un oggetto di servizio per questo è come colpire una puntina da disegno con una mazza - è molto più del necessario.
Ho scoperto che il controller è nella posizione migliore per gestire la transazione o un oggetto Unit Of Work . Il controller o l'oggetto Unit Of Work delegherà quindi agli oggetti di servizio per operazioni complesse o andrà direttamente al repository per operazioni semplici (come trovare un record per 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 i repository sia perfettamente accettabile. Potresti incapsulare ulteriormente la transazione in un oggetto Unit Of Work se ne sentissi la necessità.
La ripartizione delle responsabilità è la seguente:
- Il controller controlla il flusso dell'applicazione
- Restituisce "404 non trovato" se il carrello non è presente nel database
- Riesegue il rendering del modulo con messaggi di convalida se la convalida non riesce
- Salva il carrello se tutto viene estratto
- Il controller delega a una classe di servizio per eseguire la logica aziendale sui modelli di dominio (o entità). Gli oggetti di servizio non devono implementare la logica aziendale! Essi eseguono la logica di business.
- I controllori possono delegare direttamente ai repository per operazioni semplici
- Gli oggetti di servizio accettano i dati nel modello di vista e delegano a Modelli di dominio per eseguire la logica aziendale (ad es. L'oggetto di servizio chiama i metodi sui Modelli di dominio prima di chiamare i metodi nel repository)
- Gli oggetti del servizio delegati ai repository per la persistenza dei dati
- I controller dovrebbero:
- Gestire la durata di una transazione, o
- Creare un oggetto Unit Of Work per gestire la durata di una transazione