This approach requires that every derived controller class also
implements a constructor that accepts any arguments requires by my
controller base class. Not only does this seem like a lot of extra
typing that I must remember to add to any new derived class, but it
also means that if I change the data passed to the constructor then I
must modify the constructor in every derived controller class.
This is one of the approach (Heavy Controller) that you may choose to use EF into your application, IMO its not the cleanest approach. And you correctly noticed the drawbacks your self.
If we relate this approach to design principle, it breaks Single Responsibility Principle as controller is expected to do more (fetch or update DB) than just collecting the data and return the appropriate view with data. And how about business rules, would controller apply it, if you need to send an email, would controller does that as well. You ought to have another layer of business/service classes that are specifically designed for a set of requirement e.g. EmailHelper would send emails.
It also breaks Open Close Principle as you need to change the constructors every time you change the input parameter.
This gives me a DBContext for all my controller classes. But what
about other classes in my model that need the DBContext? Should I need
to manually pass the instance to the DBContext to all these classes?
As far as dependency injection is concerned one of the goal is, to inject the dependency where it is needed directly. If you have a model class that needs DbContext, you should inject it in your model class constructor (most DI framework support property injection as well but constructor remains favourite approach).
With DI Framework, you will configure the dependencies at one place (application initialization code) and then each class that need a dependency just accept it in constructor.
DI Container can be compared to a dictionary where key is interface and the value is a cooked object. Once its setup, you can anytime ask for any object by using the right key through out your application.
Or is there a way to use DI for each of these classes to get their own
copy of the DBContext?
The DI framework supports different ways of instantiation to allow controlling the lifetime of the instance. Typically, per request, per thread and singleton. More information here. If you want each controller to get a copy of DbContext, you can use per request configuration when you set up DbContext instantiation.
Alternate Solution:
Most of my MVC applications, I have had a service layer (set of classes that apply business rule). Each of these classes were injected with DbContext (not exactly a DbContext but IDataContext). The controllers were injected with the service class that they need to retrieve or update the data.
Have abstracted the DbContext behind IDataContext, I could setup a stub data context in my test or tomorrow if I want to switch from EF to NHibernate or something more smart DI Framework, i will just have to implement IDataContext and change the dependency initialization code.
Hope this helps.