asp.net mvc - unity - Controlador MVC ASP.net-Uso del constructor
unity container web api 2 (2)
Estoy trabajando en una aplicación MVC de ASP.net y tengo una pregunta sobre el uso de constructores para mis controladores.
Estoy usando Entity Framework y linq para entidades para todas mis transacciones de datos. Necesito acceder a mi modelo de entidad para casi todas mis acciones de controlador. Cuando comencé a escribir la aplicación, estaba creando un objeto de entidad al comienzo de cada método de Acción, realizando cualquier trabajo que necesitaba y luego devolviendo mi resultado.
Me di cuenta de que estaba creando el mismo objeto una y otra vez para cada método de acción, así que creé una variable miembro privada para el objeto Entity y comencé a crear una instancia en el constructor para cada controlador. Ahora, cada método solo hace referencia a esa variable miembro privada para hacer su trabajo.
Todavía me estoy preguntando de qué manera es correcto. Me pregunto A.) ¿Qué método es el más apropiado? B.) en el método constructor, ¿cuánto tiempo viven esos objetos? C.) hay problemas de rendimiento / integridad con el método constructor?
Gracias
RCravens tiene algunas ideas excelentes. Me gustaría mostrarle cómo puede implementar sus sugerencias.
Sería bueno comenzar por definir una interfaz para la clase de acceso a datos a implementar:
public interface IPostRepository
{
IEnumerable<Post> GetMostRecentPosts(int blogId);
}
Luego implementa una clase de datos. Los contextos de Entity Framework son baratos de construir, y puede obtener un comportamiento incoherente cuando no se deshace de ellos, por lo que me parece que generalmente es mejor extraer de la memoria los datos que desea y luego eliminar el contexto.
public class PostRepository : IPostRepository
{
public IEnumerable<Post> GetMostRecentPosts(int blogId)
{
// A using statement makes sure the context is disposed quickly.
using(var context = new BlogContext())
{
return context.Posts
.Where(p => p.UserId == userId)
.OrderByDescending(p => p.TimeStamp)
.Take(10)
// ToList ensures the values are in memory before disposing the context
.ToList();
}
}
}
Ahora su controlador puede aceptar uno de estos repositorios como un argumento de constructor:
public class BlogController : Controller
{
private IPostRepository _postRepository;
public BlogController(IPostRepository postRepository)
{
_postRepository = postRepository;
}
public ActionResult Index(int blogId)
{
var posts = _postRepository.GetMostRecentPosts(blogId);
var model = new PostsModel { Posts = posts };
if(!posts.Any()) {model.Message = "This blog doesn''t have any posts yet";}
return View("Posts", model);
}
}
MVC le permite usar su propia fábrica de controladores en lugar de la predeterminada, por lo que puede especificar que su estructura de IoC como Ninject decida cómo se crean los controladores. Puede configurar su marco de inyección para saber que cuando solicita un IPostRepository debe crear un objeto PostRepository.
Una gran ventaja de este enfoque es que hace que sus controladores sean comprobables por la unidad. Por ejemplo, si quiere asegurarse de que su modelo recibe un mensaje cuando no hay publicaciones, puede usar un marco de simulación como Moq para configurar un escenario donde su repositorio no devuelve ninguna publicación:
var repositoryMock = new Mock<IPostRepository>();
repositoryMock.Setup(r => r.GetMostRecentPosts(1))
.Returns(Enumerable.Empty<Post>());
var controller = new BlogController(repositoryMock.Object);
var result = (ViewResult)controller.Index(1);
Assert.IsFalse(string.IsNullOrEmpty(result.Model.Message));
Esto hace que sea más fácil probar el comportamiento específico que espera de las acciones de su controlador, sin la necesidad de configurar su base de datos o algo así. Las pruebas unitarias como esta son fáciles de escribir, deterministas (su estado de aprobación / falla se basa en el código, no en los contenidos de la base de datos), y rápido (a menudo puede ejecutar miles de estos en un segundo).
Usted está haciendo las preguntas correctas.
R. Definitivamente no es apropiado crear estas dependencias dentro de cada método de acción. Una de las principales características de MVC es la capacidad de separar las preocupaciones. Al cargar su controlador con estas dependencias, hará que el controlador sea grueso. Estos deben ser inyectados en el controlador. Hay varias opciones para la inyección de dependencia (DI). En general, estos tipos de objetos pueden ser inyectados en el constructor o en una propiedad. Mi preferencia es la inyección de constructor.
B. El tiempo de vida de estos objetos será determinado por el recolector de basura. GC no es determinista. Por lo tanto, si tiene objetos que tienen conexiones a servicios con recursos limitados (conexiones de bases de datos), entonces es posible que deba asegurarse de cerrar esas conexiones usted mismo (en lugar de confiar en deshacerse de ellas). Muchas veces las preocupaciones de ''vida'' se separan en un contenedor de inversión de control (IOC). Hay muchos por ahí. Mi preferencia es Ninject.
C. Los costos de instanciación son probablemente mínimos. El costo de las transacciones de la base de datos es donde probablemente desee centrar su atención. Existe un concepto llamado "unidad de trabajo" en el que es posible que desee investigar. Esencialmente, una base de datos puede manejar transacciones de más de una operación de guardado / actualización. Aumentar el tamaño de la transacción puede conducir a un mejor rendimiento de db.
Espero que te ayude a empezar.
Chelín