Search code examples
c#dependency-injectionautofac

Registering a third party class in Autofac whose constructor take in values from another service


I am working with IQueueClient interface in Microsoft.Azure.ServiceBus namespace.

Here is my code

public HomeControllerBL(IApplicationSettings appSettings)
{
    _appSettings = appSettings;
}

and here is my IApplicationSettings Interface

public interface IApplicationSettings
{
    string GetServiceBusConnectionString();    
    string GetQueueName();
}

Now for creating an object of QueueClient

IQueueClient queueClient = new QueueClient(appSettings.GetServiceBusConnectionString(), appSettings.GetQueueName());

So IQueueClient has a dependency on IApplicationSettings .

Is there a way I can register both IQueueClient and IApplicationSettings with Autofac as a dependency for HomeControllerBL

Something on these Lines :-

builder.RegisterType<ApplicationSettings>()
    .As<IApplicationSettings>()
    .InstancePerLifetimeScope();

builder.RegisterType<QueueClient>()
    .As<IQueueClient>().WithParameters(new List<Parameter>() { How to access Applicationsettings methods here ???  })
    .InstancePerLifetimeScope();

Solution

  • Reference Lambda Expression Components

    Reflection is a pretty good default choice for component creation. Things get messy, though, when component creation logic goes beyond a simple constructor call.

    Autofac can accept a delegate or lambda expression to be used as a component creator:

    builder.Register(c => {
        IApplicationSettings appSettings = c.Resolve<IApplicationSettings>();
        IQueueClient queueClient = new QueueClient(appSettings.GetServiceBusConnectionString(), appSettings.GetQueueName());
        return queueClient;
    })
    .As<IQueueClient>()
    .InstancePerLifetimeScope();
    

    The parameter c provided to the expression is the component context (an IComponentContext object) in which the component is being created. You can use this to resolve other values from the container to assist in creating your component. It is important to use this rather than a closure to access the container so that deterministic disposal and nested containers can be supported correctly.

    So now the controller can depend on IQueueClient explicitly

    private readonly IQueueClient queueClient;
    
    public HomeControllerBL(IQueueClient queueClient) {
        this.queueClient = queueClient;
    }