RCravens有一些很好的見解。我想展示如何實施他的建議。
這將是很好定義的接口,爲數據訪問類來實現啓動:
public interface IPostRepository
{
IEnumerable<Post> GetMostRecentPosts(int blogId);
}
然後實現數據類。實體框架上下文構建起來很便宜,並且在不處理它們時可能會出現不一致的行爲,所以我發現將內存中的數據提取出來然後處理上下文通常會更好。
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對象。
這種方法的一大優勢是它使您的控制器可以進行單元測試。例如,如果你想確保你的模型獲取消息時,有沒有文章,你可以像使用最小起訂量嘲弄的框架,建立這樣一個場景,你的資料庫沒有返回崗位:
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));
這使得很容易測試您對控制器操作期望的特定行爲,而無需設置數據庫或其他任何特殊的東西。像這樣的單元測試很容易編寫,具有確定性(它們的通過/失敗狀態基於代碼,而不是數據庫內容),並且速度很快(一秒鐘可以運行一千次)。
只有一個控制器需要該對象嗎? – 2010-12-18 22:36:06
可能你應該使用單例模式與私有靜態實例和延遲加載get實例的屬性。 – 2010-12-18 22:39:38