Autofac resolving dependencies - c#

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.

Related

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();
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;
}

How to use factory to resolve interface using Autofac

I want to have a service like the following
public SomeService(IMongoDatabase mongoDatabase) {
DB = mongoDatabase;
}
and I want to use a factory to resolve IMongoDatabase, just to encapsulate the IConfiguration usage
public static IMongoDatabase GetMongoDatabase(IConfiguration config)
{
var connectionString = config.Get("SomeConnectionString");
// MongoClient handles connection pooling internally
var client = new MongoClient(connectionString);
var db = client.GetDatabase(config.Get("SomeDbName"));
return db;
}
I can't figure out how to handle the registrations so that MongoDbFactory.GetMongoDatabase gets called whenever any class needs an IMongoDatabase. IConfiguration will be registered already.
I'd really like to just use an IMongoDatabase and not a Func<IConfiguration, IMongoDatabase> in my Service. The latter just seems way too obtuse, requiring consumers to implement steps that I should be able to implement for them.
You can register your static GetMongoDatabase factory method like this :
builder.Register(c => MongoDbFactory.GetMongoDatabase(c.Resolve<IConfiguration>)())
.As<IMongoDatabase>();
By the way, using a static method may introduce some problem, it may be better to register the MongoDbFactory class and use it in your factory registration.
builder.RegisterType<MongoDbFactory>()
.AsSelf();
builder.Register(c => c.Resolve<MongoDbFactory>().GetMongoDatabase())
.As<IMongoDatabase>();
Of course, you will need to adapt the MongoDbFactory implementation to make it work - by adding a property for Configuration and adding IConfiguration to the constructor.

Autofac/FluentValidation: No scope with a Tag matching 'AutofacWebRequest' is visible from the scope in which the instance was requested

Attempting to inject data into a FluentValidation validator:
public class MyFormValidator : AbstractValidator<MyForm>
{
private readonly IQueryable<Models.User> _users;
public MyFormValidator(IQueryable<Models.User> users)
{
_users = users;
...
}
}
My validator factory:
public class DependencyResolverValidatorFactory : ValidatorFactoryBase
{
private readonly IContainer container;
public DependencyResolverValidatorFactory(IContainer container)
{
this.container = container;
}
public override IValidator CreateInstance(Type validatorType)
{
return container.ResolveOptionalKeyed<IValidator>(validatorType);
}
}
My Autofac configurator:
public class AutofacConfigurator
{
public static void Configure()
{
var builder = new ContainerBuilder();
...
builder.RegisterType<MyFormValidator>()
.Keyed<IValidator>(typeof(IValidator<MyForm>))
.As<IValidator>()
// 2nd parameter returns IQueryable<User>
.WithParameter("users", new SqlRepository<User>(dataContext))
.InstancePerRequest();
builder.RegisterSource(new AnyConcreteTypeNotAlreadyRegisteredSource());
var container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
// Register the validator factory with FluentValidation, and register
// FluentValidation as the model validator provider for the MVC framework.
// see http://www.jerriepelser.com/blog/using-fluent-validation-with-asp-net-mvc-part-3-adding-dependency-injection
var fluentValidationModelValidatorProvider =
new FluentValidationModelValidatorProvider(
new DependencyResolverValidatorFactory(container));
DataAnnotationsModelValidatorProvider.AddImplicitRequiredAttributeForValueTypes = false;
fluentValidationModelValidatorProvider.AddImplicitRequiredValidator = false;
ModelValidatorProviders.Providers.Add(fluentValidationModelValidatorProvider);
}
}
Getting the following exception:
No scope with a Tag matching 'AutofacWebRequest' is visible from the scope in which the instance was requested. This generally indicates that a component registered as per-HTTP request is being requested by a SingleInstance() component (or a similar scenario.) Under the web integration always request dependencies from the DependencyResolver.Current or ILifetimeScopeProvider.RequestLifetime, never from the container itself.
I have other validators, most of which will not need data injected into them.
This is largely new ground for me (in both Autofac and FluentValidation) and am still trying to understand what I am doing here. I suspect I'm simply registering my type incorrectly. How do I fix this and properly register my type?
(My apologies if this is too similar to other questions that were already asked.)
I have zero experience with FluentValidation, but I doubt it's the cause of your issues anyway, so I'll plow forward regardless.
The exception you're getting means that Autofac can't resolve your service as 'instance per request'. There's a lot of documentation as to what this means on the Autofac documentation page. To summarize, it means that Autofac will attempt to resolve the service from a lifetime scope that is automatically created for each request sent to the webserver. When you register something as .InstancePerRequestScope() but then attempt to resolve that service outside of that scope, you'll get the DependencyResolutionException you see.
So we've established that your MyFormValidator isn't being resolved from a 'Request' scope. Why?
The custom DependencyResolverValidatorFactory you've written takes the actual IContainer that was built by Autofac, and resolves from that. This is a special type of ILifetimeScope, the 'root scope'. There's no request lifetime scope directly associated with this, so you get your exception. You need to to resolve from an ILifetimeScope that is began from the 'request' scope, or a sub-scope that is contained within the request scope.
The Autofac/MVC integration already automatically hosts a request scope (within the AutofacDependencyResolver, see the source), but your custom DependencyResolverValidatorFactory doesn't resolve from it. If you want to do that, I suppose you could modify your DependencyResolverValidatorFactory to accept the AutofacDependencyResolver instance instead, and use that to resolve.
It would look something like this:
public class DependencyResolverValidatorFactory : ValidatorFactoryBase
{
private readonly AutofacDependencyResolver resolver;
public DependencyResolverValidatorFactory(AutofacDependencyResolver resolver)
{
this.resolver = resolver;
}
public override IValidator CreateInstance(Type validatorType)
{
return resolver.RequestLiftimeScope.ResolveOptionalKeyed<IValidator>(validatorType);
}
}
Note the RequestLifetimeScope stuck in there.
Then you create this in your .Configure() method using
var resolver = new AutofacDependencyResolver(container);
DependencyResolver.SetResolver(resolver);
var fluentValidationModelValidatorProvider =
new FluentValidationModelValidatorProvider(
new DependencyResolverValidatorFactory(resolver));
That should get rid of the exception, assuming that this factory does indeed have a request to work from when creating instances of IValidators. If not, You might need to register using the default behavior (.InstancePerDependency(), where it creates a new instance every time it's requested) or a singleton (.SingleInstance()), depending on how/if validators can or should be shared.
Good luck.

autofac: component registration being ignored

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();

Orchard CMS, Autofac Relationship

I am trying to create a "A(UserManager) needs to create instances of B(UserClient)" relationship (http://code.google.com/p/autofac/wiki/RelationshipTypes) where B(UserClient) needs a HttpSessionStateBase..
UserClient
public class UserClient : IUserClient
{
public UserClient(HttpSessionStateBase session)
{
//...
}
//...
}
UserManager
public class UserManager : IUserManager
{
private readonly Func<IUserClient> userClientPerRequest;
private IUserClient UserClient
{
get
{
return userClientPerRequest();
}
}
public UserManager(Func<IUserClient> userClientPerRequest)
{
this.userClientPerRequest = userClientPerRequest;
}
public void DoStuff()
{
UserClient.DoStuff();
}
This is where is register autofac stuff
public class MyModule : Module
{
protected override void Load(ContainerBuilder builder)
{
base.Load(builder);
builder.RegisterType<UserManager>().As<IUserManager>().SingleInstance();
builder.RegisterType<UserClient>().As<IUserClient>().InstancePerHttpRequest();
builder.RegisterModule(new AutofacWebTypesModule());
//If i try this, i get Error 1 (printing errors after this code-block)
builder.Register<Func<IUserClient>>(c => c.Resolve<IUserClient>);
//If i try this, i get Error 2
builder.Register<Func<IUserClient>>(c => {
var ctx = c.Resolve<IComponentContext>();
return ctx.Resolve<IUserClient>;
});
//If i try this, well i always get null from GetService..
builder.Register<Func<IUserClient>>(c =>
DependencyResolver.Current.GetService<IUserClient>);
}
Looking at Autofac: Reference from a SingleInstance'd type to a HttpRequestScoped , they use some RequestContainer but i can find no such thing. :)
Error 1
This resolve operation has already ended. When registering components using lambdas, the IComponentContext 'c' parameter to the lambda cannot be stored. Instead, either resolve IComponentContext again from 'c', or resolve a Func<> based factory to create subsequent components from.
Error 2
No scope with a Tag matching 'AutofacWebRequest' is visible from the scope in which the instance was requested. This generally indicates that a component registered as per-HTTP request is being reqested by a SingleInstance() component (or a similar scenario.) Under the web integration always request dependencies from the DependencyResolver.Current or ILifetimeScopeProvider.RequestLifetime, never from the container itself.
I have tried switching .InstancePerHttpRequest() to .InstancePerLifetimeScope() and a whole other different stuff.. Anyone have any ideas?
Thanks
When adding Autofac registrations manually in Orchard, use InstancePerMatchingLifetimeScope("shell"), if you need a singleton or InstancePerMatchingLifetimeScope("work"), if you need per-request instance.
I'm not sure if HttpSessionStateBase ctor argument can actually be resolved from the container. You could put IHttpContextAccessor there instead and use it to access the session state object inside IUserClient implementation.
And as Jim Bolla suggested - Func<IUserClient> (factory) is already available out of the box.
I don't think you need to do either of those registrations. Because of Relationship Types, Func<IUserClient> should already be available to you.

Categories