P.Brian.Mackey
P.Brian.Mackey

Reputation: 44275

Implementing just a little IOC for MVC 3

I'm working on a design that will allow me to mock out my database so I can test my views. I don't want to read a full book on IOC because I don't have the time right now. So, this is my home cooking.

Controller:

    public ActionResult Milestone()
    {
        var result = SJMServiceFactory.GetService("Milestone");
        return View(result);
    }

Factory:

public static class SJMServiceFactory
{
    public static DatabaseCollection_Result<T> GetService(string serviceName)
    {
        switch(serviceName)
        {
            case("Milestone"): return MileStoneService.GetMilestone();
            case ("MilestoneMock"): return MileStoneService.GetMilestone(true);
            default : return default(T);
        }
    }
}

MileStone

public class MileStoneService
{
    public MileStoneService()
    {

    }
    public static DatabaseCollection_Result<Milestone> GetMilestone(bool Mock)
    {
        if (Mock)
        {
            DatabaseCollection_Result<Milestone> mileStones = new DatabaseCollection_Result<Milestone>();
            Milestone milestone1 = new Milestone();
            milestone1.Name = "New";
            Milestone milestone2 = new Milestone();
            milestone2.Name = "Assessment";
            mileStones.Results.Add(milestone1);
            mileStones.Results.Add(milestone2);
            return mileStones;
        }
        else
            return null;
    }
}

I figure I need to return an interface from my factory instead of that Generic type I tried and failed at doing. I don't know how to create an interface that works for all my models, is that the wrong direction?

Upvotes: 3

Views: 996

Answers (2)

quentin-starin
quentin-starin

Reputation: 26628

Don't fear the learning curve. IoC is a reasonably simple concept.

Ninject was the first container I picked up, and it went smoothly. The only point I really struggled with for any amount of time was how to organize all the bindings, but even that was only an issue in large applications.

YMMV, but I'd say just diving in with Ninject or similar is better investment of time than DIY.

IoC with Ninject only takes code in a few places.

1: Bind you interfaces to implementations:

public class ServiceModule : NinjectModule
{
    public override void Load() {
        Bind<Common.Billing.AuthorizeNet.IBillingGatewayParametersFactory>().To<AuthorizeNetParameterFactory>();
        Bind<Common.Billing.IBillingGateway>().To<Common.Billing.AuthorizeNet.BillingGateway>();
    }
}

2: Use constructor arguments to pass dependencies into a class:

public class BillPayingService
{
    private readonly IBillingGateway _billingGateway;

    public BillPayingService(
            IBillingGateway billingGateway
        )
    {
        _billingGateway = billingGateway;
    }

    public void PayBills()
    {
       // ....
    }
}

3: Initialize your container on application startup:

public static class Ioc
{
    public static void Initialize()
    {
        var modules = new INinjectModule[] {
            new ServicesModule(),
            new DataModule()
                            new VideoProcessing.NinjectModule()
        };


        IKernel kernel = new Ninject.StandardKernel(modules);
    }
}

Upvotes: 5

Michael
Michael

Reputation: 20049

Without reading a whole book (does one exist? IoC is a pretty small topic in the scheme of things):

Controller:

private readonly IMilestoneService milestoneSerivce;

public MilestoneController(IMilestoneService milestoneService)
{
    this.milestoneService = milestoneService;
}

public ActionResult Milestone()
{
    var result = milestoneService.GetMilestones();
    return View(result);
}

IMilestoneService.cs

public interface IMilestoneService
{
    DatabaseCollection_Result<Milestone> GetMilestones();
}

MilestoneService.cs

public class MilestoneService : IMilestoneService
{
    public DatabaseCollection_Result<Milestone> GetMilestones()
    {
        return null;
    }
}

MockMilestoneService.cs:

public class MockMilestoneService : IMilestoneService
{
    public DatabaseCollection_Result<Milestone> GetMilestones()
    {
        DatabaseCollection_Result<Milestone> mileStones = new DatabaseCollection_Result<Milestone>();
        Milestone milestone1 = new Milestone();
        milestone1.Name = "New";
        Milestone milestone2 = new Milestone();
        milestone2.Name = "Assessment";
        mileStones.Results.Add(milestone1);
        mileStones.Results.Add(milestone2);
        return mileStones;
    }
} 

Global.asax:

ObjectFactory.Configure(x => {
    x.For<IMilestoneService>().Use<MilestoneService>();
    // uncomment for test
    //x.For<IMilestoneService>().Use<MockMilestoneService>();
});

This uses StructureMap, but I imagine the Ninject way to wiring up the dependencies is similar. Having never used Ninject I don't know for sure, but it looks like it might be something like:

Bind<IMilestoneService>().To<MilestoneService>();

In general though I wouldn't go about creating a whole new class to test your Views, I would use a mocking framework such as Moq to create mock objects and pass them to the View and then use Assertions about the ViewResult to determine if it worked correctly.

If you're doing interactive testing though and want to be detached from the database, this might be an ok approach.

Upvotes: 7

Related Questions