9

I have a class in a web application I am working on that holds client settings. For some background, I do not own this class, and changing it is not an option. We recently added some logic to store the settings in a database, and I was tasked with creating a page to edit them, fair enough.

Here is my issue; the settings are held in a static class, and are themselves static, read-only properties. For example

public static class Settings
{
 public static readonly setting1 = SettingmanagerClass.GetSetting("setting1");
 public static readonly setting2 = SettingmanagerClass.GetSetting("setting2");
 public static readonly setting3 = SettingmanagerClass.GetSetting("setting3");
}

Now, for example, through the page I wrote, we change the value for setting2 to "Happy Variable"; it saves to the DB just fine, but now I need it to be reflected in the web app as the new value. Since it is a static readonly property of a static class, it only ever gets called when the app first wires up and can't be set manually.

Just to reiterate, I don't own the original class, so "just make the properties writeable" is not (currently) a valid option. Normally I would just talk this over with my boss and he would make a judgement call and possibly allow me to modify the other class, but I am not in a position to make that call and he is out of the office for the week.

So basically; is there any way to re-initialize a static class once a web application has started running? I just need for it to reload all of its properties as if the app was just rebuilt and started up again.

ddietle
  • 131
  • 1
  • 2
  • 6
  • You can change it with reflection or recycle the process. [Here is a thread](http://stackoverflow.com/questions/934930/can-i-change-a-private-readonly-field-in-c-sharp-using-reflection) on how to do reflection: – zeal Apr 23 '12 at 15:05
  • Just a side-note: You know that all settings(f.e. from web.config) are cached anyway? – Tim Schmelter Apr 23 '12 at 15:07
  • Is it possible to restart your IIS? [Start or Stop an Application Pool (IIS 7)](http://technet.microsoft.com/en-us/library/cc732742(v=WS.10).aspx) – Steve Apr 23 '12 at 15:09
  • Best bet is reflection or bouncing the IIS AppDomain to bin the statics. Both of which are detailed below. When your boss gets back, get approval to put a proper solution in place and get rid of the `static readonly` members. Be careful, I've seen and still see plenty of "temporary hacks" that are older than my programming career. – Adam Houldsworth Apr 23 '12 at 15:13
  • 1
    Really, anything suggested is going to be far more ugly than making them writable, I know you said that's "not (currently) a valid option", but it would be the cleanest... – James Michael Hare Apr 23 '12 at 15:14
  • This sounds like a good case for significant push back... It sounds like the Settings class is owned internally by your company. If that's the case, yell scream and do whatever is necessary to solve the problem correctly. – RQDQ Apr 23 '12 at 15:21
  • I agree that just rewriting the original class to not be read-only is likely the best method, but then again, the number of properties in the actual code is somewhere in the 300s, so I may be stuck using reflection anyway, so it may be moot. Once I am actually able to get into the app and try out everyone's suggestions, I will mark the one I ultimately used. Of course to add insult to injury, I get good responses and now the DB is down and I can't run the app. Stupid Monday. – ddietle Apr 23 '12 at 15:40

8 Answers8

16
  ConstructorInfo constructor = typeof(Settings).GetConstructor(BindingFlags.Static | BindingFlags.NonPublic,null, new Type[0], null);
  constructor.Invoke(null, null);
Nesim Razon
  • 9,684
  • 3
  • 36
  • 48
  • Thanks. I tested with OPs class to make sure than posted :) – Nesim Razon Apr 23 '12 at 15:24
  • I tired this one, and I absolutely worked, but the web app for some weird reason continued to load the original values in the pages despite the debugger showing the updated value. Very weird, and although I didn't use it this time, I will hold on to that one, it is great, even if it's purely for academic reasons (for me) right now. – ddietle Apr 23 '12 at 19:28
  • 2
    That's evil. Thought I was going to have to refactor my cache class, but black magic it is, thanks, – johnc Feb 10 '16 at 21:35
  • 1
    Thank you. This is evil, but it works. Reflection is scary – Aymen Oct 18 '19 at 09:41
5

You could use reflection:

var prop = typeof(Settings).GetField("setting1", BindingFlags.Static | 
                                                 BindingFlags.Public);
prop.SetValue(null, "Bar");
string currentValue = Settings.setting1; //Bar
BrokenGlass
  • 158,293
  • 28
  • 286
  • 335
2

If the above code is representative of the situation you're in, you won't be able to reinitialize the code unless you do something particularly hacky with reflection (this is not recommended by the way).

Edit: Oh wait - I didn't realize this was a web app. You could programmatically bounce the application:

System.Web.HttpRuntime.UnloadAppDomain
RQDQ
  • 15,461
  • 2
  • 32
  • 59
  • This could be dangerous though if other users are in the system and the session is lost due to bounce. – tsells Apr 23 '12 at 16:27
  • I actually just tested this against the scenario I laid out in the original post and it worked; no loss of session at all, just the settings reloaded. Perfect. I have tested it a few times to make sure I am not just being excited over a perceived success, but from what I can see, this is pure win, thank you! – ddietle Apr 23 '12 at 19:26
  • @ddietle - I'm glad this is working for you, but am puzzled as to how your sessions weren't destroyed. Are you storing your session out of process (e.g. in SQL Server)? – RQDQ Apr 23 '12 at 20:18
  • That is exactly how they handle it (SQL State server). I guess it was luck of the draw on my part. – ddietle Apr 30 '12 at 13:38
  • UPDATE: I was (luckily) able to get permission to handle this is the "right" way and I will be changing the properties from readonly to standard properties with get and set. *huge sigh of relief* – ddietle Apr 30 '12 at 13:48
  • BTW - You don't have to make the properties themselves writable... If you just use the approach that jp2code gave you, the problem takes care of itself. – RQDQ Apr 30 '12 at 15:26
1

The only option comes to my mind which is requires a lot of work:

  1. Create another AppDomain
  2. Load assembly in the other domain
  3. Use Remoting to get the data
  4. If settings changed, unload the AppDomain and do steps 1 to 3 again
Aliostad
  • 80,612
  • 21
  • 160
  • 208
1

I would use reflection

var info = typeof(Settings)
.GetField("Settings",BindingFlags.Static|BindingFlags.Public);
info.SetValue(null, "setting4");
Lukasz Madon
  • 14,664
  • 14
  • 64
  • 108
1
public static class Settings
{
   public static name = "";

   static Settings()
   {
    ReInitialize();
   }

   public static void ReInitialize()
   {
      name = "My name is re-initialized";
   }
}


Settings.name = "My name has changed";
// Console.WriteLine(Settings.name);
Settings.ReInitialize(); //name is "My name is re-initialized"
// Console.WriteLine(Settings.name);
Mo D Genesis
  • 5,187
  • 1
  • 21
  • 32
0

Hmm, you want to find a way to hack the class? even if it exists with reflection and something like that, it is not good way to solve this

Fast workaround I can suggest to create you own not readonly static properties, initialize with that static variables and use them everywhere

But it will be better to use Cache or Application stores instead of static variables

Hope this helps

Arsen Mkrtchyan
  • 49,896
  • 32
  • 148
  • 184
0

Old thread I know, but one thing I have done is to create an Initialize method (public static void) that sets all of the variables (they're all public static). In that method, the database calls are made and the variables of the class are set. Then in code, anytime you want to refresh the variables (i.e. anytime you call SaveChanges()), you can call Class.Initialize() and you're done.

I use this for caching common lists of lookup information that can change, and we need to keep that in sync for when the database is updated from the application.

How 'bout a Fresca
  • 2,267
  • 1
  • 15
  • 26