Using values from AppConfig file in C# - c#

selenium = new DefaultSelenium(
ConfigurationManager.AppSettings["TestMachine"].ToString(),
4444,
ConfigurationManager.AppSettings["Browser"].ToString(),
ConfigurationManager.AppSettings["URL"].ToString()
);
Is there an efficient way to do this, instead of repeating:
ConfigurationManager.AppSettings[""].ToString()

I think a better idea is to write a wrapper class to everything that deals with configuration, especially if you write tests. A simple example might be:
public interface IConfigurationService
{
string GetValue(string key);
}
This approach will allow you to mock your configuration when you need it and reduce complexity
So you could proceed with:
public void SelTest(IConfigurationService config)
{
var selenium = new DefaultSelenium(config.GetValue("TestMachine"),
4444, config.GetValue("Browser"), config.GetValue("URL"));
}
or you could inherit your configuration from a List and reduce the typing to:
config["Browser"]

Yes, you can do
ConfigurationManager.AppSettings[""]
As it is already a string.
If you're using ConfigurationManager.AppSettings["Something"] at multiple places, you should create a static Config class, that reads your AppSettings via static properties.

You can go to the properties of the project and add Settings, then read it with:
Properties.Settings.Default.Property

I always create a config class per application which wraps access to the app/web.config file and exposes the config entries as properties. E.g. something like this:
public static class MyConfig
{
/// documentation of config entry
public static string Browser
{
get { return Read("Browser", "some default value"); }
}
/// documentation of config entry
public static int Port
{
get { return int.Parse(Read("Browser", "80")); }
}
public static string Read(string entry, string defaultValue)
{
var entry = ConfigurationManager.AppSettings[entry];
return string.IsNullOrEmpty(entry) ? defaultValue : entry;
}
}
This has several advantages:
I can define default values (e.g. if a config entry is optional/missing)
I can expose numerical/boolean config entries in the correct type (int, bool)
I can document all config entries in a central place

If you want have strong type reference, you can inherit from ConfigurationSection / ConfigurationElementCollection and ConfigurationElement.
You can specify default value to ConfigurationElement with [ConfigurationProperty("key", IsRequired = true, DefaultValue = "*^%)(#")] and validator like [StringValidator(MinLength = 3)] etc.

Write a helper function to get the parameter. You need to check if the key is actually present in the first place for good coding practices.

The only "more efficient" manner to pull from a config file is to consume the entire section and then iterate through what you desire. As you end up with looping code, it is unlikely to be more efficient than the method you have now.
One pattern to use to simplify is to create an "App settings" Singleton and load at Application Load. You essentially create a generic hashtable (dictionary, etc.) of string, string, so you can accomplish lookups more easily. But there is still the overhead of ripping through the app settings section.

You need to be a bit more creative with the class name perhaps but you could do something along the lines of:
class ConfigManager
{
public static string GetSetting(string name)
{
return ConfigurationManager.AppSettings[name].ToString();
}
}

Related

How to cache data in C# in the simplest and most elegant way?

I am writing an audiobook app in C# .NET Framework. I need to store on user disc information about audiobooks' locations and last listened audiobooks. I'm looking for the simplest and the most elegant way to do it. As easy as it can be.
What is the best (safe and proper) way to do it? How you would do it?
A very simple way is to create a custom class that holds properties for each setting you want to persist between sessions. Then create an instance of this class and set the properties with the values you want to persist.
Finally serialize the instance with a Json library transforming it in a string and save it to a location where you have read/write permissions.
To retrieve the information just do the reverse, read from the file, deserialize the string into an instance of your setting class and then use it.
So supposing a class like this:
public class ApplicationSettings
{
public string LastBookName { get; set; }
public List<string> PreviousTitles { get; set; }
}
You can have two helper methods like these one (making use of NewtonSoft.Json library NuGet here)
public void SaveSettings(ApplicationSettings aps)
{
string json = JsonConvert.SerializeObject(aps);
File.WriteAllText(#"E:\temp\savedsettings.json", json);
}
public ApplicationSettings LoadSettings()
{
string json = File.ReadAllText(#"E:\temp\savedsettings.json");
return JsonConvert.DeserializeObject<ApplicationSettings>(json);
}
Now you just need to call these two methods in the appropriate points of your code.

Best way to display Global Resource Value

I've got a Global Resource file with many values
Currently in code I call the value like this
TxtSuccess.Text = (string) GetGlobalResourceObject("GlobalResource", "msgSuccess");
But if later in the design we needed to rename variables then maintaining will be a pain.
would it be better to do something like this?
public class AppGlobalConstants
{
public string MsgSuccess{ get; private set; }
public AppGlobalConstants()
{
MsgSuccess= (string) GetGlobalResourceObject("GlobalResource", "msgSuccess");
}
}
Then if later on the team wanted to change the name of some of these global resources they could do so without having to modify any pages which used these resources.
We want to use globals as there are plans for our web application (asp.net web forms 4.5) to be available to additional countries and languages in the future.
I would rather do something like this:
public static class AppGlobalConstants
{
public static string MsgSuccess
{
get
{
return (string) GetGlobalResourceObject("GlobalResource", "msgSuccess");
}
}
}
This way, the values are static. In case the name changes, you simply modify the strings in this class. Because everything is static in this class, you could do something like this:
Console.WriteLine(AppGlobalConstants.MsgSuccess);
If you want, you could also add a set accessor to the properties. Because everything is static, there's no need to create instances of this class.

Resource file with multiple values (or access comments column via code)

Is it possible to have a resource file with entries that have multiple values.
Eg. Id like to have something like.
Resource.CanViewSection.Value
Resource.CanViewSection.Description.
My reason for this is that our database is being created with the code first approach, and we're going to need to implement very granular permissions in our application, so i'm expecting a lot of permissions & or possible repetition of items, and id like to centralize them all.
Thus in our database seeder i can do something like this:
private IEnumerable<Permission> SetupParameterPermissions()
{
var innerCollection = new List<Permission>
{
//id like to do this
this.New(Resource.CanViewSection.Value, Resource.CanViewSection.Description),
//instead of this
this.New("CanViewSection", "User can view the section")
};
return this.SetGroupId(innerCollection, PermissionGroupEnum.Parameters);
}
and in our services we can just run our access checks against the resource as well like this:
eg.
if(UserHasAccessTo(Resource.CanViewSection.Value))
{
// do something amazing
}
I've tried a few approaches, EG. adding a name to the value column of the resource & a description to the comment section, but i don't know how to programatically access the comments column of the resource file.
I realize I can achieve this effect with ENUMS as well, but i'm second guessing what the best approach would be, as we'll have a ton of permissions, and somehow the idea of a gigantic ENUM with 2 equally gigantic extensions weirds me out.
public enum SomeEnum
{
CanViewSection
}
public static class SomeEnumExtensions
{
public static string GetValue(this SomeEnum)
{
switch (me)
{
case SomeEnum.CanViewSection:
return "CanViewSection";
default:
return "Fail!";
}
}
public static string GetDescription(this SomeEnum)
{
switch (me)
{
case SomeEnum.CanViewSection:
return "YOLO!";
default:
return "Fail!";
}
}
}
I'm open to other suggestions as well?
Maybe you can try this (or something like it):
1) Create resource file with your ID's. F.e.
Resource.Code1
Resource.Code2
2) Create XML file and add it to project. It will look probably like this:
<codes>
<Code1 Value="Some value text" Description="Some description">
<Code2 Value="Some value text" Description="Some description">
</codes>
3) Create some kind of wrapper class with 2 fields - Value and Description, f.e.
public class ResourceWrapper
{
public string Value {get;set;}
public string Description{get;set;}
}
3) Then create simple static method which will get value from XML file by code from your resource file, parse it, and return ResourceWrapper as a result.
public static class ResourceHelper
{
public static ResourceWrapper GetSomeWrapper(string resourceCode);
}
Calling will look like (in your case):
ResourceWrapper wrap = ResourceHelper.GetSomeWrapper(Resource.Code1.ToString());
this.Add(new Permission(wrap.Value, wrap.Description));
Probably you would like to store a collection of already wrapped objects in some kind of cache, or else.

C# - Re-initialize static class?

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.
ConstructorInfo constructor = typeof(Settings).GetConstructor(BindingFlags.Static | BindingFlags.NonPublic,null, new Type[0], null);
constructor.Invoke(null, null);
You could use reflection:
var prop = typeof(Settings).GetField("setting1", BindingFlags.Static |
BindingFlags.Public);
prop.SetValue(null, "Bar");
string currentValue = Settings.setting1; //Bar
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
The only option comes to my mind which is requires a lot of work:
Create another AppDomain
Load assembly in the other domain
Use Remoting to get the data
If settings changed, unload the AppDomain and do steps 1 to 3 again
I would use reflection
var info = typeof(Settings)
.GetField("Settings",BindingFlags.Static|BindingFlags.Public);
info.SetValue(null, "setting4");
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);
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
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.
Change your values to properties:
public static class Settings
{
public static setting1
{
get { return SettingmanagerClass.GetSetting("setting1"); }
}
public static setting2
{
get { return SettingmanagerClass.GetSetting("setting2");
}
public static setting3
{
get { return SettingmanagerClass.GetSetting("setting3");
}
}
Also, this does not change the signature of your code.

C# plugin architecture question

I'm working on a system monitoring application similar to Nagios in C#. I have a plugin interface defined as:
public interface IPlugin
{
PluginResult Execute();
}
Each plugin, depending on its functionality, will have a variable number of arguments. As an example, a ping plugin might take a hostname, # of packets, timeout value, etc. I want the user to be able to define these arguments per service in my user interface, but obviously these arguments won't be known until the application discovers which plugins are available. I'm curious as to how others might design a plugin such that these variable arguments would be discoverable by the application.
Right now, as an example, I've got a ping plugin:
public class PingPlugin : IPlugin
{
private const string RESULT_MESSAGE = "Average ms: {0}; Packet loss: {1}";
private string _hostname;
private int _packets;
private int _timeout;
private int _warningTimeThreshold;
private int _warningLossThreshold;
private int _errorTimeThreshold;
private int _errorLossThreshold;
public PingPlugin(
string hostname,
int packets,
int timeout,
int warningTimeThreshold,
int warningLossThreshold,
int errorTimeThreshold,
int errorLossThreshold)
{
_hostname = hostname;
_packets = packets;
_timeout = timeout;
_warningTimeThreshold = warningTimeThreshold;
_warningLossThreshold = warningLossThreshold;
_errorTimeThreshold = errorTimeThreshold;
_errorLossThreshold = errorLossThreshold;
}
public PluginResult Execute()
{
// execute the plugin
}
}
I thought I might be able to discover the constructor parameters using reflection and present the user with a property grid to allow the configuration of the plugin, but I'm not sure the best way to provide a set of default values with this design. What might some alternatives be?
Have you considered looking at the Managed Extensibility Framework?
Rather than have a Plugin constructor determine the parameters, you might consider something like this:
public interface IPlugin
{
PluginResult Execute(Object parameters);
}
public class PingParameters
{
//Various parameters here, including [Description] and [DisplayName] attributes if you wish
}
public class ParametersTypeAttribute : Attribute
{
public Type Type { get; private set; }
public ParametersTypeAttribute(Type type)
{
Type = type;
}
}
[ParametersType(typeof(PingParameters))]
public class PingPlugin : IPlugin
{
public PluginResult Execute(Object parameters)
{
return Execute((PingParameters) parameters);
}
private PluginResult Execute(PingParameters parameters)
{
//Your execution code here
}
}
This gives you more flexibility for the parameters, as you can add attributes, provide setter validation and even specify designer/converter integration for the property grid. The property grid hooks up directly to the parameters object.
You can apply the [DefaultValue] attribute to the parameters.
In C# for, you can use new syntax for this: int warningLossThreshold = 30,
I voted +1 for the MEF answer too, it will solve many of your problems.
However, if you want to do it without MEF, it seems to me that you are missing some way to have the plugins tell your application via metadata, about the parameters it require.
One possible design could be this: Have an IPluginProvider interface, which your application can discover. This should have a parameterless constructor, so you can easily new up an instance. It should then have methods that return whatever metadata is needed (such as "pretty names" for the parameters, which are required, what are some sensible defaults, and so on). It should then include CreateInstance method, which takes the actual parameters as IDictionary<string,object> and returns the actual IPlugin instance.
I haven't looked at the MEF (will do now).
I had a problem almost identical to yours, I solved it with Attributes.
I have a UI which (calls BL which) uses reflection to show all the available "services" (nothing more than appropriately decorated classes).
When the user selects a "service" further attributes drive the UI. The attribute "schema" is fairly straight forward, and allows for any number of parameters with any name. By introducing constants (with the attribute definition) you can standardise common things like "name" so that your services are consistent.
All the data is then stored in a Key-Value pair table.
The great thing about this is that you can just dump new / modified "service" assemblies in teh bin dir - no extra work required. The only dependency is the attribute definitions assembly - so keep this lean.
Source code is at CodePlex if you want to "steal" some :)

Categories