1

I'm using ASP.NET MVC 2. I got the sample application from Darin (the guy that seems to answer all the MVC questions). I'm not sure if any one else has this sample project that he created? He has a base controller in his application, and the code looks like this:

public abstract class BaseController<TRepository> : Controller, IModelMapperController
{
   protected BaseController(TRepository repository, IMapper mapper)
   {
      Repository = repository;
      ModelMapper = mapper;
   }

   public TRepository Repository { get; private set; }
   public IMapper ModelMapper { get; private set; }
}

The questions that I have regarding this code is what does BaseController mean?

If I need to specify more than one repository how would the BaseController constructor code look like?

Is it best practices to have only one repository per controller? The reason why I ask is because in my ApplicationController class I make use of a Create() action method to populate my view from custom view model. In this view model I need to populate 2 different drop down lists. Bank names and account types. Each has their own repository. BankRepository has a method called GetBanks() and AccountTypeRepository has a method called GetAccountTpes(). So in my Application controller I have to call these 2 methods to populate the drop downs. So the Application controllers implements Base controller. How would base controller look like if I have to pass it more than one repository?

Please can someone shed some light regarding this.

@Darin: Thanks for the sample application, I am learning a lot from it already.

Brendan Vogt
  • 25,678
  • 37
  • 146
  • 234
  • 2
    This isn't an answer to your question... but why are you even designing the controller like this? If there's a possibility of multiple repositories, BaseController would be essentially useless. Even worse, you're not really saving yourself anything by designing a controller that simply sets properties. Personally, I think you're setting yourself up for a mess... – zowens Dec 03 '10 at 14:50
  • It's not me, I am working from a sample project that Darin posted. And then I had questions around this. How would you have done it? Have a base constructor that accepts a specific type of I repository? – Brendan Vogt Dec 03 '10 at 15:12
  • 2
    One repository per controller is good for simple scenarios. It all depends on what you need to do. A aggregated view where two aggregate roots are used together for example will need more than one repository if your a 1:1 root per repository type of guy. -- As an aside be careful adhering to patterns you do not understand fully. My experience is it creates worse code than not knowing the patterns at all. ;) – John Farrell Dec 03 '10 at 17:11
  • 1
    I'd agree with zowens and jfar. I'd further say that in most cases, my controllers don't call repositories directly anyway (again, except in the simplest scenarios), b/c if they do then you find yourself slipping more business logic into the controller, where the controller's main concern should be with routing requests to views and redirects. When I first got into MVC I went down the path that Darin seems to be advocating, and as jfar says found it quickly became untenable, there're just too few benefits from strongly typing a controller to a repository or a single entity. – Paul Dec 04 '10 at 19:39

3 Answers3

4

so each of your controllers could point to a different repo. something like this:

public class UsersController : BaseController<UserRepository>
{
    public UsersController() 
        : base(new UserRepository(), new UserModelMapper())
    {
        // do stuff
    }

    public ActionResult Index()
    {
        // now you can use syntax like, since "Repository" is type "UserRepository"
        return View(Respository.GetAllUsers());
    }

    public ActionResult Details(int id)
    {
        return View(Respository.GetUser(id));
    }
}

UPDATED for Addresses

public class AddressesController : BaseController<AddressRepository>
{
    public AddressesController() 
        : base(new AddressRepository(), new AddressModelMapper())
    {
    }

    public ActionResult Addresses(int id)
    {
        return View(Respository.GetAllByUserId(id));
    }
}

UPDATED for Factory

public static class RepositoryFactory
{
    internal static Hashtable Repositories = new Hashtable();

    internal static T GetRepository<T>() where T : class, new()
    {
        if (Repositories[typeof(T)] as T == null)
        {
            Repositories[typeof(T)] = new T();
        }
        return Repositories[typeof(T)] as T;
    }

    public static AccountTypeRepository AccountTypeRepository
    {
        get { return GetRepository<AccountTypeRepository>(); } 
    }

    public static BankRepository BankRepository
    {
        get { return GetRepository<BankRepository>(); } 
    }
    /* repeat as needed or change accessibility and call GetRepository<> directly */

Now rather than even using a BaseController you could just write this:

public class ApplicationModel
{
    public Application Application { get; set; }
    public IList<Bank> Banks { get; set; }
    public IList<AccountType> AccountTypes { get; set; }
}

public class ApplicationController : Controller
{
    public ActionResult Index()
    {
        ApplicationListModel model = new ApplicationListModel()
        {
            Applications = RespositoryFactory.ApplicationRepository.GetAll();
        }
        return View(model);
    }

    public ActionResult Details(int id)
    {
        ApplicationModel model = new ApplicationModel()
        {
            Application = RespositoryFactory.ApplicationRepository.Get(id),
            Banks = RespositoryFactory.BankRepository.GetAll(),
            AccountTypes = RespositoryFactory.AccountTypeRepository.GetAll()
        }
        return View(model);

    }
}
hunter
  • 62,308
  • 19
  • 113
  • 113
  • @hunter. I have my code like this, but this is not what I asked. I asked what happens if your controller requires more than one repository, how would base look like? I asked a couple of other questions as well. Not a decent answer. – Brendan Vogt Dec 03 '10 at 14:34
  • brendan, i generally tend to think about a single controller per entity and as such, i don't think my 'thoughts' on this would fit with what you're trying to achieve. would your 'view' not be composed of partialviews that grabbed each section from the appropriate controller. also, a bit harsh docking the guy a point just for giving you a clear demonstration of how it can be achieved based on the example (and a severe lack of humour :)). – jim tollan Dec 03 '10 at 14:40
  • A single controller yes. But I have multiple repositories which I need to use per controller. How would BaseController need to be implemented top accommodate this? DO I need to pass it more than one repository to the constructors? – Brendan Vogt Dec 03 '10 at 14:45
  • 1
    @brendan, sorry I misinterpreted your question. Like jim said, you would be better off creating an AddressController which would handle actions related to Addresses and the AddressRepository. Unless you created some hybrid repository class that handled the actions of UserRepository and AddressRepository you might want to create a separate Controller for each Repository-bound Controller – hunter Dec 03 '10 at 14:46
  • 1
    If you want to be able to hit multiple Repositories from one controller I would suggest using a different pattern than the one Darin suggested – hunter Dec 03 '10 at 14:47
  • Ok fine. 1 controller, but I need to make use of more than 1 repository in this controller, what would the BaseController construcotrs look like? – Brendan Vogt Dec 03 '10 at 14:48
  • @hunter: I'm a novice at this. What pattern would you suggest? – Brendan Vogt Dec 03 '10 at 14:48
  • I don't think what you're trying to do is a bad way to go about things. Breaking Address-related actions into its own Controller will keep your UsersController from becoming cluttered with User, Address, and whatever other actions you might want there, too. You'll probably like this result better since you're Controllers, Views, and Models will be tidy and Repository specific, not to mention easier to manage and for other developers to use later. – hunter Dec 03 '10 at 14:55
  • 1
    Brendan - it's difficult to explain simply, but if you used a service layer, then each model entity could have a class that was exposed via its IRepository interface. you could then instantiate an instance of the address service class inside the user one if required. it's a well known pattern. in fact, you would actually go a level above this and have a tasks layer on top of the service layer that performed duties that were outside the generic repository ensemble. – jim tollan Dec 03 '10 at 14:57
  • Every one here is missing the question! Am I not clear in my question. Let me try again. I have many controllers. They all inherit from a base controller. I would need to implement more than one repository in my controller. Lets say in my view model I need to populate a a status drop down (coming from a method in StatusRepository) and maybe another drop down with other values from another repository. – Brendan Vogt Dec 03 '10 at 15:16
  • I will update my answer to show you how to implement a RepositoryFactory so that you can get data from any Repository in any Controller... – hunter Dec 03 '10 at 16:02
  • you could make the factory a singleton but I just wanted to show you one way you could do what you want to do – hunter Dec 03 '10 at 16:18
  • hunter, you might wanna change the public class ApplicationModel to public class ApplicationListModel to match your code :). was going to edit it for you but thought it would be too cheeky!! – jim tollan Dec 03 '10 at 16:25
  • @jim, nice typo-catch... writing code in a textarea is less than optimal. This is the longest answer I've written for 1 vote! – hunter Dec 03 '10 at 16:32
  • @Brendan> re: missing the question. I don't think anyone is missing the question, but I think the respondents agree that your question is based on the flawed assumption that you need to use Darin's BaseController at all. There are many ways to skin the cat, and Darin's BaseController is probably applicable for only the simplest ones. I often use a base class for my controllers also, but I don't pass a repository to it in any fashion (not all controllers in my apps even need to hit data stores). – Paul Dec 04 '10 at 19:46
1

I'm not sure if I'll answer all of your questions, but here goes...

I use a BaseController as well, but I don't do what your example does. Here's how my code looks like (my application also uses DI for the constructors...):

public class BaseController : Controller {
    private readonly IProvider AddressProvider = null;
    private readonly IProvider EmailProvider = null;
    private readonly IProvider PhoneProvider = null;

    [Inject] // Using Ninject for DI
    public BaseController(
        AddressProvider AddressProvider,
        EmailProvider EmailProvider,
        PhoneProvider PhoneProvider) {
        this.AddressProvider = AddressProvider;
        this.EmailProvider = EmailProvider;
        this.PhoneProvider = PhoneProvider;
    }
}

And here's my AdministrationController which inherits from BaseController:

public class AdministrationController : BaseController {
    private readonly CustomerProvider CustomerProvider = null;
    private readonly EmployeeProvider EmployeeProvider = null;

    [Inject]
    public AdministrationController(
        CustomerProvider CustomerProvider,
        EmployeeProvider EmployeeProvider,
        AddressProvider AddressProvider,
        EmailProvider EmailProvider,
        PhoneProvider PhoneProvider) : base(AddressProvider, EmailProvider, PhoneProvider) {
        this.CustomerProvider = CustomerProvider;
        this.EmployeeProvider = EmployeeProvider;
    }
}

My AdministrationController only cares about CustomerProvider and EmployeeProvider and it passes AddressProvider, EmailProvider and PhoneProvider to the BaseController.

AddressProvider, EmailProvider and PhoneProvider are in the BaseController because I consider Address, Email and Phone to be low-level objects. My reason for that is because they can be linked to Customer, Employee or anything else as far as the database is concerned. So, instead of having multiple methods for Customer or Employee to interact with each of their objects, I just have one. For example:

public class BaseController : Controller {
    //  GET: /Addresses/{AddressId}/Delete
    public void DeleteAddress(
        int AddressId) {
        this.AddressProvider.DeleteAndSave(AddressId);

        Response.Redirect(Request.UrlReferrer.AbsoluteUri);
    }

    //  GET: /Emails/{EmailId}/Delete
    public void DeleteEmail(
        int EmaildId) {
        this.EmailProvider.DeleteAndSave(EmailId);

        Response.Redirect(Request.UrlReferrer.AbsoluteUri);
    }

    //  GET: /Phones/{PhoneId}/Delete
    public void DeletePhone(
        int PhoneId) {
        this.PhoneProvider.DeleteAndSave(PhoneId);

        Response.Redirect(Request.UrlReferrer.AbsoluteUri);
    }
}

And with that I take care of my low-level objects. Keep in mind, in my application I have additional methods to further manipulate those objects as needed.

Now, in my AdministrationController I'm working with CustomerProvider and EmployeeProvider. These are more specialized because I consider Customer and Employee to be high-level objects. That being said, their providers do a bit more work than Delete. For example they also provide the view models used by the views (durp...):

public class AdministrationController : BaseController {
    public ActionResult Customer(
        int CustomerId) {
        return this.View(this.CustomerProvider.GetView(CustomerId));
    }

    public AciontResult Customers() {
        return this.Veiw(this.CustomerProvider.GetAllView(CustomerId));
    }

    public ActionResult CustomerAddresses(
        int CustomerId,
        Address Address) {
        if (ModelState.IsValid) {
            this.CustomerProvider.AddAddressAndSave(CustomerId, Address);
        };

        return this.RedirectToAction("Customer", new {
            CustomerId = CustomerId
        });
    }

    public ActionResult Employee(
        int EmployeeId) {
        return this.View(this.EmployeeProvider.GetView(EmployeeId));
    }

    public ActionResult Employees() {
        return this.View(this.EmployeeProvider.GetAllView());
        //  OR
        //  return this.View(this.EmployeeProvider.GetActiveView());
        //  OR
        //  return this.Veiw(this.EmployeeProvider.GetInactiveView());
        //  ETC...
        //  All of these return the exact same object, just filled with different data
    }

    public RedirectToRouteResult EmployeeAddresses(
        int EmployeeId,
        Address Address) {
        if (ModelState.IsValid) {
            this.EmployeeProvider.AddAddressAndSave(EmployeeId, Address);
            //  I also have AddAddress in case I want to queue up a couple of tasks
            //  before I commit all changes to the data context.
        };

        return this.RedirectToAction("Employee", new {
            EmployeeId = EmployeeId
        });
    }
}

Is it best practices to have only one repository per controller?

I'm going to say no because your repositories will only work for the object they're instanced for. You can't have (well, you can, but that's just bad...) a repository that handles an Address, Email and Phone all at once because you'll have to specialize it just for it to work the way you need it.

My AddressProvider, EmailProvider and PhoneProvider are all essentially the same because they implement IProvider, however they each instance a generic repository (Repository<T>) for the object they're working with.

Furthermore, you're controller shouldn't be interacting with the repositories directly, but indirectly through the providers.

My CustomerProvider and EmployeeProvider each instance specialized repositories for Customer and Employee (CustomerRepository, EmployeeRepository), but they also instance other repositories they'll need when they for example construct the view models. For example, they'll instance a StateRepository which is Repository<State> or PhoneTypesRepository which is Repository<PhoneType>, and they'll use those repositories to pass additional objects/collections to the view to build up forms with drop downs or whatever. They'll also instance other providers to further help with building the view model such as CookieProvider which they use to get the currently active Cookie and pass it to the view model.

All in all it's a mesh of independent/generic providers or repositories which are combined to accomplish a specialized task.

I hope this sheds some light for you through an alternative way of writing code, or at the least I hope it just helps you understand a little bit better.

P.S. In case you're wondering what Provider is, most all other people choose to call them Service, but to me that word is misused, so I just call them Providers because they provide the controller with specialized functions or data as needed.

Gup3rSuR4c
  • 9,145
  • 10
  • 68
  • 126
0

Well, it seems like the sample mentioned is somewhat special case or its authors taste.

I'd advise to not comlicate things around and avoid such a layer supertype as a Base Controller unless it is clearly necessary. This approach lets you define as much Repositories (and other dependencies) per Controller as you like without forcing you to use special-case BaseController supertype.

The other advice is when you need some common logic between your Controllers prefer Composition over Inheritance.

So, to summarize - yes, it is normal to have different repositories injected in your Controller if that is your case and for me it seems as the better approach than some kind of unnecessary BaseController.

Community
  • 1
  • 1
Vasiliy R
  • 941
  • 8
  • 18