Как использовать контейнер DI / IoC с подшивкой модели в ASP.NET MVC 2+? - PullRequest
8 голосов
/ 24 мая 2010

Допустим, у меня есть сущность User, и я бы хотел установить для ее свойства CreationTime в конструкторе значение DateTime.Now.Но, будучи приверженцем модульного теста, я не хочу получать прямой доступ к DateTime.Now, а использую 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; } }
}

Я использую NInject 2 в своем приложении ASP.NET MVC 2.0.У меня есть UserController и два метода Create (один для GET и один для POST).Одна для GET прямолинейна, но для POST не такая прямая и не такая прямая: P, потому что мне нужно возиться с механизмом связывания модели, чтобы сказать ему, чтобы получить ссылку на реализацию ITimeProvider, чтобы иметь возможность конструироватьпользовательский экземпляр.

public class UserController : Controller {

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

    [HttpPost]
    public ActionResult Create(User user) {

         // ...

    }
}

Я также хотел бы иметь возможность сохранить все функции связующего устройства модели по умолчанию.

Есть ли шанс решить этот простой / элегантный / и т.д.?: D

Ответы [ 3 ]

20 голосов
/ 25 мая 2010

Пара наблюдений:

Не вставляйте зависимости просто для их запроса в конструкторе

Нет причин вводить ITimeProvider в пользователя, чтобы просто вызвать Now немедленно. Просто вместо этого введите время создания:

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

Действительно хорошее эмпирическое правило, связанное с DI, заключается в том, что конструкторы не должны выполнять логику .

Не использовать DI с ModelBinders

ASP.NET MVC ModelBinder - действительно плохое место для DI, особенно потому, что вы не можете использовать Constructor Injection. Единственным оставшимся вариантом является статический анти-шаблон Service Locator .

ModelBinder преобразует данные HTTP GET и POST в строго типизированный объект, но концептуально эти типы не являются объектами домена, но похожи на объекты передачи данных .

Гораздо лучшим решением для ASP.NET MVC является полное отказ от пользовательских ModelBinder и вместо этого явно охватывает , что вы получаете по HTTP-соединению , а не объект полного домена .

Вы можете иметь простой поиск или маппер для извлечения вашего доменного объекта в вашем контроллере:

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

где this.userRepository - внедренная зависимость.

5 голосов
/ 24 мая 2010

Как насчет того, чтобы вместо ITimeProvider попробовать это:

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

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

И в вашем модульном тесте:

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

Я знаю, что это не очень элегантно, но вместовозиться с моделью связующего это может быть решением.Если это не похоже на хорошее решение, вы можете внедрить пользовательский механизм связывания модели и переопределить метод CreateModel , где вы бы внедрили зависимости в конструктор модели.

1 голос
/ 25 мая 2010

Другим вариантом является создание другого класса для представления пользователей, которые еще не были сохранены и у которых вообще нет свойства даты создания.

Даже если CreationDate является одним из UserИнварианты, это может быть обнуляемым в вашей модели представления - и вы можете установить его дальше вниз по течению, на уровне контроллера или домена.

В конце концов, это, вероятно, не имеет значения, но должен ли атрибут даты созданиядействительно представляет момент, когда вы создаете пользовательский экземпляр , или было бы более уместно представлять момент, когда пользователь отправляет свои данные?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...