Accessing Constants Static Class That References App Settings Config File - c#

I have a class called LocalConstants....
public static class LocalConstants {
public static string DM_PATH = ConfigurationManager.AppSettings["DMQueue"];
public static string PROJECT_PATH = ConfigurationManager.AppSettings["MSQueue"];
}
When trying to access this class in my main program I am getting a null reference exception. Anything from ConfigurationManager.AppSettings[ is always null. But if I write
//The value is returned fine
string bo=ConfigurationManager.AppSettings["MSQueue"];
this compiles fine but is always null and throws a NullRefexception
string moomoo = LocalConstants.PROJECT_PATH;
The exception is
The type initializer for 'TestCodeOutOnSide.LocalConstants' threw an exception.
The innerException is the basic
Object reference not set to an instance of an object.
Even if I change the PROJECT_PATH to
public static readonly string PROJECT_PATH = #"FORMATNAME:DIRECT=OS:serus-nickl\RMQDEV";
I get the same exception
Any ideas?

To begin with, if you are doing this to provide some sort of performance benefit then you should know that these are cached. See ConfigurationManager.AppSettings Caching, to remove any.
Second the issue is most likely that Static field initialization does not work how you expect it to. So your code as written provides no guarantee of that ConfigurationManager.AppSettings has been run. From the linked article sample code:
might produce either the output:
Init A
Init B
1 1
or the output:
Init B
Init A
1 1
[EDIT per OP comment]
There must be something else involved as:
public static class LocalConstants
{
public static string DM_PATH = "DMQueue";
public static string PROJECT_PATH = "MSQueue";
}
class Program
{
static void Main(string[] args)
{
string moomoo = LocalConstants.PROJECT_PATH;
Console.WriteLine(moomoo);
}
}
works for me.
[Edit 2 - Fro those who come after]
It looks like The type initializer for ‘SomeClass’ threw an exception can be a case where
But when it's called by the WPF designer, the "application" is Visual Studio, which (presumably) doesn't have the appropriate connection strings in its .config file;
The fix for that author was:
moving the instantiation of my Entity Data Model into a property

Why don't try something like:
public static string ProjectPath
{
get
{
return ConfigurationManager.AppSettings["MSQueue"];
}
}

I called this
public static string Environment = AppEnvironmentVariable.ToUpper() != "PROD" ? "***FROM " + AppEnvironmentVariable.ToUpper() + "** " : "";
Before this
public static string AppEnvironmentVariable = "DEV";
In the LocalConstants file which broke it because of what Josh said about Static field initialization

You could try making them readonly
public static readonly string PROJECT_PATH = ConfigurationManager.AppSettings["MSQueue"];
readonly fields can be lazy-loaded

Related

Why can't my declared non static field be accessed inside static method?

Hi I am new to C# and I am aware on a surface level that I cannot use non static fields inside static methods. But I have a situation that I am trying to understand conceptually.
Check out this code snippet:
class CIMConversionHelper
{
private static Logger Logger = LogManager.GetCurrentClassLogger();
private readonly ProcessingEndTimeData _procEndTimeData = new ProcessingEndTimeData();
public static TDX2KlarfResult HandleConversion(TDXProcessItem item, string fileName)
{
TDX2KlarfResult result = new TDX2KlarfResult();
result.success = true;
XmlDocument doc = new XmlDocument();
try
{
doc.Load(fileName);
}
catch (Exception ex)
{
result.success = false;
Logger.Error(ex, "XML Parsing Error: ");
return result;
}
_procEndTimeData.ToolType = toolType;
_procEndTimeData.Lot = input.cimToolContext.LOT;
_procEndTimeData.WaferScribe = input.cimWaferContainer.waferContext.WAFER_SCRIBE;
_procEndTimeData.Processing_End_Time = input.cimToolContext.PROCESSING_END_TIME;
}
public static TDX2KlarfResult Convert(TDXProcessItem item, string fileName)
{
TDX2KlarfResult result = new TDX2KlarfResult();
result.success = true;
try
{
result = CIMConversionHelper.HandleConversion(item, fileName);
}
catch (Exception ex)
{
// Failed to Parse the xml Not good mark nonrecoverable error and return.
result.errorType = "Non-Recoverable";
result.success = false;
Logger.Error(ex, "Unknown Error: ");
return result;
}
if (result.success)
{
//DBHelper.AddProcessingEndTimeToDB();
}
return result;
}
}
This is a very abridged snippet but one that captures my question. I have created an object reference as field for ProcessingEndTimeData called _procEndTimeData.
Why then is it telling me in Visual Studio that:
"an object reference is required for the non-static field, method, or property CIMConversionHelper._procEndTimeData?
I thought I should be able to assign values to the declared object "_procEndTimeData" in the 4th line inside the static function "HandleConversion"
Can someone explain to me why this reference is not enough? and why I would then have to create yet another ProcessingEndTimeData object inside the static function HandleCOnversion?
I know I can just toggle _procEndTimeData to be static but why do I need to do this if I have already created a reference in the field level?
Think about the memory of the equipment.
When you create an object, memory is reserved for it. Imagine, that because of its properties (int, char...) it occupies 32 bytes. If you create 10 objects, you will have 320 bytes occupied in memory for your objects.
But when you use "static", those properties are created only once for the class. Not once for each object you create.
So, your 10 objects can access their own properties (int, char...) and also the static ones. But from a "static" method you cannot access the properties of an object of that class because you don't have the instance of it.
A very simple example: You have a User class with the Name property. You add a static variable of type integer: static int count. That variable will be used to record the number of users you create.
In the constructor of the user you can do count++ because the instances of the class can access to the properties of the class. But if you create a static method:
public static void DoSomething()
{
// You can show a message with the number of users
MessageBox.Show(count.ToString());
// But you CAN'T access to a "Name" because this method is not
// a method of one concrete user. It's a general method, for all users
}
If you invoke DoSomething and you are created two users, "Tom" and "Jerry", in DoSomething you don't know any user.
You have 2 choices to make this work. Not sure which one applies. My guess is the first one I will show
private readonly ProcessingEndTimeData _procEndTimeData = new ProcessingEndTimeData();
change to
static private readonly ProcessingEndTimeData _procEndTimeData = new ProcessingEndTimeData();
This says that this field is also static, ie belongs to the class, not to instances of the CIMConversionHelper class.
The alternative, which I dont think you want it to create an instance of CIMConversionHelper in that method. Which as I said is probably not what you want.
If your intent is that this class (CIMConversionHelper) is all static, ie you will never create an instance of it then mark the class itself static and the compiler will ensure that you dont accidentally create non static members. ie
static class CIMConversionHelper{....}
Why is this so?
You say you have created a reference here
private readonly ProcessingEndTimeData _procEndTimeData = new ProcessingEndTimeData();
YOu have not created it yet.
You need to understand the difference between static and instance functions and fields.
Lets have an example. We have a class Thingy. It includes a factory method that makes thingy instances and keeps a count of how many it has made
public class Thingy{
static s_thingyCount = 0;
string _froop;
public static CreateThingy(){
var thing = new Thingy();
......
s_thingyCount++;
thing._froop = "hello";
return thing;
}
public void Twang(int froop){
......
}
public int Oink(string pling){
......
_froop = pling;
}
}
we can go
var t1 = Thingy.CreateThingy();
t1.Oink("Ole");
The CreateThingy does not operate on instances of the class, it operates on the class itself. The count variable does not belong to an instance, it belongs to the class itself. Note that in the create method we have to say
thing._froop = "hello";
ie which objects _froop we want to set (the one we are in the process of making).
var t1 = Thingy.CreateThingy();
now we have an instance of Thingy we can call methods on it
t1.Oink("Ole");
Look in that method
public int Oink(string pling){
......
_froop = pling;
}
we dont say which froop to set, we are manipulating an instance of the class.
We cannot do
Thingy.Oink("xxx");
Which THingy would be updates? Nor can we do
Thingy._froop = "fff";
for the same reason
but we can do
var count = Thingy.s_thingyCount;
How does this map to your class. THis method is static. It is like CreateThingy, it does not have an instance to operate on.
public static TDX2KlarfResult HandleConversion(TDXProcessItem item, string fileName)
but you do this
_procEndTimeData.ToolType = toolType;
with this field
private readonly ProcessingEndTimeData _procEndTimeData = new ProcessingEndTimeData();
this is just like doing
_froop = "hello"
in CreateThingy
_proceEndTimeData only exists in instances on your class.
It will be create when you do
new CIMConversionHelper();
But I suspect thats not what youo want to do. So you need to make _proceEndTimeData static, just like s_thingyCount
If I'm understanding it correctly, you answered yourself: "I am aware on a surface level that I cannot use non static fields inside static methods", and then you have declared a non static variable inside your method:
private readonly ProcessingEndTimeData _procEndTimeData
It should be static, apart than readonly if you want.
The reason for this has to do with object oriented programming. To access a static method from a class you don't need to instantiate it. This is why you can't reference class-level non static variables inside a static method from that class. Hope that made it a little clearer.
I know I can just toggle _procEndTimeData to be static but why do I need to do this if I have already created a reference in the field level?
You created no such thing, your _procEndTimeData is a field in every instance of CIMConversionHelper, of which you have none.
If it helps you visualize the problem better, imagine what would happen if your expectation was reality and you had the following code:
CIMConversionHelper h1 = new(), h2 = new();
CIMConversionHelper.Convert(.....whatever....);
Would it change h1._procEndTimeData? h2._procEndTimeData? It has to pick one, right? So which one does it pick?
No. static methods can only use static fields, period.

How can I add a default constructor and have it call another constructor and use the default values?

I have this code:
public class NewFrame
{
public NewFrame(string iconSource = Const.Car,
string iconColor = Const.Red)
{
When I try and use it then it's telling me I am missing a default constructor. How can I add one of these and still make the code use the default values for iconBackgroundColor and IconSource? I thought that adding in those defaults with the = Const. would make it work but it seems like it doesn't think my constructor is a default (with no params).
You just have to add another empty overload and call the required constructor with defaults. See below:
public class NewFrame
{
public NewFrame() : this(Const.Car, Const.Red){
}
public NewFrame(string iconSource,
string iconColor)
{
...
}
}
By having two optional parameters, you don't actually create 4 different constructor declarations under the hood (one with both parameters, one with the first parameter, one with the second parameter, and one with neither). There is still only one constructor, with two parameters. It's just that C# recognises that the parameters are optional, and has syntactic sugar to let you omit them when you call the constructor.
However, if you use reflection to create an instance of your class (probably whatever the thing that requires a default constructor is doing), and you attempt to invoke the parameterless constructor, it won't find one, because there is no syntactic sugar in reflection.
Here is an example:
class MainClass
{
public static void Main(string[] args)
{
Type t = typeof(MainClass);
object o = Activator.CreateInstance(t, 1);
Console.WriteLine(o);
}
public MainClass(int a = 10)
{
}
}
If you use typeof(MainClass).GetConstructors(), it will tell you that there is only one.
To actually declare a default constructor, you can do:
public class NewFrame
{
public NewFrame(string iconSource = Const.Car,
string iconColor = Const.Red)
{
...
}
public NewFrame() : this(Const.Car, Const.Red) { }
}
For what it's worth, when I do something like this, I take the route that #VyacheslavBenedichuk's answer is showing.
I'm not sure what your complaint is. This code compiles for me:
public class TestConstructor
{
public TestConstructor(string what = Const.Car, string color = Const.Red)
{
}
public static void Test()
{
var tc = new TestConstructor();
}
public class Const
{
public const string Car = "car";
public const string Red = "red";
}
}
What do your definitions of Const.Car and Const.Red look like? Where are you seeing the error?
But, if you use something that requires a default constructor, then this will not work. For example, this will fail at runtime:
var tc2 = Activator.CreateInstance(typeof(TestConstructor));
Please, when you are reporting an error, describe it exactly - in particular say whether it's a runtime or a compile-time error, the exact wording of the error, and the context in which the error occurs. In this case (the call to CreateInstance) will result in a System.MissingMethodException: 'No parameterless constructor defined for this object.'
In this case, you need to follow #VyacheslavBenedichuk's advice

cannot access property within the same class

I'm having trouble understanding why a part of my code can't resolve another part.
I have this class that contains two properties. The second property relies on the first, but it keeps throwing this error:
cannot resolve symbol 'yearlyEmployees'
public class Financials
{
public static IEnumerable<SalaryEntity> yearlyEmployees = FactoryManagement(12345);
//cannot resolve symbol 'yearlyEmployees'
public static IEnumerable<CompanyEntity> YearlyGroup(IList<yearlyEmployees> allExempt)
{
}
}
I'm sure there's an easy answer, but I just can't find it.
Thanks!
yearlyEmployees is a variable name, not a class name. Try:
public static IEnumerable<CompanyEntity> YearlyGroup(IList<SalaryEntity> allExempt)
You must use the type SalaryEntity as item for your list.
public static IEnumerable<CompanyEntity> YearlyGroup(IList<SalaryEntity> allExempt) {}
That is because you don't have a type of yearlyEmplyee - that is your variable.
Instead:
public static IEnumerable<CompanyEntity> YearlyGroup(IList<SalaryEntity> allExempt)
{ }
And then just pass a collection of SalaryEntity to the function. If you always want to process only yearlyEmployees (which I don't think is the case but not sure) then just call it from within the method `Financials.yearlyEmployees'.

Read-only Violation Not Handled as Expected

Given the code below, I'm very surprised that an exception is not thrown and would like to know why not. I have a class that has a readonly field that is initialized in the constructor. I then use reflection to get the FieldInfo and call the SetValue method. This results in the otherwise read-only field being writable. My question is why is this allowed to happen?
If this is allowed to happen, that means the readonly keyword is purely for compile-time checking and has very little bearing on the actual instruction generation, I would assume. Thanks in advance for your insights.
public class SomeType
{
public readonly int RONumber;
public int LocalMember;
public SomeType()
{
RONumber = 32;
}
}
class Program
{
static void Main(string[] args)
{
var st = new SomeType
{
LocalMember = 8
};
var ron1 = st.RONumber;
var type = typeof(SomeType);
var ronField = type.GetField("RONumber");
ronField.SetValue(st, 405);
var ron2 = st.RONumber; // ron2 is 405!
}
}
A readonly field tells the compiler to prevent you from writing code that will mutate that value. If you use reflection you can bypass those checks and do basically whatever you want.
Note that is different from a const field, which is a compile time constant.

Static class remaining in memory.....how best to achieve this

I've created a very simple helper class that I can use in my ASP.Net pages. The idea is that it is supposed to be a very simple way to log an on-page error or success (not a form validation error) and then display it to the user.
In my public helper class I have a class which has certain properties, as shown below:
public class UserMessage
{
public UserMessage()
{
Messages = new Dictionary<string, string>();
}
public string SummaryMessage;
public Dictionary<string, string> Messages;
public bool ShowMessages;
public bool ShowAsError;
}
I then have a variable which is used to store an instance of the UserMessage class, like so:
private static UserMessage _userMessage { get; set; }
I then have two public static methods, one to log a message, the other to display all the messages, like so:
public static void LogSummary(string summaryMessage, bool showIndividualMessages, bool showAsError)
{
_userMessage = new UserMessage();
_userMessage.SummaryMessage = summaryMessage;
_userMessage.ShowMessages = showIndividualMessages;
_userMessage.ShowAsError = showAsError;
}
public static string DisplayUserMessages()
{
if (_userMessage == null)
return string.Empty;
StringBuilder messageString = new StringBuilder();
messageString.AppendFormat("\n");
messageString.AppendLine(string.Format("<div class=\"messageSummary {0}\">", (_userMessage.ShowAsError) ? "invalid" : "valid"));
messageString.AppendLine(string.Format("<h3>{0}</h3>", _userMessage.SummaryMessage));
messageString.AppendLine("</div>");
return messageString.ToString();
}
The problem I have is that the _userMessage variable has to be a static variable, otherwise I get the error message "An object reference is required for the non-static field.......". The problem with the variable being static is that is stays in memory, so if the user receives an error message and then visits another page - the error message is still displayed!
I'm sure this is because I missed OOP 101, but how should I correct this?
Do not use static variable to keep messages per user! ASP.NET application is multi-threaded and using static variable is not thread safe. Store them in Session.
public static void LogSummary(string summaryMessage, ...)
{
HttpContext.Current.Session["userMessages"] = new UserMessage();
...
}
public static string DisplayUserMessages()
{
// get the value from session
var userMessage = (UserMessage)HttpContext.Current.Session["userMessages"];
// do the work
// do the clean up
HttpContext.Current.Session["userMessages"] = null;
// the messages will not be displayed on next request
}
Each request is handled by different thread, so the users will overwrite the _userMessage field and you cannot guarantee that messages for the current user will be displayed.
Pass the reference as an argument to the static member, or have it return a new instance like below:
public static UserMessage LogSummary(string summaryMessage, bool showIndividualMessages, bool showAsError)
{
var userMessage = new UserMessage();
userMessage.SummaryMessage = summaryMessage;
userMessage.ShowMessages = showIndividualMessages;
userMessage.ShowAsError = showAsError;
return userMessage;
}
In my opinion you try to face a problem with a wrong approach. Considering that you're developing service side component (ASP.NET) and you have to have perfect isolation between every user visits your site, I personally don't see any reason why do not use a backend database for error message holding where every record can be associated to a single user unique ID.
The simple ACID supported database (in practice almost any on the market) is a perfect fit in this case.
In this way you can pull from the database the message you need at the moment you need, and don't need more worry about any type of memory issue (at least from the perspective of this question)
Hope this helps.
Static variable will be shared within AppDomain - i.e. concurrent requests will share the same instance and hence your approach is problematic.
You should consider putting your user-message instance into the current HttpContext to get per request semantics as needed by your use case. For example,
public class UserMessage
{
public static UserMessage Current
{
get { return HttpContext.Current.Items["_User_Message"] as UserMessage; }
}
public static void LogSummary(string summaryMessage, bool showIndividualMessages, bool showAsError)
{
var userMessage = new UserMessage();
userMessage.SummaryMessage = summaryMessage;
...
HttpContext.Current.Items["_User_Message"] = userMessage;
}
public static string DisplayUserMessages()
{
var userMessage = UserMessage.Current;
if (userMessage == null ) return string.Empty;
...
}
// rest of the code
...
}
I would probably also make UserMessage constructor private.

Categories