Tengo código del controlador como este por todo el sitio de ASP.NET MVC 3:¿Se puede refactorizar este código MVC usando un patrón de diseño?
[HttpPost]
public ActionResult Save(PostViewModel viewModel)
{
// VM -> Domain Mapping. Definetely belongs here. Happy with this.
var post = Mapper.Map<PostViewModel, Post>(viewModel);
// Saving. Again, fine. Controllers job to update model.
_postRepository.Save(post);
// No. Noooo..caching, thread spawning, something about a user?? Why....
Task.Factory.StartNew(() => {
_cache.RefreshSomeCache(post);
_cache2.RefreshSomeOtherCache(post2);
_userRepository.GiveUserPoints(post.User);
_someotherRepo.AuditThisHappened();
});
// This should be the 3rd line in this method.
return RedirectToAction("Index");
}
Básicamente, me refiero al código en el bloque de roscado. Todas las cosas deben suceder, pero el usuario no tiene que esperarlas (es un buen argumento para un hilo de fondo, ¿no?).
Para que quede claro, utilizo el caché (caché de datos ASP.NET regular) en todo el sitio, y la mayoría tiene una política de caché "sin caducidad", así que lo desalojo manualmente cuando sea necesario (como el anterior) .
Y la parte del usuario básicamente le está dando al usuario representante para hacer algo (como Stack).
Recapitulemos: tenemos almacenamiento en memoria caché, manejo de la reputación del usuario, auditoría, todo en uno. Realmente no pertenece en un solo lugar. De ahí el problema con el código actual y el problema con tratar de encontrar la manera de alejarlo.
La razón por la que quiero refactorizar esto es por varias razones:
- difícil de probar la unidad. El multihilo y las pruebas unitarias realmente no funcionan bien.
- Legibilidad. Es difícil de leer Sucio.
- SRP. Controlador haciendo/sabiendo demasiado.
Lo resuelto 1) envolviendo el código de generación de hebras en una interfaz, y solo burlándote/simulándolo.
Pero me gustaría hacer algún tipo de patrón, donde mi código podría tener este aspecto:
[HttpPost]
public ActionResult Save(PostViewModel viewModel)
{
// Map.
var post = Mapper.Map<PostViewModel, Post>(viewModel);
// Save.
_postRepository.Save(post);
// Tell someone about this.
_eventManager.RaiseEvent(post);
// Redirect.
return RedirectToAction("Index");
}
Básicamente, poniendo la responsabilidad en "algo más" que reaccionan, no el controlador.
He oído/leído acerca de Tareas, Comandos, Eventos, etc., pero todavía tengo que ver uno implementado en el espacio ASP.NET MVC.
Los primeros pensamientos me dirían crear algún tipo de "gestor de eventos". Pero luego pensé, ¿a dónde va esto? En el dominio? Entonces, ¿cómo maneja las interacciones con el caché, que es una preocupación de infraestructura? Y luego enhebrar, que también es una preocupación de infraestructura. ¿Y qué ocurre si quiero hacerlo sincrónicamente, en lugar de asincrónico? ¿Qué hace esa decisión?
No quiero tener que apilar toda esta lógica en otro lado. Lo ideal es que se vuelva a factorizar en componentes manejables y significativos, sin responsabilidad cambiada, si eso tiene sentido.
¿Algún consejo?
+1 esta es una buena pregunta a un problema común. Espero ver soluciones n + 1. dónde ir después ... hmmm :) –