Simple Injector constructor parameter - c#

I'm using Simple Injector as DI Container in a project.
The problem is that I have a SqliteStorage-class, which needs the path to the db. There are multiple dbs, so I need a way to inject the path to the SqliteStorage-class at creation.
My code looks as follows (simplified without interfaces):
public class SqliteStorageOptions
{
public string Path {get; set;}
}
public class SqliteStorage
{
private readonly string _path;
public SqliteStorage(SqliteStorageOptions options)
{
_path = options.Path;
}
}
public class Db1
{
private readonly SqliteStorage _sqlite;
public Db1(SqliteStorage sqlite)
{
_sqlite = sqlite;
}
}
public class Db2
{
private readonly SqliteStorage _sqlite;
public Db1(SqliteStorage sqlite)
{
_sqlite = sqlite;
}
}
// without di
var db1 = new Db1(new SqliteStorage(new SqliteStorageOptions { Path = "db1.db" });
var db2 = new Db2(new SqliteStorage(new SqliteStorageOptions { Path = "db2.db" });
Possible Solutions:
Include SqliteStorageOptions as parameter at every method in SqliteStorage.
Provide a init-method in SqliteStorage
Create a SqliteStorageFactory with a public SqliteStorage Create(SqliteStorageOptions options)-method.
So are there any built-in solution to my problem in simple-injector or can someone provide another (better) solution?
Thanks
Edit 1:
I added some code. Db1 and Db2 both connect to sqlite-dbs (different dbs, different schema), so I wanted to extract all the sqlite-stuff to its own class SqliteStorage. So, the SqliteStorage needs to know the db path.

Which solution is best depends a bit on whether you require Auto-Wiring (automatic constructor injection) or not. Using conditional registrations (using RegisterConditional) is a good pick, but you have be aware that it is limited to determining the injection based on only its direct parent. This means that you can't make SqliteStorageOptions conditional based on its parent parent (either Db1 or Db2).
If the Db1 and Db2 classes solely depend on a SqliteStorage and don't require any other dependencies, Auto-Wiring is not a real issue and your registrations can be as simple as the following:
container.Register<Db1>(
() => new Db1(new SqliteStorage(new SqliteStorageOptions { Path = "db1.db" }));
container.Register<Db2>(
() => new Db2(new SqliteStorage(new SqliteStorageOptions { Path = "db2.db" });
In case Auto-Wiring is required inside Db1 and Db2, RegisterConditional gives a good alternative, because it enables Auto-Wiring:
container.Register<Db1>();
container.Register<Db2>();
container.RegisterConditional<SqliteStorage>(
Lifestyle.CreateRegistration(
() => new SqliteStorage(new SqliteStorageOptions { Path = "db1.db" }),
container),
c => c.Consumer.ImplementationType == typeof(Db1));
container.RegisterConditional<SqliteStorage>(
Lifestyle.CreateRegistration(
() => new SqliteStorage(new SqliteStorageOptions { Path = "db2.db" }),
container),
c => c.Consumer.ImplementationType == typeof(Db2));
In this code snippet, both Db1 and Db2 are registered 'normally', while the SqliteStorage registrations are conditionally injected based on thei consumer.
This registration is more complex, because RegisterConditonal need to be supplied with a Registration instance: there is no RegisterConditional overload that directly accepts a Func<T> factory delegate.

You can have 2 singletons one per each database connection. Let's consider an example, firstly we'll need to create an interface for your StorageService:
public interface IStorage
{
void UsePath();
}
Now let's create couple of implementations of this storage service:
public class RedisStorage: IStorage
{
private readonly string _path;
public RedisStorage(string path)
{
_path = path;
}
public void UsePath()
{
Console.WriteLine($"Here's path: {_path}");
}
}
public class SqlStorage: IStorage
{
private readonly string _path;
public SqlStorage(string path)
{
_path = path;
}
public void UsePath()
{
Console.WriteLine($"Here's path: {_path}");
}
}
Enum to differentiate between implementations of IStorage:
public class StorageSource
{
public enum StorageTypes
{
Redis=1,
Sql=2
}
}
Once we are done with that, let's create a wrapper for a storage source:
public interface IStorageWrapper
{
void DoStuff();
}
Now comes a tricky part, instantiate a storage wrapper service decorator:
public class StorageServiceWrapper: IStorageWrapper
{
private readonly Func<string, IStorage> _storage;
public StorageServiceWrapper(Func<string, IStorage> storage)
{
_storage = storage;
}
public void UsePath()
{
_storage(StorageSource.StorageTypes.Redis.ToString()).DoStuff();
//uncomment for sql
//_storage(StorageSource.StorageTypes.Sql.ToString()).DoStuff();
}
}
To achieve this, you will need to register your classes in Startup.cs as follows:
services.AddScoped<IStorageWrapper, StorageServiceWrapper>();
services.AddSingleton<RedisStorage>();
services.AddSingleton<SqlStorage>();
services.AddTransient<Func<string, IStorage>>(serviceProvider => key =>
{
switch (key)
{
case "Redis":
return serviceProvider.GetService<RedisStorage>();
default:
return serviceProvider.GetService<SqlStorage>();
}
});
This wouldn't be as beautiful as calling _storage.DoStuff();, but I believe would help you with the solution of your problem. If you still want to keep it handy, consider managing your settings file and injecting proper IOptions<> instance with a conn string you need and registering a factory method.

Related

Cannot access appsettings.json from class library

I have been following this tutorial in order to get access to my appsettings.json from my MVC project inside my class library.
geek-tutorial
I have a class as such in my class library
using dapper;
public class SqlDataAccess : IConfigManager
{
private readonly IConfiguration _configuration;
public SqlDataAccess(IConfiguration configuration)
{
this._configuration = configuration;
}
public List<T> LoadData<T>(string sql)
{
using (IDbConnection cnn = new SqlConnection(GetConnectionString()))
{
return cnn.Query<T>(sql).ToList();
}
}
public int SaveData<T>(string sql, T data)
{
using (IDbConnection cnn = new SqlConnection(GetConnectionString()))
{
return cnn.Execute(sql, data);
}
}
public string GetConnectionString(string connectionName = "URLShortnerDB")
{
return this._configuration.GetConnectionString(connectionName);
}
}
Interface:
public interface IConfigManager
{
string GetConnectionString(string connectionName);
}
I have added services.AddSingleton<IConfigManager, SqlDataAccess>(); in my mvc startup.cs
However now I would like to use my SqlDataAccess class and call methods from another class e.g:
public static class ShortUrlProcessor
{
public static ShortURLModel GetOriginalURL(string shortUrl)
{
string sql = $#"SELECT * FROM dbo.shorturl WHERE shortUrl = '{ shortUrl }'";
var originalURLEnum = SqlDataAccess.LoadData<ShortURLModel>(sql); //<--- problem
return originalURLEnum.First();
}
}
However SqlDataAccess is not instantiated, and in order to do var _sqldataaccess = SqlDataAccess() I need to pass in a parameter as defined in the constructor of the class. I do not know what to pass in? I do not have any IconfigurationManager in this ShortUrlProcessor class. I understand the reason of doing this is dependancy injection, however I am still not grasping how this all works?
You're very close, but you need to fix a few things. SqlDataAccess implements IConfigManager. Why? What's that providing? Instead, you should have it implement an interface that allows it to expose the functionality other classes depend on.
public interface ISqlDataAccess
{
List<T> LoadData<T>(string sql);
int SaveData<T>(string sql, T data);
}
Change your SqlDataAccess class to implement this interface...
public class SqlDataAccess : ISqlDataAccess
And of course, wire this up with your DI container.
services.AddTransient<ISqlDataAccess, SqlDataAccess>();
Now, any class that needs to run SQL can take a dependency on the ISqlDataAccess interface, utilizing constructor injection to get an instance of ISqlDataAccess. Since we've told the DI container to provide a SqlDataAccess instance when the ISqlDataAccess dependency is present, it will all wire up nicely in your app.
Then we have the issue with ShortUrlProcessor. You declared that class as static. That's bad, because it makes it difficult for it to use constructor injection to get its dependencies, and any other class that needs to invoke its methods has to do so directly, rather than via an abstraction. That violates the Dependency Inversion Principle of SOLID. And since we should always strive to write SOLID code because of the maintainability and testability, we need to fix that.
public class ShortUrlProcessor : IShortUrlProcessor
{
readonly ISqlDataAccess _dataAccess;
public ShortUrlProcessor(ISqlDataAccess dataAccess)
{
_dataAccess = dataAccess;
}
public ShortURLModel GetOriginalURL(string shortUrl)
{
string sql = $#"SELECT * FROM dbo.shorturl WHERE shortUrl = '{ shortUrl }'";
var originalURLEnum = _dataAccess.LoadData<ShortURLModel>(sql); //<--- problem
return originalURLEnum.First();
}
}
And we'll need an interface so other classes don't have to depend directly on ShortUrlProcessor...
public interface IShortUrlProcessor
{
ShortURLModel GetOriginalURL(string shortUrl);
}
And of course, we need to register it with our DI container.
services.AddTransient<IShortUrlProcessor, ShortUrlProcessor>();
Then any class that needs to access the functionality of ShortUrlProcessor can do so via the abstraction IShortUrlProcessor. You mentioned you have a controller calling this, so let's wire that up too.
public class MyController()
{
readonly IShortUrlProcessor _shortUrlProcessor;
public MyController(IShortUrlProcessor shortUrlProcessor)
{
_shortUrlProcessor = shortUrlProcessor;
}
public ActionResult SomeActionMethod()
{
var model = _shortUrlProcessor.GetOriginalURL("asdf");
return View(model);
}
}
We don't have to create an interface for the controller, because the controller will be called by the framework. And we don't have to wire up the controller with the DI container, because the framework handles that for us.
By doing all this, we can easily test individual methods in isolation. There's still some improvements to be made (the SQL Injection attack I mentioned in the comments needs to be fixed), but it's a good step in the right direction.

How to override config.json data using C# code?

I have followed this blog here on how to use IOC with Autofac, this is the first time hearing about IOC and autoFac.
I have downloaded the project from the link the blog provided and I have been looking through the project and I am trying to find out how the classes:
public class DatabaseSettings
{
public string ConnectionString { get; protected set; }
public int TimeoutSeconds { get; protected set; }
}
public class UserSettings
{
public string DefaultUsername { get; protected set; }
public bool ActiveByDefault { get; protected set; }
}
... gets populated without no invocation of the load function in 'Database reader'?
Is it because of (these) :
public T Load<T>() where T : class, new() => Load(typeof(T)) as T;
public T LoadSection<T>() where T : class, new() => LoadSection(typeof(T)) as T;
If it is the above codes what are they(so I can read up on how they work)?
Final Question, Is it possible to save the data back to the config.json using this approach?
The entries like
public T Load<T>() where T : class, new() => Load(typeof(T)) as T;
just mean you can use the "generic" syntax when accessing in the functions. It's a bit neater than passing in the Type as a method parameter, and also means you get a strongly-typed object back. Another way of writing the above is:
public T Load<T>() where T : class, new()
{
var type = typeof(T);
var loaded = Load(type);
return loaded as T;
}
It's a useful language feature but nothing to do with IoC itself. The IoC magic itself is mostly contained in SettingsModule. This bit:
builder.RegisterInstance(new SettingsReader(_configurationFilePath, _sectionNameSuffix))
.As<ISettingsReader>()
.SingleInstance();
tells Autofac to provide a SettingsReader (the RegisterInstance part) whenever anyone requests an ISettingsReader (the As<> bit). .SingleInstance means it will treat the SettingsReader as a singleton: only one of them will be created and that same object is passed to everywhere an ISettingsReader is requested.
This other part
var settings = Assembly.GetExecutingAssembly()
.GetTypes()
.Where(t => t.Name.EndsWith(_sectionNameSuffix, StringComparison.InvariantCulture))
.ToList();
settings.ForEach(type =>
{
builder.Register(c => c.Resolve<ISettingsReader>().LoadSection(type))
.As(type)
.SingleInstance();
});
is just a fancy way of automatically telling it what to do whenever it sees a request for DatabaseSettings or UserSettings. As per the original question, this is where the Load function is actually called. A simpler way of doing the same would just be:
builder.Register(c => c.Resolve<ISettingsReader>().LoadSection(typeof(DatabaseSettings))).As<DatabaseSettings>();
builder.Register(c => c.Resolve<ISettingsReader>().LoadSection(typeof(UserSettings))).As<UserSettings>();
You could write out the logic for those as "when a DatabaseSettings object is requested (.As), find an implementation for ISettingsReader, and then call LoadSection on that (the first part)"
Elsewhere in the Container class there's also this:
builder.RegisterType<UserService>().As<IUserService>();
which just tells Autofac what to do for an IUserService.
The result is that where in the main application method we have:
using (var scope = container.BeginLifetimeScope())
{
var userService = scope.Resolve<IUserService>();
Without that main method "knowing" anything about the concrete types it uses, we'll get a fully functioning IUserService back. Internally, Autofac will resolve the chain of dependencies required by plugging all of the constructor parameters for each type in the chain. That might look something like:
IUserService requested
Resolve UserService
Resolve IDatabase
return Database
Resolve UserSettings
Resolve ISettingsReader
return SettingsReader
Call LoadSection on ISettingsReader
return generated UserSettings object
For your Final Question - yes! However, IoC isn't necessarily what would enable you to do so. It just lets you bind together and access whichever custom classes you'd create to allow saving.
You might create a new interface like
public interface ISettingsWriter
{
void Save<T>(T settings);
}
And then for some reason you add a method which accesses that in the UserService:
public class UserService : IUserService
{
private readonly IDatabase _database;
private readonly UserSettings _userSettings;
private readonly ISettingsWriter _settingsWriter;
public UserService(IDatabase database, UserSettings userSettings, ISettingsWriter settingsWriter)
{
_database = database;
_userSettings = userSettings;
_settingsWriter = settingsWriter;
}
public void UpdateUserSettings()
{
_settingsWriter.Save(new UserSettings());
}
Using it in this way is a bit simpler than in the original sample code - I'd recommend taking this approach until you get more used to it. It means that the only other thing you'd need to add would be the registration for the settings writer, like:
builder.RegisterType<SettingsWriter>()
.As<ISettingsWriter>();

C# Dependency Injection - good practices

I have some problem with understanding how to create injectable classes…
Here is my example:
public interface IService
{
string FindSomeData()
}
Now we create a class which implements the interface:
public class FolderService : IService
{
private string _path;
public FolderService(string path)
{
_path = path;
}
public string FindSomeData()
{
//Open a folder using _path and find some data
}
}
And maybe other class:
public class DbService : IService
{
private MyConnectionClass _connection;
public DbService(MyConnectionClass connection)
{
_connection = connection;
}
public string FindSomeData()
{
//Connect to database using _connection object and find some data
}
}
Now I would like to add one of the classes to IoC Container e.x.:
if (InDebug)
SimpleIoc.Default.Register<IService, FolderService>();
else
SimpleIoc.Default.Register<IService, DbService>();
And know I have a problems.
When I want to pass this object to the constructor of some other classes:
public MyViewModel(IService service)
{
_service = service;
}
// Read folder name from TextBox on View and then call _service.FindSomeData
Then I would like to pass user selected path to the IService object (FolderService) in this case.
How should I do this in a correct way (according to SOLID and other good practiciess patterns…)?
Once I should pass string (folder path), once a MyConnectionClass (if connection to database).
What is the best way to do that kind of things?
Best regards,
Michal
You can encapsulate folder path provide/change logic into a separate provider like IFolderPathProvider and inject it into FolderService
public interface IFolderPathProvider {
string GetFolderPath();
void SetFolderPath(string);
}
public class FolderPathProvider : IFolderPathProvider {
...
}
public class FolderService : IService
{
private IFolderPathProvider _folderPathProvider;
public FolderService(IFolderPathProvider folderPathProvider)
{
_folderPathProvider = folderPathProvider;
}
public string FindSomeData()
{
string path = _folderPathProvider.GetFolderPath();
//Open a folder using path and find some data
}
}
When user changes the path, inject IFolderPathProvider to the handler and call SetFolderPath. Similarly, you can create IDbConnectionProvider. Depending on the situation, they can be combined into one DataConfigProvider but I 'm not sure what exactly do you need there; the main idea is to separate folderpath/dbconnection changing logic from the services and keep using dependency injection.

Accessing strongly typed configuration settings directly into class library in ASP.NET 5 (vNext)?

I have an ASP.NET 5 MVC 6 application. It has a Data Access library which needs a connection string to make a connection to the database.
Currently I am passing a strongly typed configuration settings class with connection string as a public property all the way up from the MVC controllers (Where it is received through DI) to the Data Access Class library.
I want to know if there is a better way for a class library to access strongly typed configuration settings using dependency injection or any other mechanism ?
Thank you.
EDIT : Code Example
This is a generic DbTransaction class which is called from the business layer.
public class DbTransactions<TEntity> where TEntity : DbEntity, new()
{
private readonly Query _query;
public DbTransactions(string connectionString)
{
_query = new Query(connectionString);
}
public TEntity GetById(long id)
{
var sqlGenerator = new SqlGenerator<TEntity>();
var sql = sqlGenerator.GetSelectByIdQuery();
var mapper = new NMapper.Mapper<TEntity>();
var cmd = _query.GetNpgsqlCommand(sql, new { id });
return mapper.GetObject(cmd);
}
}
The query class creates the connection object from the connection string that is provided to it.
I agree with #Steven that using IOptions<T> is a bad idea. You can however use the ConfigurationBinder extensions to read out a specific section of configuration into a strongly-typed POCO class. Just make sure you have this somewhere in your project.json's dependencies section:
"dependencies": {
[other dependencies],
"Microsoft.Extensions.Configuration.Binder": "1.0.0-rc1-final",
[other dependencies]
}
Just build up your configuration as normal. For example, say you had a Database.json configuration file that looked like this:
{
"Database": {
"ConnectionInfo": {
"connectionString": "myConnectionString"
}
}
}
You can build your configuration from the Startup method in Startup.cs:
public IConfiguration Configuration { get; private set; }
public Startup(IHostingEnvironment env, IApplicationEnvironment appEnv) {
IConfigurationBuilder configBuilder = new ConfigurationBuilder()
.SetBasePath(appEnv.ApplicationBasePath)
.AddJsonFile("Database.json")
.AddEnvironmentVariables()
Configuration = configBuilder.Build();
}
Now we can make a POCO class to match the "Database:ConnectionInfo" section of the JSON configuraiton file. You can match it to an interface as #janhartmann suggests, but it may or may not be necessary.
public class DatabaseConnectionInfo {
public string ConnectionString { get; set; }
}
Now, how can we get that DatabaseConnectionInfo class populated with the data from the JSON config file? One way is to use the IOptions<T> framework type, but I don't like using framework types when I can avoid them. Instead, you can get an instance like so:
DatabaseConnectionInfo dbConnInfo = Configuration
.GetSection("Database:ConnectionInfo")
.Get<DatabaseConnectionInfo>();
Now you can just register the dbConnInfo type as a singleton of the type DatabaseConnectionInfo (or as a singleton of an interface type if you prefer to have an immutable configuration settings object). Once it's registered in the IoC container, you can constructor inject it where needed:
public class DbTransactions<TEntity> where TEntity : DbEntity, new()
{
private readonly Query _query;
public DbTransactions(DatabaseConnectionInfo dbConnInfo)
{
_query = new Query(dbConnInfo.ConnectionString);
}
public TEntity GetById(long id) { ... }
}
You can let your service class depend on a an interface, e.g.:
public interface IConnectionFactory {
string ConnectionString();
}
public class MyDataAccessClass {
private readonly IConnectionFactory _connectionFactory
public MyDataAccessClass(IConnectionFactory connectionFactory) {
_connectionFactory = connectionFactory;
}
public void Whatever() {
var connectionString = _connectionFactory.ConnectionString();
}
}
And then make an implementation of it (as near to your composition root as possible):
public class SqlConnectionFactory : IConnectionFactory {
public string ConnectionString() {
return "myConnectionString";
}
}
Let the interface have the methods or properties you need.
Wire like:
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<IConnectionFactory, SqlConnectionFactory>();
}
I use a similar method to some of those listed earlier, but I think its sufficiently different to warrant another answer.
Firstly I define an interface with all the configuration that my class needs. In this case
public interface IDbTransactionsConfiguration {
string ConnectionString { get; }
}
Then I alter my class to take this configuration via constructor injection
public class DbTransactions<TEntity> where TEntity : DbEntity, new() {
public DbTransactions(IDbTransactionsConfiguration configuration) {
...
}
}
Then I define a class that handles all the configuration for my application.
public class MyApplicationConfiguration : IDbTransactionsConfiguration, ISomeOtherConfiguration, etc {
public string ConnectionString { get; }
... other configuration
}
Then I pass this class into all classes that need it using some kind of Depenendency Injection (normally Castle Windsor or AutoFac for me).
If it is too difficult to construct DbTransactions for legacy type reasons, I define a static version of MyApplicationConfiguration and access this directly.
More details on this blog post.

Using Registry in StructureMap to create a pluggable architechture

I have a web project and I want it to work with ravendb and ravendb-embedded.
So this is how I think I should solve it.
Two projects, MvcRavendb and MvcRavendb-Embedded where the two projects references two different nuget packages, one for ravendb and one for ravendb embedded.
In my core project I have an interface IDocumentStoreInitializer which has one method, IDocumentStore InitializeDocumentStore()
MvcRavenDb and MvcRavenDb-Embedded has one class like this
public class RegisterRavenDb : IDocumentStoreInitializer {
public IDocumentStore InitializeDocumentStore() {
return new DocumentStore OR EmbeddableDocumentStore();
}
}
Then I have a class that registers the concrete implementation like this
public class RavenRegistry : Registry {
public RavenRegistry() {
For<IDocumentStoreInitializer>().Use<RegisterRavenDb>();
}
}
So far so good but then I have bootstrapper that configures structuremap like this
public class Bootstrapper {
public static IContainer Initialize() {
ObjectFactory.Initialize(x =>
{
// here I want to use the registered concrete implmentaiton of IDocumentStore
var documentStore = new DocumentStore { ConnectionStringName = "RavenDB" };
documentStore.Initialize();
}
}
}
So how can I tell structuremap to use InitializeDocumentStore from the RavenRegistry class?
Maybe I have missed something or I'm taking the wrong approach here
Just use the EmbeddableDocumentStore instance, using the connection string, you can control whatever it will be embedded or server/client.
This should do as you wish. In OnCreation the ConnectionString can be set, too.
ObjectFactory.Initialize(x =>
{
// here I want to use the registered concrete implmentaiton of IDocumentStore
x.Scan(scan =>
{
scan.TheCallingAssembly();
scan.AssembliesFromApplicationBaseDirectory();
scan.LookForRegistries();
});
x.For<IDocumentStore>().Use(c =>
c.GetInstance<IDocumentStoreInitializer>().
InitializeDocumentStore()).OnCreation<IDocumentStore>(z => z.Initialize());
});

Categories