Karl Offenberger
Karl Offenberger

Reputation: 85

Property injection in to Web Api controller using Autofac

I'm trying to set a property on an System.Web.Http.ApiController to a value of a resolved IServerPackageRepository. The controller runs in a HttpSelfHostServer and the DependencyResolver has been set to AutofacWebApiDependencyResolver. Here is the code from the Autofac.Module.Load method

...

builder.RegisterType<ServerPackageRepository>()
    .As<IServerPackageRepository>()
    .SingleInstance()
    .WithParameter("path", this.StoragePath);

builder.RegisterApiControllers(Assembly.GetExecutingAssembly())
    .PropertiesAutowired();

The ApiController controller itself has a property of type

public IServerPackageRepository Repository { get; set; }

but is never resolved.

I am trying to do it this way because ApiController won't take nothing but default constructors. Any suggestions on how to do this the correct way using Autofac?

Upvotes: 1

Views: 4238

Answers (3)

Matthias G&#252;ntert
Matthias G&#252;ntert

Reputation: 4668

An alternative would be to directly wire your dependency to the property like so:

var repo = new ServerPackageRepository(path: this.StoragePath);

builder.RegisterInstance(repo)
    .SingleInstance();

builder.RegisterApiControllers(Assembly.GetExecutingAssembly())
    .WithProperty("Repository", repo)
    .PropertiesAutowired();

Upvotes: 0

Alex Meyer-Gleaves
Alex Meyer-Gleaves

Reputation: 3831

If the ApiController is only using the default constructor is sounds like the dependency resolver is not being called and may not be registered with Web API correctly. Here is a working example of self-hosting with constructor injection.

The dependency (in this case a simple logger):

public interface ILogger
{
    void Log(string text);
}

public class Logger : ILogger
{
    public void Log(string text)
    {
        Debug.WriteLine(text);
    }
}

A simple controller with a dependency on the logger:

public class ValuesController : ApiController
{
    readonly ILogger _logger;

    public ValuesController(ILogger logger)
    {
        _logger = logger;
    }

    // GET api/values
    public IEnumerable<string> Get()
    {
        _logger.Log("GET api/values");

        return new string[] { "value1", "value2" };
    }
}

The console application:

class Program
{
    static void Main(string[] args)
    {
        var configuration = new HttpSelfHostConfiguration("http://localhost:8080");

        configuration.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional }
            );

        var builder = new ContainerBuilder();

        // Register API controllers using assembly scanning.
        builder.RegisterApiControllers(Assembly.GetExecutingAssembly());

        // Register API controller dependencies.
        builder.Register<ILogger>(c => new Logger()).SingleInstance();

        var container = builder.Build();

        // Set the dependency resolver implementation.
        var resolver = new AutofacWebApiDependencyResolver(container);
        configuration.DependencyResolver = resolver;

        // Open the HTTP server and listen for requests.
        using (var server = new HttpSelfHostServer(configuration))
        {
            server.OpenAsync().Wait();

            Console.WriteLine("Hosting at http://localhost:8080/{controller}");
            Console.ReadLine();
        }
    }
}

Hit the controller action using:

http://localhost:8080/api/values

Please test this out and let me know if you have any problems.

Upvotes: 4

tugberk
tugberk

Reputation: 58494

Not sure if this is what you want but you can create your own base controller and inject the IServerPackageRepository into it.

public class MyApiController : ApiController { 

    public IServerPackageRepository ServerPackageRepository { get; set; }

    public MyApiController(IServerPackageRepository serverPackageRepository) { 

        ServerPackageRepository = serverPackageRepository;
    }
}

Then, use this as your base controller:

public class ProductsController : MyApiController { 

    public ProductsController(IServerPackageRepository serverPackageRepository) 
        : base(serverPackageRepository) { 
    }

    public IEnumerable<Product> Get() { 

        ServerPackageRepository.DoWork();

        //...
    }
}

Upvotes: 2

Related Questions