No es una mala práctica que un controlador llame a un repositorio directamente. Un "servicio" es solo otra herramienta, así que úselo donde tenga sentido.
NikolaiDante comentó:
... Elija el patrón correcto para la aplicación correcta. Lo que diría es que debe hacer que su aplicación sea coherente.
No creo que la consistencia sea el aspecto más importante. Una clase de "servicio" está destinada a encapsular alguna lógica de nivel superior para que el controlador no necesite implementarla. Si no se requiere una "lógica de nivel superior" para una operación determinada, simplemente vaya directamente al repositorio.
Para promover una buena Separación de preocupaciones y capacidad de prueba, el repositorio debe ser una dependencia que inyecte en el servicio a través de un constructor:
IFooRepository repository = new FooRepository();
FooService service = new FooService(repository);
service.DoSomething(...);
Si la búsqueda de registros en la base de datos necesita algún tipo de consulta parametrizada, una clase de servicio podría ser un buen lugar para tomar en su modelo de vista y construir una consulta que luego se ejecuta por el repositorio.
Del mismo modo, si tiene un modelo de vista complejo para un formulario, una clase de servicio puede encapsular la lógica de crear, actualizar y eliminar registros llamando a métodos en sus Modelos / Entidades de Dominio, y luego persistiéndolos usando un repositorio.
Yendo en la dirección opuesta, si su controlador necesita obtener un registro por su Id, delegar en un objeto de servicio para esto es como golpear una chincheta con un mazo: es mucho más de lo que necesita.
He descubierto que el controlador está en la mejor posición para manejar la transacción, o un objeto de Unidad de trabajo . El controlador o el objeto Unidad de trabajo luego delegaría en objetos de servicio para operaciones complejas, o iría directamente al repositorio para operaciones simples (como encontrar un registro por 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);
}
}
}
}
Creo que una combinación de servicios y trabajar con repositorios directamente es perfectamente aceptable. Puede encapsular aún más la transacción en un objeto de Unidad de trabajo si siente la necesidad.
El desglose de responsabilidades es el siguiente:
- El controlador controla el flujo de la aplicación.
- Devuelve "404 Not Found" si el carrito de compras no está en la base de datos
- Vuelve a representar el formulario con mensajes de validación si la validación falla
- Guarda el carrito de compras si todo sale
- El controlador delega a una clase de servicio para ejecutar la lógica de negocios en sus Modelos de dominio (o Entidades). ¡Los objetos de servicio no deberían implementar la lógica empresarial! Ellos ejecutan la lógica de negocio.
- Los controladores pueden delegar directamente en repositorios para operaciones simples
- Los objetos de servicio toman datos en el modelo de vista y delegan en Modelos de dominio para ejecutar la lógica empresarial (por ejemplo, el objeto de servicio llama a métodos en los Modelos de dominio antes de llamar a métodos en el repositorio)
- Los objetos de servicio delegan en repositorios para la persistencia de datos
- Los controladores deberían:
- Administrar la vida útil de una transacción, o
- Crear un objeto de Unidad de trabajo para administrar la vida útil de una transacción