How to set a view state in a master page? - c#

I need to check whether an event is fired from the master page or not. For that i kept a count in the viewstate . This is throwing exception on page load. I'm just calling the below line in a pageload
Int32 count = Int32.Parse(this.ViewState["Count"].ToString());
Please help.

This will throw an exception in a few cases.
The key "Count" isn't in the view state yet. ViewState["Count"] will return null and the .ToString() call will throw a NullReferenceException.
The value of "Count" can't be parsed into an int, throwing a FormatException.
Things to try:
You should check the ordering of your code to make sure that you are setting the value of count before attempting to read from it.
Your code can be improved as follows:
Int32 count;
string countStr = this.ViewState["Count"];
if(!string.IsNullOrEmpty(countStr )
{
bool ok = Int32.TryParse(countStr, out count);
if(ok)
{
// Do stuff with count
}
}
You might consider using the Session rather than the ViewState to store custom data between pages.

<pagesenableSessionState="false"enableViewState="false"theme="Default" />

Make sure that ViewState["Count"] exist before performing operations to avoid exceptions.

Use this code to default the count value to 0:
Int32 count = Int32.Parse((this.ViewState["Count"] ?? "0").ToString());
This will stop you seeing an Exception if the "Count" key doesn't exist in the ViewState collection.

Related

Getting a try catch to continue 'trying' and 1st exception

I wonder if someone could give me some advice please?
I need to check for the existence of some session variables in asp.net so for instance:
try
{
zOrder = Session["epdqOrderNo"].ToString();
zAmount = Session["epdqAmount"].ToString();
zEmail = Session["epdqEmail"].ToString();
}
catch
{
}
Some or all of the session variables may exist and I'm trying to check them all but it appears that the try/catch routine goes into the catch on the first exception that it finds. So in the above example if the session variable epdqAmount doesn't exist it won't try and check for epdqEmail as its already fell out the try part. So my question is is there any way to stop this behaviour and check all of the variables or should I be using something else?
You're getting the error because Session["foo"] will return null is there is no session state variable called foo, and you can't call ToString() on a null reference.
However, you can use Convert.ToString on a null reference (in which case it will simply return string.Empty), so you could try this instead:
zOrder = Convert.ToString(Session["epdqOrderNo"]);
zAmount = Convert.ToString(Session["epdqAmount"]);
zEmail = Convert.ToString(Session["epdqEmail"]);
Using this approach, no try...catch is required because exceptions won't get thrown if any of the session variables don't exist.
You generally shouldn't try...catch in this manner, you could be potentially hiding other problems in your code. Whenever you use a try...catch try to be more specific with the exception it is you are after e.g.
try
{
}
catch (ErrorICanHandle ex)
{
}
Although in your case you would be listening for a NullReferenceException which is an indicator that you should really be checking that directly in the code as you would be effectively using exceptions to control your application flow which isn't a good idea.
As to your code, assuming all your session values are of type string then all you need is a straight cast
zOrder = (string)Session["epdqOrderNo"];
zAmount = (string)Session["epdqAmount"];
zEmail = (string)Session["epdqEmail"];
string is a special type of value type which inherits from object so this would just leave your variable as null if there is nothing in the session and not throw an exception.
try this
if(Session["MyDataSet"] == null)
{//something}
else
{//something}
In general, you'd write 3 try/catch blocks.
Couple of notes though:
You shouldn't be using a catch-all block. You might end up swallowing other important exceptions
In your particular case, there are other ways to check whether the session has those variables without throwing an exception, such as a simple null check (Session["epdqOrderNo"] == null), so I wouldn't even use try/catch here.
You can assign "" if they are null as follows using ?? as follow
zOrder = Session["epdqOrderNo"]??"";
zOrder = (string) (Session[""] ?? "");

Is it possible to continue running code from the point of failure?

Okay, I have some very simple code which I will post below. Essentially, I have a connection to a database and I want to map a subset of columns in a query to a particular class. The problem is that it is possible for these to be null.
I would like to know if it is possible if an exception is thrown at a particular line, can we resume the entire block from the next line.
So if this code below was to execute and Line 6 catches an error. Is there an elegant way to catch the exception and make the code resume running at line 7. Essentially making it as though line 6 was never executed.
private static Column MapTableToColumn(OracleDataReader reader){
Column c = new Column();
c.ColumnName = Convert.ToString(reader["COLUMN_NAME"]);
c.DataType = Convert.ToString(reader["DATA_TYPE"]);
c.DataLength = Convert.ToInt32(reader["DATA_LENGTH"]);
c.DataPrecision = Convert.ToInt32(reader["Data_Precision"]);//<---Line 6
c.DataScale = Convert.ToInt32(reader["Data_scale"]);//<--- Line 7
c.AllowDBNull = Convert.ToBoolean(reader["ALLOW_DB_NULL"]);
c.IsReadOnly = Convert.ToBoolean(reader["IS_READ_ONLY"]);
c.IsLong = Convert.ToBoolean(reader["IS_LONG"]);
c.IsKey = Convert.ToBoolean(reader["IS_KEY"]);
c.KeyType = Convert.ToString(reader["KEY_TYPE"]);
c.IsUnique = Convert.ToBoolean(reader["IS_UNIQUE"]);
c.Description = Convert.ToString(reader["DESCRIPTION"]);
return c;
}
It is important to note I am not asking for best practice, it is not something I intend to use in actual code (unless its absolutely genius). I simply want to know if this is possible and how one would go about doing this if it were.
My Research
Most of my research is proactive as opposed to reactive. I would attempt to know if it is possible for the given field to be null before it is read from. If it is, then I'd do a check to determine if the field is null and then set it to a default value. It essentially avoids the possibility of an error happening which I believe is a very good solution. I just wanted to attempt this as I know that when an exception is thrown, the most inner exception contains the line number at which it was thrown. Based on this if you put the exception inside of the class throwing the exception you should hypothetically be able to use reflection in order to continue running from its last point. I'm just not sure how you'd go about doing this. I've also considered the possibly of putting try catches around every single line which I think would be very effective; however, I think that it would be very ugly.
No, what you are asking for is not possible in C#.
Instead the proper solution to this problem is to use better parsing methods that won't throw exceptions in the first place. If your input values can be null, then use parsing methods that can accept null values.
The first thing you probably need to do is use nullable types for your int/bool fields, so that you can support null values. Next, you'll need to create your own methods for parsing your ints/bools. If your input is null, return null, if not, use int.TryParse, bool.TryParse (or as for each if your input is the proper type, just cast to object).
Then by using those methods, instead of Convert, you won't be throwing exceptions in the first place (which you shouldn't be doing here even if it could work, because exceptions are for exceptional cases, not expected control flow).
If the exception is expected then it is not exceptional. Never never never catch a null reference exception. A null reference exception is a bug. Instead, write code to avoid the bug.
You can easily write helper methods that test for null, or use methods like Int32.TryParse that can handle malformed strings.
Check for IsDBNull
SqlDataReader.IsDBNull Method
And Reader has methods for each SQL datatype
For example
SqlDataReader.GetSqlBoolean
If the data is in SQL as string (char,nchar) then first check for null and then TryParse
For example
DateTime.TryParse
And ordinal position is faster
This is a sample for a nullable Int16
Int16? ID;
ID = rdr.IsDBNull(4) ? (Int16?)null : rdr.GetInt16(4);
If you want a default
Int16 ID;
ID = rdr.IsDBNull(4) ? 0 : rdr.GetInt16(4);
You'd need a try/catch around every single variable assignment, and you'd need to initialize all your Column instance values before you tried. This would be relatively slow.
As for reflection based on the line number: I wouldn't rely on the line number because one simple, innocent change to the code will throw it off completely.
I'd check for nulls specifically. If you expect them you can't hardly call them "exceptions". The method that does that is reader.IsDBNull. It takes the column index (not the column name) so you'll need to resolve the index using reader.GetOrdinal:
if (reader.IsDBNull(reader.GetOrdinal("Data_Precision"))) {
// It's null
} else {
// It's not null
}

Do I need to initialize a variable, even if I know it will be assigned before used?

In an ASP.NET MVC app, I have code that boils down to the following:
public ActionResult Test() {
string query;
try {
query = GenerateQueryString();
}
catch (Exception ex) {
ModelState.AddModelError("error", ex.Message);
}
... do additional validation ...
if (ModelState.IsValid) {
return RedirectToAction("Success?" + query);
}
return View(); // Show validation messages
}
The above code has a compile error ... query might not be initialized.
However, the logic in the code will clearly initialize query before using it.
What is the best way to resolve this issue?
The C# compiler is looking at your code and seeing that the value of the variable is initialized in a try block and is then used later on. It can see that a logical branch of execution exists where an exception is thrown, is caught, and then the subsequent code is executed with an uninitialized value.
The simplest way to stifle the error is to assign a default value to the field. null is sufficient. As you're adding the error to the MVC model state and are checking that value later on before accessing query, you shouldn't be in a situation when the default value will matter.
You are wrong, What if GenerateQueryString throws an exception? What will be the value of Query?
You might want to do a query = "Error"; or something in your catch block. This because appareantly you want the application to run if an exception in GenerateQueryString is thrown.
EDIT
I would recommend against presetting query with a default value. This because the meaning is different. A default value is different than a certain value at a certain moment. Doing so will also prevent the compiler from warning you when you create a new code path but forget to setup a value for query
If there is exception in the call to GenerateQueryString the value of query will be undefined.
Try
string query = string.Empty;
to have a definite assignment to the variable.
Alternatively, if an exception should abort the execution, this will work too:
string query;
try {
query = GenerateQueryString();
}
catch (Exception ex) {
ModelState.AddModelError("error", ex.Message);
return View();
}
The Code is NOT clearly initialized. When the GenerateQueryString() Method throws an Exception, no value will be set. You should set the String to null and check for null before you use it, als you don't break in the catch-block.
Just because YOU know that it will be initialized (it may not be by the way in your code), the COMPILER can't know that - it's called the Halting problem.
So the compiler errs on the side of caution, something .net does a lot (e.g., no fallthrough in switch..case).
The thing here is that local variables must be initialized before read - they won't be initialized by default and this prevents from bugs programmers often makes. Some time ago I was looking for the answer to this simple situation:
bool a = true, b;
if (a == true) //here everything is OK, because a is initialized
b = true;
if(b == false) //here you get an error, I thought b == false by default
return;
I found on stackoverflow deep explanations, why it works so(couldn't find at the moment which I was reading). But you can read Absence of evidence is not evidence of absence interesting article. Maybe it will explain what I tried to say :)
Resume:
In your case you need to initialize query or set variable in catch block
Just change the declaration of query in: string query = string.Empty;.
The problem is that query is initialised in the try block, but query is declared in the block above. You must initialise it at the top level block.
It could just be that your GenerateQueryString() throws an exception. Personally, I prefer to initialize my variables, just to be on the safe side. For this reason you might just initialize to query to:
string query = String.Empty;
It doesn't hurt to be on the safe side.

Handling a null exception C#

Ok, new coder here looking for a little insight into this problem. So I have a for loop like that starts like this:
for (int i = 0; i < rowHandles.Length; i++)
{
.........code....
}
rowHandles is an int array that contains rows of data. This for loop has code that deletes the rows of data when a delete button is clicked, to be specific it is a grid tool strip Delete button and this is inside the delete button click event handler. The problem is the delete button can be clicked when there are no rows left, so rowHandles.Length is equal to null. How would I prevent this from stopping the program? Is there something I could add inside the for loop, in the for loop declaration, or outside the for loop to correct this? Maybe a try catch? How would this be structured around this specific problem/loop?
Thanks for all your help - Newbie Coder
If the problem is that rowHandles can be null then just add an explicit check for that which prevents you from executing the for statement.
if ( rowHandles != null ) {
for ( int i = 0; i < rowHandles.Length; i++ ) {
...
}
}
Another option would be to disable the delete button altogether if there are no rows to be deleted. The operation is invalid so prevent it from the start.
An important principle here is never handle an exception that you could have prevented in the first place. You should never ever ever handle a null reference exception; a null reference exception indicates a bug in your program that should be fixed, not an expected occurrance that should be trapped and ignored. Either write code that ensures that the value is not null, or detect that it is null and do not dereference it.
The problem is the delete button can be clicked when there are no rows left, so rowHandles.Length is equal to null.
This is wrong. When there are 0 elements, Length is set to 0. What is null is probably rowHandles. You need to handle that condition before you get into your loop.
If there are no rows left, rowHandles.Length will be zero not null. If you're getting rid of rowHandles after the loop, then you can just do:
if (rowHandles != null)
{
for (int i = 0; i < rowHandles.Length; i++)
{
// Code
}
}
No need for exception handling. On the other hand if you're allowing rowHandles to be changed by something else while that loop is running, that's another story.
It's not rowHandles.Length which is null, it's rowHandles itself.
A common solution would be:
if (rowHandles != null)
//Your loop here
It looks like Length is not the thin that is null. Rather it is rowHandles that is null and you are getting the null exception when trying to access the Length property.
if(rowHandles != null)
{
//for loop
}
I would suggest you try as much as possible to stick to the Single Responsibility Principle, in that you let the code do what it is intended to do, and handle the errors elsewhere.
It makes sense to me that rowHandles is used elsewhere, so you should centralize the process of checking whether or not it is null.
If you still choose to handle it in the code body you're referencing, any of the suggested solutions will work.
Change to a foreach loop:
foreach (var rowHandle in rowHandles)
{
// use rowHandle instead of rowHandles[i]
}
This way, provided the entire rowHandles object is not null (a quick null check can verify this) you will iterate over all items, and if there are no items, you wont iterate at all.

How to handle multiple errors in C#?

I have some code that reads 10 registry keys, sometimes the values are not present sometimes the keys are not present, sometimes the value isn't boolean etc etc. How should I add error handling to this, currently it is placed in one big try{} catch{} but if the second value I read fails then the rest are not read as the program jumps to catch{}, I could add a try{} catch{} for each but I'm guessing there is a better way. How would you handle this? I'm asking as I regularly come across similar problems and my own solution is to add a try{} catch{}.
Thanks for the help.
First, swallowing exceptions is generally a bad idea - could you not write a method that checks the keys etc for existance, and returns the value if one?
If that absolutely, positively isn't possible, you can refactor the code into multiple calls to a single method that (for each) does a try/catch (swallow):
SomeReturnType foo = HackyMethod(first path);
SomeReturnType bar = HackyMethod(sedond path);
SomeReturnType HackyMethod(string path)
{
try {} catch {} etc
}
Dictionary<String,String> regKeys = new Dictionary<String,String>()
{
{ "Key1", String.Empty},
{ "Key2", String.Empty},
{ "Key3", String.Empty}
};
for (int i = 0; i < regKeys.Length; i++)
{
try
{
regKeys[i].Value = ReadFromRegistry(regKeys[i].Key);
}
catch (Exception ex)
{
Console.WriteLine("Unable to read Key: " + regKeys[i].Key
+ " Exception: " + ex.Message);
}
}
How are you reading the registry values? The Registry class (Microsoft.Win32.Registry) allows you to read a registry value and return a default value that you specify if the value/name pair does not exist, like this:
object o = Microsoft.Win32.Registry.GetValue(
#"HKEY_CURRENT_USER\Software\Microsoft\Calc", "layout", "");
The last parameter here is the specified default to be returned if the value name is not found. I made it a blank string, but you can change this to whatever you like.
Refactor the code that reads the values into its own function that handles the errors how you want them to be handled.
Essentially, yes, you want to define the error-handling on each individual element, not define the error handling on the set of elements. That is, if you want each error to be caught but not cause the process to abort, you should perform error handling on each individual element, not on the group as a whole.
This depends on the severity of the errors. Is it meaningful and useful for the program to continue if some of the keys it looks up are missing or have the wrong type? Are some of the keys more important than others?
I would suggest the following:
Find all of the keys that you have to have, and put them in a single try{}, with the catch{} that reports the fatal error and initiates cleanup. Execute this block first.
Find all of the optional keys and put each of them in their own try{} block, which allows you to recover and go on to the other keys. To make this simpler, you can add a wrapper method that has the necessary try/catch block and error checking, and which takes the key name as a parameter.
EDIT: changed it all around. :P I suggested a struct or class (previously) but now i'm changing that to a simple string collection.
some pseduo code off the top of my head....
public IEnumerable<string> ReadRegistryKeys()
{
IEnumerable<string> resultList = new List<string>();
if (string.IsNullOrEmpty(read_in_key_#1())
{
resultList.Add("Failed to load key 'blah'..");
}
if (.... read in the next key .. etc.... ) ...
return resultList == null || resultList.Count <= 0 ? null : resultList;
}
You can use a StringCollection (System.Collections.Specialized?) also, if u feel like it.
#Marc's answer is the best, but if you absolutely must have a single excpetion that contains the collection of registry keys that had errors you should look at using the Data property of the exception. From the MSDN documentation on this property,
Use the System.Collections.IDictionary object returned by the Data property to store and retrieve supplementary information relevant to the exception. The information is in the form of an arbitrary number of user-defined key/value pairs. The key component of each key/value pair is typically an identifying string, whereas the value component of the pair can be any type of object.

Categories

Resources