ASP.net MVC Controller-Uso del constructor


Estoy trabajando en un ASP.net La aplicación MVC y yo tenemos una pregunta sobre el uso de constructores para mis controladores.

Estoy usando Entity Framework y linq to Entities para todas mis transacciones de datos. Necesito acceder a mi modelo de Entidad para casi todas mis acciones de controlador. Cuando empecé a escribir la aplicación estaba creando un objeto de entidad al principio de cada método de Acción, realizando cualquier trabajo que necesitara 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 de miembro privado para el objeto Entity y comencé a instanciarla en el constructor para cada controlador. Ahora cada método solo hace referencia a esa variable de miembro privado para hacer su trabajo.

Todavía me pregunto cuál es el camino 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

Author: BZink, 2010-12-19

2 answers

Usted está haciendo las preguntas correctas.

A. 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, está haciendo que el controlador sea grueso. Estos deben inyectarse en el controlador. Hay varias opciones para la inyección de dependencias (DI). En general, estos tipos de objetos se pueden inyectar en el constructor o en propiedad. Mi preferencia es la inyección de constructor.

B. La vida útil de estos objetos será determinada 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 base de datos), es posible que deba asegurarse de cerrar esas conexiones por su cuenta (en lugar de confiar en disponer). Muchas veces las preocupaciones de "vida útil" se separan en un contenedor de inversión de control (IOC). Hay muchos por ahí. Mi la 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. Hay un concepto llamado "unidad de trabajo" que usted puede querer investigar. Esencialmente, una base de datos puede manejar transacciones más grandes que una sola operación de guardar/actualizar. Aumentar el tamaño de la transacción puede conducir a un mejor db rendimiento.

Espero que eso te ayude a empezar.

Bob

 27
Author: rcravens,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-04-12 20:47:28

RCravens tiene algunas ideas excelentes. Me gustaría mostrarle cómo puede implementar sus sugerencias.

Sería bueno comenzar definiendo una interfaz para la clase data access 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 se puede obtener un comportamiento inconsistente cuando no se dispone de ellos, así que me parece que por lo general es mejor extraer los datos que desea en la memoria, y luego disponer del 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 el controlador puede aceptar uno de estos repositorios como argumento 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 del predeterminado, por lo que puede especificar que su marco de IoC como Ninject decida cómo se crean los Controladores. Puede configurar su marco de inyección para saber que cuando solicite un IPostRepository debe crear un objeto PostRepository.

Una gran ventaja de este enfoque es que hace que sus controladores sean comprobables por unidad. Por ejemplo, si desea asegurarse de que su modelo recibe un mensaje cuando no hay publicaciones, puede usar un marco de burla como Moq para configurar un escenario donde su repositorio no devuelve publicaciones:

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 fácil probar el comportamiento específico que espera de las acciones de su controlador, sin necesidad de configurar su base de datos ni nada especial como eso. Las pruebas unitarias como esta son fáciles de escribir, deterministas (su estado de aprobado / no aprobado se basa en el código, no en el contenido de la base de datos), y rápido (a menudo se puede ejecutar un millar de estos en un segundo).

 28
Author: StriplingWarrior,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-12-19 00:18:04