3

Im new in C#,i have read about constructor,and i have learned the reason we use them is we can assign whatever we want at the time of construct,but something which is difficult for me to understand is,i have a IRepository student like:

    public  interface IStudentRepository
    {

        object getAll();
    }

i implemented it in StudentRepository:

     public class StudentRepository:IStudentRepository
    {
       public testDBEntities DB = new testDBEntities();
        public object getAll()
        {
            var reslt = (from s in DB.Students
                     select new StudentViewModel
                     {
                         Name = s.Name,
                         Id=s.Id
                     });

            return reslt;
        }
    }

in my homeController i can do like the following:

    IStudentRepository _repository=new StudentRepository();   
    public JsonResult Index()
    {
       var m= _repository.getAll();
       return Json(m,JsonRequestBehavior.AllowGet);
    }

why should i have a constructor then?like:

       IStudentRepository _repository=new StudentRepository();
    public HomeController(StudentRepository _repository)
    {
        this._repository = _repository;
    }
    public JsonResult Index()
    {
       var m= _repository.getAll();
       return Json(m,JsonRequestBehavior.AllowGet);
    }

im sorry if my question is basic but i could not find a right answer,thanks in advance

1
  • By injecting the repository into the constructor you are doing something called Dependency Injection. This removes the tight coupling between the controller class and the specific implementation of IStudentRepository. Constructor injection is one method (probably the most common) of dependency injection.
    – SBFrancies
    Commented Jul 18, 2018 at 12:10

2 Answers 2

6

Single Responsibility Principle

The first advantage is that your HomeController doesn't have to worry about creating the StudentRepository object. Someone else already instanciated it, generated it from a database, a file or user input or whatsoever. And this is great, because your controller can then focus on its real job, not on how to instanciate another object. This is getting closer on the Single Responsibility Principle.

Dependency Injection

Then, to take advantage of the second one, your constructor should receive the interface instead of the class. That is called Dependency Injection.

If later on, for a reason or another, you decide to change your StudentRepository class in any way, as long as you still implement the interface, you don't have to make a change into your controller.

So your final code could look like :

class HomeController
{
    private IStudentRepository _repository;
    public HomeController(IStudentRepository _repository)
    {
        //We don't know who instanciated the repo, but we don't care
        this._repository = _repository;
    }

    public JsonResult Index()
    {
        //We only know about the repo that it implements IStudentRepository
        //So we know we can call this method without a risk.
        var m= _repository.getAll();
        return Json(m,JsonRequestBehavior.AllowGet);
    }
}

When it changes

To illustrate a change, let's say you first want to test your repo, but don't have a proper database connection. So you decide to use a file, there your class would look like :

public class TestStudentRepository : IStudentRepository
{
    private string MyDatabaseFilePath;

    public object getAll()
    {
        //Load everything from my text file
    }
}

Okay this will work. Let's now say that you have a connection to your database, but that connection requires some steps before being able to use the getAll() method. With your solution, you would have to perform the init steps in your HomeController.

Now with this pattern, you can do :

public class StudentRepository : IStudentRepository
{
    private string _connectionString;

    public DatabaseStudentRepository(string ConnectionString)
    {
        _connectionString = ConnectionString;
    }

    public object getAll()
    {
        //Load everything from my text file
    }
}

Then, it is the role of the object that is using the controller to make sure it instanciated your object correctly. No changes in your controller.

The factory pattern

Final step is to create a Factory for your StudentRepository. It is the role of the Factory to instanciate a proper repo:

public static class StudentRepositoryFactory
{
    public static IStudentRepository InstanciateRepo(bool FromDatabase)
    {
        if (FromDatabase)
        {
            return new DatabaseStudentFactory("ConnectionString To my server");
        }
        else
        {
            return new TestStudentRepository();
        }
    }
}

And now, whatever the way you need to init your repo, it is the role of the Factory to do so; while it is the role of the Controller to use one method of your repository, getAll().

4
  • what change for example?even if i add more interface in the Studentrepository i still can have access to them by instantiating,am i right?
    – moris62
    Commented Jul 18, 2018 at 12:19
  • thanks for your nice example and if i have multiple repositories should i have multiple constructor in homecontroller as well?
    – moris62
    Commented Jul 18, 2018 at 12:44
  • @mortezasol No, and that is the point of such constructs. You constructor in HomeController juste receive an IStudentRepository, whatever class implements it. Commented Jul 18, 2018 at 13:29
  • sorry Martin for asking stupid questions,if i want to use other repositories in homecontroller,whats the best practice?add them also in this constructor?
    – moris62
    Commented Jul 18, 2018 at 13:31
1

I think your constructor isn't correct. It must like

IStudentRepository _repository
public HomeController(IStudentRepository _repository)
{
     this._repository = _repository;
}

In fact, it's better to pass the IStudentRepository in the constructor for respecting the pattern dependency injection.

Imaging that you want to test your controller by the unit test. So you want to create fake data. If you create new StudentRepository inside the controller, how to test it?.

But if you pass by the constructor, like :

public class FakeStudentRepository : IStudentRepository 
{
     //return fake data
}

By some config, the 3rd library ``dependency injection` will pass your fake repo to the controller and you can test it

Not the answer you're looking for? Browse other questions tagged or ask your own question.