Actually, the "right" way is to NOT use a factory at all unless there is absolutely no other choice (as in unit testing and certain mocks - for production code you do NOT use a factory)! Doing so is actually an anti-pattern and should be avoided at all costs. The whole point behind a DI container is to allow the gadget to do the work for you.
As was stated above in a prior post, you want your IoC gadget to assume the responsibility for the creation of the various dependent objects in your app. That means letting your DI gadget create and manage the various instances itself. This is the whole point behind DI - your objects should NEVER know how to create and/or manage the objects that they depend on. To do otherwise breaks loose coupling.
Converting an existing application to all DI is a huge step, but setting aside the obvious difficulties in doing so, you will want also (just to make your life a bit easier) to explore a DI tool that will perform the bulk of your bindings automatically (the core to something like Ninject is the "kernel.Bind<someInterface>().To<someConcreteClass>()"
calls that you make to match your interface declarations to those concrete classes you wish to use to implement those interfaces. It's those "Bind" calls that allow your DI gadget to intercept your constructor calls and provide the necessary dependent object instances. A typical constructor (pseudo code shown here) for some class might be:
public class SomeClass
{
private ISomeClassA _ClassA;
private ISomeOtherClassB _ClassB;
public SomeClass(ISomeClassA aInstanceOfA, ISomeOtherClassB aInstanceOfB)
{
if (aInstanceOfA == null)
throw new NullArgumentException();
if (aInstanceOfB == null)
throw new NullArgumentException();
_ClassA = aInstanceOfA;
_ClassB = aInstanceOfB;
}
public void DoSomething()
{
_ClassA.PerformSomeAction();
_ClassB.PerformSomeOtherActionUsingTheInstanceOfClassA(_ClassA);
}
}
Note that nowhere in that code was any code that created/managed/released either the instance of SomeConcreteClassA or of SomeOtherConcreteClassB. As a matter of fact, neither concrete class was even referenced. So...where did the magic happen?
In the start up portion of your app, the following took place (again, this is pseudo code but it's pretty close to the real (Ninject) thing...):
public void StartUp()
{
kernel.Bind<ISomeClassA>().To<SomeConcreteClassA>();
kernel.Bind<ISomeOtherClassB>().To<SomeOtherConcreteClassB>();
}
That little bit of code there tells the Ninject gadget to look for constructors, scan them, look for instances of interfaces that it has been configured to handle (that's the "Bind" calls) and then create and substitute an instance of the concrete class wherever the instance is referenced.
There is a nice tool that complements Ninject very well called Ninject.Extensions.Conventions (yet another NuGet package) that will do the bulk of this work for you. Not to take away from the excellent learning experience you will go through as you build this up yourself, but to get yourself started, this might be a tool to investigate.
If memory serves, Unity (formally from Microsoft now an Open Source project) has a method call or two that do the same thing, other tools have similar helpers.
Whatever path you choose, definitely read Mark Seemann's book for the bulk of your DI training, however, it should be pointed out that even the "Great Ones" of the software engineering world (like Mark) can make glaring errors - Mark forgot all about Ninject in his book so here is another resource written just for Ninject. I have it and its a good read: Mastering Ninject for Dependency Injection