ASP.net MVC Controller - Constructor usage

前端 未结 2 1411
面向向阳花
面向向阳花 2021-01-30 01:45

I\'m working on an ASP.net MVC application and I have a question about using constructors for my controllers.

I\'m using Entity Framework and linq to Entities for all o

2条回答
  •  闹比i
    闹比i (楼主)
    2021-01-30 02:35

    RCravens has some excellent insights. I'd like to show how you can implement his suggestions.

    It would be good to start by defining an interface for the data access class to implement:

    public interface IPostRepository 
    {
        IEnumerable GetMostRecentPosts(int blogId);
    }
    

    Then implement a data class. Entity Framework contexts are cheap to build, and you can get inconsistent behavior when you don't dispose of them, so I find it's usually better to pull the data you want into memory, and then dispose the context.

    public class PostRepository : IPostRepository
    {
        public IEnumerable 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(); 
            }
        }
    }
    

    Now your controller can accept one of these repositories as a constructor argument:

    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 allows you to use your own Controller Factory in lieu of the default, so you can specify that your IoC framework like Ninject decides how Controllers are created. You can set up your injection framework to know that when you ask for an IPostRepository it should create a PostRepository object.

    One big advantage of this approach is that it makes your controllers unit-testable. For example, if you want to make sure that your model gets a Message when there are no posts, you can use a mocking framework like Moq to set up a scenario where your repository returns no posts:

    var repositoryMock = new Mock();
    repositoryMock.Setup(r => r.GetMostRecentPosts(1))
        .Returns(Enumerable.Empty());
    var controller = new BlogController(repositoryMock.Object);
    var result = (ViewResult)controller.Index(1);
    Assert.IsFalse(string.IsNullOrEmpty(result.Model.Message));
    

    This makes it easy to test the specific behavior you're expecting from your controller actions, without needing to set up your database or anything special like that. Unit tests like this are easy to write, deterministic (their pass/fail status is based on the code, not the database contents), and fast (you can often run a thousand of these in a second).

提交回复
热议问题