Handling dependency injection when seeding the database

.net asp.net-mvc c# dapper dependency-injection

Question

I need to seed the application database with default users. I don't use Entity Framework in this project, I've decided to use Dapper instead.

Simplest thing that I can do is to have a simple class like DatabaseConfig (or AccountsConfig) with a Seed() static method:

public class DatabaseConfig {

    public static void Seed() {

        using(var conn = new SqlConnection()) {

            conn.ConnectionString = GetConnectionString();
            conn.Open();

            var query = "insert into users (username, [password]) values (@username, @password)";

            var queryParams = new {
                username = "Admin",
                password = HashedPassword.CreateHash("DefaultSecretKey") 
            }

            conn.Execute(query, queryParams);
        }

    }

    private static string GetConnectionString() {
        return ConfigurationManager.ConnectionStrings["appDb"].ConnectionString;
    }
}

and then to call it in the Global.asax:

DatabaseConfig.Seed();

I have two dependencies here:

  1. I call a ConfigurationManager to get a connection string. I don't know if this is a bad approach. For other services I use in the application I pass the connection strings as a constructor parameters in the SimpleInjector initializer:

    private static void InitializeContainer(Container container) {
    
        var appDbConnString = ConfigurationManager.ConnectionStrings["appDb"].ConnectionString;
        container.RegisterSingleton<IUsersRepository>(new UsersRepository(appDbConnString));
    
    }
    
  2. The other dependency is HashedPassword class. I don't expect it to change with time but still this is a dependency. Should I resolve it? How do I resolve it?

Accepted Answer

I call a ConfigurationManager to get a connection string. I don't know if this is a bad approach.

In general, you should only read the config file at application startup, and preferably only within the startup path of the application. This allows the reading of the config file to be centralized in one single place and it allows the application to fail fast in case some configuration value is missing.

You seem to follow that practice, so I would say what you're doing is fine.

The other dependency is HashedPassword class. I don't expect it to change with time but still this is a dependency. Should I resolve it?

Since this Seed method seems to be part of your composition root, it's okay to have strong dependencies on other classes in your system. Or let me put it differently, if the use of this dependency doesn't cause trouble in any way (because you don't want to test the code in isolation, or want to replace, wrap, decorator or intercept the code inside that class), I would say this is okay.

If however you want this HashesPassword class to be injectable, you will have to make it an instance class. In that case you should probably hide it behind an abstraction (like IHashPashword) and pass it as parameter into the Seed() method, or you should promote the DatabaseConfig to a non-static class with non-static methods and inject the IHashPashword abstraction into its constructor. This allows you to resolve DatabaseConfig from the container.


Popular Answer

you are accessing HashedPassword and ConfigurationManager in static way, this means you need to change them to non static classes in order to dependency inject them. that can be done by changing them (which may be not possible is they are not your classes) or to wrap them in an instance class.



Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Is this KB legal? Yes, learn why
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Is this KB legal? Yes, learn why