1

Maybe this is not possible but I would like to validate.

I have a class and in its constructor it reads some value from the Windows Registry.

I need this valued to be readed inside the class, I could not pass it as a parameter to the class.

This is the class (a DBContext and the value readed is the Connection String)

public class VtulDb : IdentityDbContext<User>
{
    public VtulDb()
    {
        RegistryKey hklm = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64);
        RegistryKey vtulRegistryBranch = hklm.OpenSubKey(@"SOFTWARE\Tulpep\Vtul");
        string connectionString = vtulRegistryBranch.GetValue("DBConnectionString").ToString();
        Database.Connection.ConnectionString = connectionString;

    }

    public DbSet<Computer> Computers { get; set; }

}

So, the issue is that this class is instanciated from a web site, in each request. So in each request the application is reading the registry key and I dont think this is the best approach.

What would you do to read this value from the Registry just the first time the class is instanciated, and then have the string in RAM?

Ricardo Polo Jaramillo
  • 12,110
  • 13
  • 58
  • 83
  • Exactly why can't you pass this value to your class? If you could, you could store it as a session variable. (You could anyway, but that'd be messy) –  Jan 19 '14 at 00:37
  • Look into caching which would be a solution for this very problem. – Dmitriy Khaykin Jan 19 '14 at 00:38
  • Static constructor might also come in handy, if you really cannot pass the value via parameter. – Patko Jan 19 '14 at 00:40
  • I dont want to pass the parameter because this class is used by multiple projects (web apps, windows services, etc); so I dont want to make the read in multiple places (Dont repeat my self). – Ricardo Polo Jaramillo Jan 19 '14 at 00:52

2 Answers2

2

I would define a "lazy" static property (one that computes its value only after it is first accessed):

private static RegistryKey _key;
private static RegistryKey Key {
    get {
        if (_key == null) {
            // calculate the value and set _key here
        }
        return _key;
    }
}

Any instance can then access the Key property at any time instead of calculating it.

nmclean
  • 7,564
  • 2
  • 28
  • 37
1

Originally, I was kind of blinded by lazy loading, but I would use a static constructor as it is guaranteed to only run once.

class VtulDb
{
    private static readonly string CONNECTION_STRING;

    static VtulDb
    {
        // this code is only invoked on first use
        RegistryKey hklm =
            RegistryKey.OpenBaseKey(
                RegistryHive.LocalMachine, RegistryView.Registry64);
        RegistryKey branch = hklm.OpenSubKey(@"SOFTWARE\Tulpep\Vtul");

        // store string
        CONNECTION_STRING = branch.GetValue("DBConnectionString").ToString();
    }
}

This will avoid synchronization while still giving you the single, delayed invocation that is thread safe.

If you want to initialize it lazily, then I would use nmclean's approach with an actual Lazy object to guarantee thread safety, as well as to encapsulate the behavior.

private static readonly Lazy<string> CONNECTION_STRING =
    new Lazy<string>(() =>
    {
        // this code is only invoked on first use
        RegistryKey hklm =
            RegistryKey.OpenBaseKey(
                RegistryHive.LocalMachine, RegistryView.Registry64);
        RegistryKey branch = hklm.OpenSubKey(@"SOFTWARE\Tulpep\Vtul");

        return branch.GetValue("DBConnectionString").ToString();
    });

private static string ConnectionString
{
    get { return CONNECTION_STRING.Value; }
}

Lazy loading without synchronization is not thread safe and with some code that seems likely to be used in parallel, it can be unwise. Fortunately, loading the same key from the exact same source is unlikely to cause any issues, but the principle stands.

Community
  • 1
  • 1
pickypg
  • 22,034
  • 5
  • 72
  • 84