The following class takes a primitive on the constructor, so I need to tell AutoFac how to generate said value using a delegate:
public class BackgroundTaskScheduler : IStartable
{
private readonly IJobRunner _jobRunner;
private int _triggerMilliseconds;
public BackgroundTaskScheduler(IJobRunner jobRunner, int triggerMilliseconds)
{
_jobRunner = jobRunner;
_triggerTimespan = triggerMilliseconds;
}
}
public static class AutoFac
{
public static void Configure()
{
var builder = new ContainerBuilder();
var triggerInterval =
int.Parse(
ConfigurationManager.AppSettings["TaskScheduleTriggerMilliseconds"]);
builder.Register(
c => new BackgroundTaskScheduler(c.Resolve<IJobRunner>(), triggerInterval)).AsImplementedInterfaces().SingleInstance();
builder.RegisterAssemblyTypes(typeof (RegistrationController).Assembly)
.AsImplementedInterfaces()
.AsSelf();
IContainer container = builder.Build();
}
}
However, Autofac appears to ignore my registration as evidenced by the exception it throws when resolving an instance of BackgroundTaskScheduler:
None of the constructors found with 'Autofac.Core.Activators.Reflection.DefaultConstructorFinder' on type 'Delen.Server.Tasks.BackgroundTaskScheduler' can be invoked with the available services and parameters:
Cannot resolve parameter 'System.Int32 triggerMilliseconds' of constructor 'Void .ctor(Delen.Server.Tasks.IJobRunner, System.Int32)'.
I've successfully used the IContainerBuilder.Register method before in exactly such a scenario but I've no clue why it's not working this go around.
Update 1
Changing the order of the registrations did not make a difference.
Update 2
Here's an alternative way to achieve the same result as the accepted Answer:
builder.RegisterAssemblyTypes(typeof(IJobRunner).Assembly)
.Except<BackgroundTaskScheduler>()
.AsImplementedInterfaces()
.AsSelf()
The order of the registrations does mater beside that using the assembly scanning features can be dangerous if you also want to register types by hand because you could end up interfering registrations.
In your case you are registering your BackgroundTaskScheduler twice
once with the correct parameters when calling builder.Register
the second type when calling builder.RegisterAssemblyTypes this time without the required triggerInterval parameter.
So you've ended up two registrations where one of them is not correct so when calling builder.Build you get the exception.
To fix it you need to exclude all the hand registered types in the RegisterAssemblyTypes call:
builder.RegisterAssemblyTypes(typeof(AutofacRegistrationOrderTest).Assembly)
.Where(t => t != typeof(BackgroundTaskScheduler))
.AsImplementedInterfaces()
.AsSelf();
builder.Register(
c => new BackgroundTaskScheduler(c.Resolve<IJobRunner>(), triggerInterval))
.AsImplementedInterfaces()
.SingleInstance();
Related
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();
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;
}
I have the following class:
public class CustomDatabase : DbContext
{
public void Function1(){..}
}
public class CustomerDb : CustomDatabase
{
public void GetCustomerById(guid id){..}
}
This is created by calling
services.AddDbContext<CustomerDb>();
and is used all around the code as CustomerDb.
I now want to use a middleware from a nuget that does not know about my project, but knows about the CustomDatabase implementation. But when I try to refer to CustomDatabase I get an run-time error saying that the DI framework can not find CustomDatabase.
How can I make it so I can refer to this instance as both CustomDatabase and CustomerDb?
You cannot achieve this with the default DI container (aka. Microsoft.Extensions.DependencyInjection) because it does not support registering a service as multiple resolving interfaces. Even if you register one type as factory function that resolves and return another one, the service would be duplicately disposed (This could even be a possible solution if the service implementation type does not implement IDisposable or its Dispose method could be called for multiple times without unexpected behaviors). eg.
Given the types:
interface I1 { }
interface I2 { }
class C : I1, I2 { }
If the service implementation type does not implement IDisposable or its Dispose method could be called for multiple times without unexpected behaviors:
var services = new ServiceCollection();
services.AddSingleton<I1, C>();
services.AddSingleton<I2>(p => (I2)p.GetService<I1>()); //Must be exactly the same lifetime scope
var provider = services.BuildServiceProvider();
var i1 = provider.GetRequiredService<I1>();
var i2 = provider.GetRequiredService<I2>();
Console.WriteLine(i1 == i2); //True
But you can use Autofac to replace the default service provider that can easily do it.
var builder = new ContainerBuilder();
builder.RegisterType<C>().AsImplementedInterfaces().SingleInstance();
var container = builder.Build();
var i1 = container.Resolve<I1>();
var i2 = container.Resolve<I2>();
Console.WriteLine(i1 == i2); //true
As for your DbContext classes, you could register it manually:
builder
.RegisterType<CustomerDb>()
.AsSelf() //So that it could be resolved as CustomerDb
.As<CustomDatabase>() //So that it could be resolved as CustomDatabase
.InstancePerLifetimeScope() //Note that EF Core's DbContext is designed to be scoped services
.OwnedByLifetimeScope(); //Dispose when the scope (the request lifetime) is disposed as the default service provider does
Register the context as you have done originally and also include a registration for the derived type using the same lifetime with the factory delegate
services.AddDbContext<CustomerDb>();
services.AddScoped<CustomDatabase>(sp => sp.GetRequiredService<CustomerDb>());
I am really new to autofac and having issues.
I am using Web API and I have set my module up like this:
public class CormarModule : Module
{
// Fields
private readonly string _connectionStringName;
private readonly connectionType _connection;
/// <summary>
/// Default constructor
/// </summary>
public CormarModule() {
_connectionStringName = ConfigurationManager.AppSettings["ConnectionStringName"];
_connection = _connectionStringName.ToUpper().Contains("LIVE") ? connectionType.Live : connectionType.Test;
}
protected override void Load(ContainerBuilder builder)
{
// Singletons
builder.RegisterType<DatabaseContext>().As<DatabaseContext>().SingleInstance();
builder.RegisterType<UnitOfWork<DatabaseContext>>().As<IUnitOfWork>().SingleInstance();
builder.Register(c => new OracleUnitOfWork(_connectionStringName)).As<IOracleUnitOfWork>().SingleInstance();
builder.Register(c => new AdvancedEncryptionStandardProvider(ConfigurationManager.AppSettings["rm:key"], ConfigurationManager.AppSettings["rm:secret"])).As<IAdvancedEncryptionStandardProvider>().SingleInstance();
// Register our services
builder.RegisterType<AccountService>().As<IAccountService>();
builder.RegisterType<DeliveryInformationService>().As<IDeliveryInformationService>();
builder.RegisterType<EmailService>().As<IEmailService>();
builder.RegisterType<LogService>().As<ILogService>();
builder.RegisterType<OrderService>().As<IOrderService>();
builder.RegisterType<OrderLineService>().As<IOrderLineService>();
builder.RegisterType<PaymentHistoryService>().As<IPaymentHistoryService>();
builder.RegisterType<PrincipleProvider>().As<IPrincipleProvider>();
builder.RegisterType<ProductService>().As<IProductService>();
builder.RegisterType<RefreshTokenService>().As<IRefreshTokenService>();
builder.RegisterType<StockService>().As<IStockService>();
builder.Register(c => new UserStore<User>(c.Resolve<DatabaseContext>())).As<IUserStore<User>>();
// Single instance
builder.RegisterType<OAuthProvider>().As<OAuthProvider>();
builder.RegisterType<LogProvider>().As<ILogProvider>();
builder.RegisterType<RefreshTokenProvider>().As<IAuthenticationTokenProvider>();
builder.Register(c => new SendGridProvider(c.Resolve<IUnitOfWork>(), c.Resolve<IEmailService>(), ConfigurationManager.AppSettings["SendGridApiKey"])).As<ISendGridProvider>();
builder.Register(c => new UserProvider(_connectionStringName, c.Resolve<IUserStore<User>>(), c.Resolve<IAdvancedEncryptionStandardProvider>(), c.Resolve<ISendGridProvider>())).As<IUserProvider>();
// Per request
builder.RegisterType<DeliveryInformationProvider>().As<IDeliveryInformationProvider>().InstancePerRequest();
builder.RegisterType<JournalProvider>().As<IJournalProvider>().InstancePerRequest();
builder.RegisterType<StockProvider>().As<IStockProvider>().PropertiesAutowired(PropertyWiringOptions.AllowCircularDependencies).InstancePerRequest();
builder.Register(c => new AccountProvider(_connection, c.Resolve<IAccountService>(), c.Resolve<IPrincipleProvider>(), c.Resolve<IAdvancedEncryptionStandardProvider>(), c.Resolve<IPaymentHistoryService>())).As<IAccountProvider>().InstancePerRequest();
builder.Register(c => new ProductProvider(_connection, c.Resolve<IProductService>())).As<IProductProvider>().InstancePerRequest();
builder.Register(c => new OrderProvider(_connection, c.Resolve<IOrderService>(), c.Resolve<IPrincipleProvider>(), c.Resolve<IAdvancedEncryptionStandardProvider>())).As<IOrderProvider>().PropertiesAutowired(PropertyWiringOptions.AllowCircularDependencies).InstancePerRequest();
builder.Register(c => new OrderLineProvider(_connection, c.Resolve<IOrderLineService>(), c.Resolve<IPrincipleProvider>(), c.Resolve<IAdvancedEncryptionStandardProvider>())).As<IOrderLineProvider>().InstancePerRequest();
}
}
I am struggling with the different scopes.
A little background before I explain my issue.
Each Provider has a required Service and each Controller has one or more Providers injected.
Each Provider could have an optional Provider which should only be resolved when a method invokes that provider.
The problem I have is I don't know how to set that up.
I was going to inject the lifetime scope into the constructor and in the method, resolve the required Provider, but I have read this is bad practice, plus it would create a new instance. I would like to use one instance per request, but only if it is need in that request.
I hope that makes sense and I hope someone can help!
IMO, you're doing pretty good.
What you need is to take a dependency on a Func<Provider>. When you ask Autofac a Func<> it returns a factory method, to be called instead of .Resolve<Provider>.
See here and here for documentation.
You can write it this way:
private OptionalProvider _instance;
private Func<OptionalProvider> _providerGetter;
public OptionalProvider Prov
{
get { return _instance ?? (_instance = _providerGetter()); }
}
public MyProvider(Func<OptionalProvider> getter)
{
_providerGetter = getter;
}
public void MethodRequiringOptionalProvider()
{
// just use property Prov and let Autofac handle the rest
}
Another suggestion: instead of injecting directly the _connection string parameter, just create a CormarConfig class, to be registered with .RegisterInstance to store all your configuration options.
This way you just call RegisterType and let Autofac resolve all the type parameters (you get rid of those ugly Resolve calls).
If all your services inherit from a common ancestor or implement a common interface, you can register them all via Assembly Scanning and AsImplementedInterfaces. You would get rid of all the clutter in your module.
We have a Web API project and using the Autofac Web API Integration as the IoC container. The code that we use to register all of our types is as follows:
public class CompositionRootConfigurator
{
public static AutofacWebApiDependencyResolver Configure(Assembly servicesAssembly)
{
var container = BuildContainer(servicesAssembly);
var resolver = new AutofacWebApiDependencyResolver(container);
return resolver;
}
public static IContainer BuildContainer(Assembly servicesAssembly)
{
/*TO DELETE ONCE THE REFERENCES ISSUE IS RESOLVED!*/
var dummy = new EmployeesBL(new ContextFactory(new DBContextFactory(new RoleBasedSecurity(), new Identity())));
var builder = new ContainerBuilder();
if (servicesAssembly != null) // this is a temporary workaround, we need a more solid approach here
{
builder.RegisterApiControllers(servicesAssembly);
}
/* Registers all interfaces and their implementations from the following assemblies in the IoC container
* 1. CB.CRISP.BL
* 2. CB.CRISP.BL.CONTRACTS
* 3. CB.CRISP.DAL
* 4. CB.CRISP.DAL.CONTRACTS
* The current assembly is excluded because the controllers were registered with the builder.RegisterApiControllers expression above.
*/
var appAssemblies = AppDomain.CurrentDomain
.GetAssemblies()
.Where(a => a.ToString().StartsWith("CB.CRISP"))
.ToArray();
builder.RegisterAssemblyTypes(appAssemblies).AsImplementedInterfaces();
if (servicesAssembly != null)
{
builder.RegisterAssemblyTypes(servicesAssembly).AsImplementedInterfaces();
}
return builder.Build();
}
}
Now suppose we have a MyType which implements IMyType and this is the only one that must be a single instance per request and it will be injected in several objects along the hierarchy.
I am at a loss in how to specify this within this existing code. If I just go ahead and just do
builder.RegisterType<MyType>()
.As<IMyType>()
.InstancePerRequest();
since it will also be registered with all the others Will one registration overwrite the other one, will they be duplicated, are there potential problems?
Thank you for your insight.
Autofac will override the first registration and will accept the last one. Here is more detail.
So you should register MyType after registering all type.
I haven't seen any potential problem of this.
But you can register all types like this to be sure.
builder.RegisterAssemblyTypes(servicesAssembly).Except<MyType>().AsImplementedInterfaces();
Here is more detail about scanning.
I am using Autofac for IoC in my project. Due to some legacy software libraries I must pass some services to the controller that can't be resolved, and must be passed as parameter.
I've made a generic control using delegate factories like this:
public MyClass<TController, TInterface> {
private delegate TController ControllerFactory(TInterface service);
protected TController _myController;
protected TController Controller {
get
{
return _controller
?? (_controller = ServiceLocator.Resolve<ControllerFactory>()
.Invoke(this);
}
}
}
This works perfect, but for this to work I need the controller's service parameter name and the delegate service parameter name be the same, because as I have read, Autofac pairs the parameter BY NAME !!
I've seen you can do it by type registering the class with generic Func<>, but due to the legacy app I would need to leave "clean" registrations i.e.:
containerBuilder.RegisterType<MyController>();
Does anyone know if it's possible to make the delegate match the parameter by type??
Does anyone know if it's possible to make the delegate match the parameter by type??
Yes, you can use predefined delegates. See dynamic instantiation section here.
Here's an quick example:
public class ComponentFactory
{
private readonly Func<Dependency, Component> _componentFactory;
public ComponentFactory(Func<Dependency, Component> componentFactory)
{
_componentFactory = componentFactory;
}
public Component Create(Dependency dependency)
{
return _componentFactory(dependency);
}
}
public class Component
{
private readonly Dependency _dependency;
public Component(Dependency dependency)
{
_dependency = dependency;
}
}
public class Dependency
{
}
Registration + Usage
var builder= new ContainerBuilder();
builder.RegisterType<ComponentFactory>();
builder.RegisterType<Component>();
builder.RegisterType<Dependency>();
var container = builder.Build();
var factory = container.Resolve<ComponentFactory>();
//Usage with typed parameters
var component = factory.Create(new Dependency());
**Be warned, if you use this method, Autofac throws an exception if you try to add parameters with of the same type. Ex. Component has two dependencies on Dependency
Exception looks something like this:
The input parameter type list
has duplicate types. Try registering a custom delegate type instead of
using a generic Func relationship.
Autofac is more specific about what type you register the controller as than most DI containers. It will only resolve the type by its type if you include .AsSelf() in the registration of the controller. Here is a module we use in our project for registering MVC controllers.
public class MvcModule
: Module
{
protected override void Load(ContainerBuilder builder)
{
var currentAssembly = typeof(MvcModule).Assembly;
builder.RegisterAssemblyTypes(currentAssembly)
.Where(t => typeof(IController).IsAssignableFrom(t))
.AsImplementedInterfaces()
.AsSelf()
.InstancePerDependency();
}
}
Using this registration, you can resolve each controller by controller type.
var type = typeof(HomeController);
var controller = container.Resolve(type);