Pregunta

Vamos a decir que tengo una entidad de usuario y me gustaría ponerlo de propiedad CreationTime en el constructor de DateTime.Now. Pero ser una prueba de unidad adoptante no quiero acceder directamente, sino DateTime.Now uso un ITimeProvider:

public class User {
    public User(ITimeProvider timeProvider) {
        // ...
        this.CreationTime = timeProvider.Now;
    }

    // .....
}

public interface ITimeProvider { 
    public DateTime Now { get; }
}

public class TimeProvider : ITimeProvider {
    public DateTime Now { get { return DateTime.Now; } }
}

Estoy utilizando ninject 2 en mi aplicación ASP.NET MVC 2.0. Tengo un UserController y dos crean métodos (uno para GET y uno para POST). El uno para GET es sencillo pero la que tiene la POST no es tan recta y no tan hacia adelante: P porque necesito que meterse con el ligante modelo para indicarle que debe obtener una referencia de una implementación de ITimeProvider con el fin de ser capaces de construir una instancia de usuario.

public class UserController : Controller {

    [HttpGet]
    public ViewResult Create() {
         return View();
    }

    [HttpPost]
    public ActionResult Create(User user) {

         // ...

    }
}

También me gustaría ser capaz de mantener todas las características de la carpeta por defecto del modelo.

Hay alguna posibilidad de resolver este simple / elegante / etc? : D

¿Fue útil?

Solución

¿Qué tal en lugar de utilizar un ITimeProvider intente lo siguiente:

public class User 
{
    public Func<DateTime> DateTimeProvider = () => DateTime.Now;

    public User() 
    {
        this.CreationTime = DateTimeProvider();
    }
}

Y en la prueba de unidad:

var user = new User();
user.DateTimeProvider = () => new DateTime(2010, 5, 24);

Sé que esto no es muy elegante, pero en lugar de jugar con el modelo de ligante esto podría ser una solución. Si esto no se siente como una buena solución podría implementar un ligante modelo personalizado y anular la CreateModel método en el que inyectaría las dependencias en el constructor del modelo.

Otros consejos

Un par de observaciones:

No se inyecte dependencias sólo para consultarlos en el constructor

No hay razón para inyectar un ITimeProvider en un solo usuario para invocar Now inmediatamente. Sólo inyectar el tiempo de creación directa en su lugar:

public User(DateTime creationTime)
{
     this.CreationTime = creationTime;
}

Una muy buena regla general relacionada con DI es que constructores deben realizar ninguna lógica .

No utilice DI con ModelBinders

Una ASP.NET MVC ModelBinder es un lugar muy pobre para hacer DI, sobre todo porque no se puede utilizar Constructor de inyección. La única opción que queda es la estática Servicio Localizador anti-patrón .

A ModelBinder traduce la información HTTP GET y POST a un objeto fuertemente tipado, pero conceptualmente estos tipos no son objetos de dominio, pero similar a Transferencia de datos Objetos .

Una solución mucho mejor para ASP.NET MVC es renunciar a ModelBinders personalizados por completo y en su lugar abrazar de forma explícita que lo que recibe de la conexión HTTP es no es su objeto de dominio completo .

Se puede tener una búsqueda simple o mapeador para recuperar el objeto de dominio en el controlador:

public ActionResult Create(UserPostModel userPost)
{
    User u = this.userRepository.Lookup(userPost);
    // ...
}

donde this.userRepository es una dependencia inyectado.

Otra opción es crear una clase diferente para representar a los usuarios que no han sido todavía persistía que no tienen una propiedad de la fecha de creación en absoluto.

Aunque CreationDate es uno de los invariantes de User, puede ser anulable en su modelo de vista -. Y se puede establecer que, aguas abajo, en su controlador de dominio o de capa

Después de todo, es probable que no importa, pero si el atributo de fecha de creación realmente representar el momento en que construir una instancia de usuario , o sería más apropiado que representa el momento en que un usuario presenta sus datos?

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top