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.
Related
I thought I understood how AddHttpClient worked, but apparently, I do not. I've distilled this problem down to the very basics, and it still isn't functioning as I expect.
I have the following class and interface:
public interface ISomeService
{
Uri BaseAddress { get; }
}
public class SomeService : ISomeService
{
private readonly HttpClient _client;
public SomeService(HttpClient client)
{
_client = client;
}
public Uri BaseAddress => _client.BaseAddress;
}
Simply exposing the BaseAddress for the purposes of this example.
Now, I perform the following:
[Fact]
public void TestClient()
{
var services = new ServiceCollection();
services.AddHttpClient<SomeService>((serviceProvider, client) =>
{
client.BaseAddress = new Uri("http://fakehost");
});
services.AddSingleton<ISomeService, SomeService>();
var provider = services.BuildServiceProvider();
var svc = provider.GetRequiredService<ISomeService>();
svc.BaseAddress.Should().Be("http://fakehost");
}
and it fails, because the base address is null, instead of http://fakehost like I expect.
This is because somehow, SomeService gets an HttpClient created for it without going through my configure method (I added a breakpoint, it never got hit). But like magic I still an actual constructed instance of SomeService.
I've tried adding the HttpClient typed to the interface instead, no luck.
I found that if I GetRequiredService<SomeService>, instead of for ISomeService the code behaves as expected. But I don't want people injecting concrete SomeService. I want them to inject an ISomeService.
What am I missing? How can I inject an HttpClient already configured with a base address to a service that will be, itself, injected via DI (with other potential dependencies as well).
Background: I'm building a client library with ServiceCollectionExtensions so that consumers can just call services.AddSomeService() and it will make ISomeService available for injection.
EDIT:
I have since found (through experimentation) that .AddHttpClient<T> seems to add an HttpClient for T only when explicitly trying to resolve T, but also adds a generic HttpClient for any other class.
commenting out the AddHttpClient section of my test resulted in failed resolution but changing the to AddHttpClient<SomeOtherClass> allowed ISomeService to resolve (still with null BaseAddress though).
EDIT 2:
The example I posted originally said I was registering ISomeService as a singleton, which I was, but after inspection, I've realized I don't need it to be so switching to transient allows me to do
.AddHttpClient<ISomeService, SomeService>(...)
Internally build in DI works with ServiceDescriptors which represent implementation type-service type pairs. AddHttpClient<SomeService> registers SomeService as SomeService which has nothing to do with ISomeService from DI standpoint, just provide service type and implementation type:
services.AddHttpClient<ISomeService, SomeService>((serviceProvider, client) =>
{
client.BaseAddress = new Uri("http://fakehost");
});
Though it will register the service type as transient.
If you need to have it as singleton - you can try reabstracting (though it should be done with caution as mentioned in the comments):
services.AddHttpClient<SomeService>((serviceProvider, client) =>
{
client.BaseAddress = new Uri("http://fakehost");
});
services.AddSingleton<ISomeService>(sp => sp.GetRequiredService<SomeService>());
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;
}
In my Asp.Net Core App I need a singleton service that I can reuse for the lifetime of the application. To construct it, I need a DbContext (from the EF Core), but it is a scoped service and not thread safe.
Therefore I am using the following pattern to construct my singleton service. It looks kinda hacky, therefore I was wondering whether this is an acceptable approach and won't lead to any problems?
services.AddScoped<IPersistedConfigurationDbContext, PersistedConfigurationDbContext>();
services.AddSingleton<IPersistedConfigurationService>(s =>
{
ConfigModel currentConfig;
using (var scope = s.CreateScope())
{
var dbContext = scope.ServiceProvider.GetRequiredService<IPersistedConfigurationDbContext>();
currentConfig = dbContext.retrieveConfig();
}
return new PersistedConfigurationService(currentConfig);
});
...
public class ConfigModel
{
string configParam { get; set; }
}
What you're doing is not good and can definitely lead to issues. Since this is being done in the service registration, the scoped service is going to be retrieve once when your singleton is first injected. In other words, this code here is only going to run once for the lifetime of the service you're registering, which since it's a singleton, means it's only going to happen once, period. Additionally, the context you're injecting here only exists within the scope you've created, which goes away as soon as the using statement closes. As such, by the time you actually try to use the context in your singleton, it will have been disposed, and you'll get an ObjectDisposedException.
If you need to use a scoped service inside a singleton, then you need to inject IServiceProvider into the singleton. Then, you need to create a scope and pull out your context when you need to use it, and this will need to be done every time you need to use it. For example:
public class PersistedConfigurationService : IPersistedConfigurationService
{
private readonly IServiceProvider _serviceProvider;
public PersistedConfigurationService(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public async Task Foo()
{
using (var scope = _serviceProvider.CreateScope())
{
var context = scope.ServiceProvider.GetRequiredService<IPersistedConfigurationDbContext>();
// do something with context
}
}
}
Just to emphasize, again, you will need to do this in each method that needs to utilize the scoped service (your context). You cannot persist this to an ivar or something. If you're put off by the code, you should be, as this is an antipattern. If you must get a scoped service in a singleton, you have no choice, but more often than not, this is a sign of bad design. If a service needs to use scoped services, it should almost invariably be scoped itself, not singleton. There's only a few cases where you truly need a singleton lifetime, and those mostly revolve around dealing with semaphores or other state that needs to be persisted throughout the life of the application. Unless there's a very good reason to make your service a singleton, you should opt for scoped in all cases; scoped should be the default lifetime unless you have a reason to do otherwise.
Although Dependency injection: Service lifetimes documentation in ASP.NET Core says:
It's dangerous to resolve a scoped service from a singleton. It may cause the service to have incorrect state when processing subsequent requests.
But in your case this is not the issue. Actually you are not resolving the scoped service from singleton. Its just getting an instance of scoped service from singleton whenever it requires. So your code should work properly without any disposed context error!
But another potential solution can be using IHostedService. Here is the details about it:
Consuming a scoped service in a background task (IHostedService)
Looking at the name of this service - I think what you need is a custom configuration provider that loads configuration from database at startup (once only). Why don't you do something like following instead? It is a better design, more of a framework compliant approach and also something that you can build as a shared library that other people can also benefit from (or you can benefit from in multiple projects).
public class Program
{
public static void Main(string[] args)
{
CreateWebHostBuilder(args).Build().Run();
}
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.ConfigureAppConfiguration((context, config) =>
{
var builtConfig = config.Build();
var persistentConfigBuilder = new ConfigurationBuilder();
var connectionString = builtConfig["ConnectionString"];
persistentStorageBuilder.AddPersistentConfig(connectionString);
var persistentConfig = persistentConfigBuilder.Build();
config.AddConfiguration(persistentConfig);
});
}
Here - AddPersistentConfig is an extension method built as a library that looks like this.
public static class ConfigurationBuilderExtensions
{
public static IConfigurationBuilder AddPersistentConfig(this IConfigurationBuilder configurationBuilder, string connectionString)
{
return configurationBuilder.Add(new PersistentConfigurationSource(connectionString));
}
}
class PersistentConfigurationSource : IConfigurationSource
{
public string ConnectionString { get; set; }
public PersistentConfigurationSource(string connectionString)
{
ConnectionString = connectionString;
}
public IConfigurationProvider Build(IConfigurationBuilder builder)
{
return new PersistentConfigurationProvider(new DbContext(ConnectionString));
}
}
class PersistentConfigurationProvider : ConfigurationProvider
{
private readonly DbContext _context;
public PersistentConfigurationProvider(DbContext context)
{
_context = context;
}
public override void Load()
{
// Using _dbContext
// Load Configuration as valuesFromDb
// Set Data
// Data = valuesFromDb.ToDictionary<string, string>...
}
}
I have a business-type service, let's call it AccountService.
class AccountService : IAccountService {
public AccountService(ILoggingService log) {
_log = log;
}
}
As you can see, this service requires a logging service in ctor injection.
The logging service must be instantiated passing the containing service as a type:
var log = LoggingServiceFactory.GetService(typeof(AccountService));
How do I define the object graph so the logging service gets injected as a new instance, passing account service as a type?
I could do this
container.RegisterType<IAccountService, AccountService>();
container.RegisterType<ILoggingService>( /* ??? */);
...but I'm not sure what to put in there.
Do I have to do this?
container.RegisterType<IAccountService>( () => return new AccountService(LoggingServiceFactory.GetService(typeof(AccountService)));
That is OK for this example, but what if my AccountService required other injections as well? Do I have to put everything in that one lambda expression?
container.RegisterType<IAccountService>( () => return new AccountService(LoggingServiceFactory.GetService(typeof(AccountService)), container.Resolve<IOtherService>(), container.Resolve<ISecondOtherService>());
If I do that, what if the other services also require other services (including the logging service again)? Seems like this could get pretty messy pretty fast.
I guess I change things so I could inject the factory instead:
class AccountService : IAccountService {
public AccountService(LoggingServiceFactory factory) {
_log = factory.GetService(typeof(this));
}
}
and register them this way:
container.RegisterType<IAccountService, AccountService>();
container.RegisterType<LoggingServiceFactory, LoggingServiceFactory>();
...but alas there is no ILoggingServiceFactory so I will have to inject a concrete type, which makes it harder to unit test. I cannot change the logging service (it's third party and we have to use it).
Is there a better way?
You can accomplish it in multiple ways:
1) Use factory to get logging service using the reflected class type:
class AccountService : IAccountService
{
public AccountService(ILoggingServiceFactory factory)
{
_log = factory.GetService(this.GetType());
}
}
2) Use factory generic method:
class AccountService : IAccountService
{
public AccountService(ILoggingServiceFactory factory)
{
_log = factory.GetService<AccountService>();
}
}
3) Make logging service generic
class AccountService : IAccountService
{
public AccountService(ILoggingService<AccountService> log)
{
_log = log;
}
}
Depends on what IoC you are using, but most have a way to do this:
container.Register<LoggingService>();
Where you would just get a new instance of LoggingService wherever it was asked for. Most will also have ways to register singleton instances as well. Above is specifically the syntax SimpleInjector uses (it's just what I have sitting in front of me at the moment).
I cannot change the logging service (it's third party and we have to
use it).
I would not use a concrete type unless I absolutely had no choice. Even though you cannot modify it, you can always wrap it in your own concrete class that you can then tie an interface to.
This would allow you to no longer be bound to the concrete class and easily swap the logging service out for another one.
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.