Take the 2-minute tour ×
Code Review Stack Exchange is a question and answer site for peer programmer code reviews. It's 100% free, no registration required.

Just used DI containers in MVC projects, via constructor injection, and I'd need to now inject a service into a console app. I'm using Autofac so I followed what I found here.

The code would be something like this:

The service the console app depends on:

public interface IBatchService
{
    void WriteInformation(string input);
}
public class BatchService : IBatchService
{
    public void WriteInformation(string input)
    {
        Console.WriteLine(input);
        Console.ReadKey();
    }
}

The console app main method

public class Program
{
    private static IContainer Container { get; set; }
    static void Main(string[] args)
    {
        var builder = new ContainerBuilder();

        builder.RegisterType<BatchService.BatchService>().As<IBatchService>();
        Container = builder.Build();

        using (var scope = Container.BeginLifetimeScope())
        {
            var batchService = scope.Resolve<IBatchService>();

            batchService.WriteInformation("Injected!");
        }
    }

It's using the Service Locator if I'm not wrong (I'm trying to get my head around all of this), which I would be likely to avoid in case I could as it's thoroughly discussed in the web. But can I actually avoid it in a console app? Can any see any big flaw with this implementation?

The main method is almost as simple as this one, only one call to one service (although the service doesn't write a console). And that's the only code in the project in fact.

share|improve this question
add comment

1 Answer 1

up vote 3 down vote accepted

Your Main method has too many responsibilities: it's your application's composition root, and it's executing the program's logic... if printing to Console can be considered logic.

There's not enough meat in this project to even justify using DI/IoC: you have a service that nothing depends on.

If you had, say, an Application class:

public interface IApplication
{
    void Run();
}

public class Application : IApplication
{
    private readonly IBatchService _service;
    public Application(IBatchService service)
    {
        _service = service;
    }

    public void Run()
    {
        _service.WriteInformation("Injected!");
    }
}

...then composition would refer to resolving all dependencies of an Application instance, regardless of how complex that might be.

The Main method would only ask for an Application instance (let's call it app), and your IoC container would do its job - the Main method would only call app.Run();, and the rest of the application doesn't need to know there's an IoC container involved.


You don't need the static IContainer field; I've never used Autofac (you should look into Ninject, seems much simpler), but your IoC container should only live (and die) in the Main method - if you're using it anywhere else, you're doing something wrong (Service Locator).

I'd make it something like this:

static void Main(string[] args)
{
    var builder = new ContainerBuilder();

    builder.RegisterType<BatchService.BatchService>().As<IBatchService>();
    var container = builder.Build();

    using (var scope = container.BeginLifetimeScope())
    {
        var app = scope.Resolve<IApplication>();
        app.Run();
    }
}

Then your Main method is done with. If you're going to expand the application, you just inject new dependencies, and consume them.

Actually, this:

builder.RegisterType<BatchService.BatchService>().As<IBatchService>();

I'd move elsewhere; as your application grows, you'll be registering tons of stuff here, registration is a concern of its own, that deserves its own class IMO. That class can be static for all you care, it's infrastructure stuff, its only goal is to spit out a configured IContainer.

The configuration class could look like this:

public static class ContainerConfig
{
    public static IContainer Configure()
    {
        var builder = new ContainerBuilder();

        builder.RegisterType<BatchService.BatchService>().As<IBatchService>();
        // add other registrations here...

        return builder.Build();
    }
}

Leaving your Main method like this:

static void Main(string[] args)
{
    var container = ContainerConfig.Configure();
    using (var scope = container.BeginLifetimeScope())
    {
        var app = scope.Resolve<IApplication>();
        app.Run();
    }
}
share|improve this answer
    
Thanks @Mat'sMug I completely agree that this project doesn't need injection, actually in the solution there are a few of the like this. With just classes of 40 lines calling one service each, so maybe I should raise that to the "owner" of the code who wanted me to use the container in all of them –  mitomed Jul 5 at 17:18
    
One small thing in Mat'sMug code is that we should add builder.RegisterType<Application>().As<IApplication>(); to the container config –  mitomed Jul 7 at 9:54
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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