RCravens имеет некоторые отличные идеи. Я хотел бы показать, как вы можете реализовать его предложения.
Было бы хорошо начать с определения интерфейса для реализуемого класса доступа к данным:
public interface IPostRepository
{
IEnumerable<Post> GetMostRecentPosts(int blogId);
}
Затем реализуйте класс данных. Контексты Entity Framework дешевы в создании, и вы можете получить противоречивое поведение, если не утилизируете их, поэтому я считаю, что обычно лучше извлечь нужные данные в память, а затем утилизировать контекст.
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();
}
}
}
Теперь ваш контроллер может принять одно из этих хранилищ в качестве аргумента конструктора:
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 позволяет вам использовать собственную фабрику контроллеров вместо настроек по умолчанию, поэтому вы можете указать, что ваша структура IoC, такая как Ninject, решает, как создаются контроллеры. Вы можете настроить свою инфраструктуру внедрения так, чтобы при запросе IPostRepository он создавал объект PostRepository.
Одним из больших преимуществ этого подхода является то, что он делает ваши контроллеры тестируемыми на уровне модулей. Например, если вы хотите убедиться, что ваша модель получает сообщение, когда сообщений нет, вы можете использовать фиктивную среду, такую как Moq, для настройки сценария, в котором ваш репозиторий не возвращает сообщений:
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));
Это позволяет легко протестировать определенное поведение, которое вы ожидаете от действий вашего контроллера, без необходимости настраивать базу данных или что-то особенное в этом роде. Подобные модульные тесты просты в написании, являются детерминированными (их состояние прохождения / неудачи основано на коде, а не на содержимом базы данных) и быстрыми (часто можно выполнить тысячу таких в секунду).