Nested try-catches or is there a better way? - c#

In the method below there are numerous case statements (many have been removed) that make calls to Manager classes. For example, the first one calls ApplicationManager.GetByGUID. Any time a "manager" class is used, security checks occur.
Problem: I have entities that may be permitted to some of these but not all. So when this method gets run, if one of them craps out it'll throw a security exception and crash the whole report.
Someone has suggested to me that I could just throw try-catch blocks around each case but the more I read the more I feel like that might be sloppy. I admittedly am not very knowledged about exceptions...I was hoping someone could suggest a way to do this with more finesse...I need to be able to get back good data and ignore the ones that throw security exceptions....or maybe try-catches are ok in this case?
Hope that makes sense...thanks
private string GetLookup(string value, string type)
{
MySqlConnection mconn = new MySqlConnection(ConfigurationSettings.AppSettings["UnicornConnectionString_SELECT"]);
try
{
mconn.Open();
lock (reportLookups)
{
if (reportLookups.ContainsKey(type+value))
return reportLookups[type+value].ToString();
else if (reportLookups.ContainsKey(value))
return reportLookups[value].ToString();
else
{
switch (type)
{
case "ATTR_APPLICATIONNAME":
if (value != Guid.Empty.ToString())
{
reportLookups.Add(type + value, applicationManager.GetByGUID(value).Name);
}
else
{
reportLookups.Add(type + value, "Unknown");
}
mconn.Close();
return reportLookups[type + value].ToString();
break;
case "ATTR_CITYNAME":
reportLookups.Add(type + value, UMConstantProvider.UMConstantProvider.GetConstant<UMString64>(int.Parse(value), UMMetricsResourceLibrary.Enumerations.ConstantType.CITY_NAME, ref mconn));
mconn.Close();
return reportLookups[type + value].ToString();
break;
case "ATTR_COUNTRYNAME":
reportLookups.Add(type + value, UMConstantProvider.UMConstantProvider.GetConstant<UMString2>(int.Parse(value), UMMetricsResourceLibrary.Enumerations.ConstantType.COUNTRY_NAME, ref mconn));
mconn.Close();
return reportLookups[type + value].ToString();
break;
case "ATTR_ITEMDURATION":
MediaItem mi = mediaItemManager.GetMediaItemByGUID(value);
if (mi.MediaItemTypeID == (int)MediaItemType.ExternalVideo || mi.MediaItemTypeID == (int)MediaItemType.ExternalAudio)
{
reportLookups.Add(type + value, mediaItemManager.GetMediaItemByGUID(value).ExternalDuration);
mconn.Close();
return reportLookups[type + value].ToString();
}
else
{
List<BinaryAsset> bins = fileSystemManager.GetBinaryAssetsByMediaItemGuid(value, mi.DraftVersion);
var durationasset = from d in bins
where d.Duration != 0
select d.Duration;
if (durationasset.Count() > 0)
{
reportLookups.Add(type + value, durationasset.ToList()[0]);
}
else
{
reportLookups.Add(type + value, 0);
mconn.Close();
return reportLookups[type + value].ToString();
}
}
break;
}
}
return string.Empty;
}
}
finally
{
mconn.Close();
}
}

As a rule, Exceptions should indicate that something went wrong. If you're expecting exceptions during the course of a typical run through this method, you should change your APIs to allow you to avoid that exception:
if (mediaItemManager.CanAccessMediaItem(value))
{
MediaItem mi = mediaItemManager.GetMediaItemByGUID(value);
....
}
Here's a quick attempt on my part to refactor this code into something more reasonable:
private string GetLookup(string value, string type)
{
var lookupKey = type + value;
using (MySqlConnection mconn = new MySqlConnection(ConfigurationSettings.AppSettings["UnicornConnectionString_SELECT"]))
{
mconn.Open();
lock (reportLookups)
{
if (reportLookups.ContainsKey(lookupKey))
{
return reportLookups[lookupKey].ToString();
}
var value = GetLookupValue(type, value);
reportLookups[lookupKey] = value;
return value;
}
}
}
private string GetLookupValue(string type, string value)
{
switch (type)
{
case "ATTR_APPLICATIONNAME":
return value == Guid.Empty.ToString()
? "Unknown"
: applicationManager.CanGetByGUID(value)
? applicationManager.GetByGUID(value).Name
: string.Empty;
case "ATTR_CITYNAME":
return UMConstantProvider.UMConstantProvider.GetConstant<UMString64>(int.Parse(value), UMMetricsResourceLibrary.Enumerations.ConstantType.CITY_NAME, ref mconn);
case "ATTR_COUNTRYNAME":
return UMConstantProvider.UMConstantProvider.GetConstant<UMString2>(int.Parse(value), UMMetricsResourceLibrary.Enumerations.ConstantType.COUNTRY_NAME, ref mconn);
case "ATTR_ITEMDURATION":
if(mediaItemManager.CanGetMediaItemByGUID(value)) {
MediaItem mi = mediaItemManager.GetMediaItemByGUID(value);
if (mi.MediaItemTypeID == (int)MediaItemType.ExternalVideo || mi.MediaItemTypeID == (int)MediaItemType.ExternalAudio)
{
return mediaItemManager.GetMediaItemByGUID(value).ExternalDuration;
}
else
{
List<BinaryAsset> bins = fileSystemManager.GetBinaryAssetsByMediaItemGuid(value, mi.DraftVersion);
var durationasset = from d in bins
where d.Duration != 0
select d.Duration;
return durationasset.FirstOrDefault() ?? "0";
}
}
else
{
return string.Empty;
}
default:
return string.Empty;
}
}
Since I don't understand the full scope of this code, I probably oversimplified some aspects of it, but you can see that there is a lot of refactoring to be done here. In the future, you might want to run some code by http://refactormycode.com/, until you get accustomed to using best practices.

Somewhere you will have some code like:
foreach(Request req in allRequests)
{
Reply result = MakeReply(req);
WriteReply(result);
}
Turn this into:
foreach(Request req in allRequests)
{
Reply result;
try
{
result = CreateReply(req);
}
catch(SecurityException ex)
{
result = CreateReplyUnauthorized();
}
catch(Exception ex) // always the last
{
LogException(ex); // for bug hunting
// Don't show the exception to the user - that's a security risk
result = CreateReplySystemError();
}
WriteReply(result);
}
You might want to put the try-catch into a separate function as the body of your foreach loop is getting large once you catch several types of exceptions.
StriplingWarrior is also right in his reply: "Exceptions should indicate that something went wrong." Let them propagate to the main loop and show them there.

Related

Is there any more efficient way to code this?

Start:
if(fileName.Contains("$track"))
if(musicInfo.Tag.Track.ToString() != "") {
fileName.Replace("$track", musicInfo.Tag.Track.ToString());
}
else {
switch(System.Windows.Forms.MessageBox.Show("Error: Track # missing from tag info", "Error", System.Windows.Forms.MessageBoxButtons.AbortRetryIgnore, System.Windows.Forms.MessageBoxIcon.Error)) {
case System.Windows.Forms.DialogResult.Abort:
fileName = "ABORTED";
return fileName;
case System.Windows.Forms.DialogResult.Retry:
goto Start;
case System.Windows.Forms.DialogResult.Ignore:
fileName.Replace("$track", "");
}
}
I can't think of any better way to write this, there would be 7 more blocks of this code.
How about this?
public string GetFileName(string fileName)
{
if(fileName.Contains("$track") &&
!String.IsNullOrEmpty(musicInfo.Tag.Track.ToString())
{
return fileName.Replace("$track", musicInfo.Tag.Track.ToString());
}
var userOption = System.Windows.Forms.MessageBox.Show(
"Error: Track # missing from tag info", "Error",
System.Windows.Forms.MessageBoxButtons.AbortRetryIgnore,
System.Windows.Forms.MessageBoxIcon.Error)
switch(userOption)
{
case System.Windows.Forms.DialogResult.Abort:
return "ABORTED";
case System.Windows.Forms.DialogResult.Retry:
return GetFileName(fileName);
case System.Windows.Forms.DialogResult.Ignore:
return fileName.Replace("$track", "");
}
}

Cannot jump out of the finally block

I'm trying to return a value from a function. The function WcfProvider.MetalsPrices may throw an exception. I want to avoid it.
public IEnumerable<PriceOfMetal> GetPrice(int id, DateTime time)
{
bool condition = false;
DateTime timenew = time.AddDays(-1);
var allPrice = from c in db.PriceOfMetal
select c;
foreach (var i in allPrice)
{
if (i.Date.Date == timenew.Date && i.ListOfMetaL_Id==id)
{
condition = true;
}
}
try
{
if (condition == false)
{
var price = WcfProvider.MetalsPrices(id, time, time).Tables[0].AsEnumerable()
.Select(
a =>
new PriceOfMetal()
{
Date = a.Field<DateTime>("Date"),
ListOfMetaL_Id = a.Field<int>("MetalId"),
Value = a.Field<System.Double>("Price")
})
.ToList().Single();
db.PriceOfMetal.Add(price);
db.SaveChanges();
}
}
finally
{
var all = from c in db.PriceOfMetal select c;
return all;
}
I want to return the value of the block finally. Is it possible? I get an error.
You have to decide whether your function should return normally or abnormally if an exception occurs inside.
If abnormally (your caller will see the exception):
try {
// do stuff
return answer;
}
finally {
// cleanup stuff
}
If normally, you need to handle the exception:
try {
// do stuff
}
catch {
// recover stuff
}
// cleanup stuff
return answer;
You can never put a return statement in a finally block, because finally runs when there is an uncaught exception, and when your function ends (abnormally) due to uncaught exception, there is no return value.
you may need a pattern like this
try
{
return here
}
catch(Exception ex)
{
// Catch any error
// re throw if you choose,
// or you can return if you choose
return here
}
finally
{
// allways do whats here
}
You might want to read a couple of the pages around here : try-catch-finally (C# Reference)
Just to build on this a bit more, Imagine if we could return within a finally block
You could have a nasty piece of code like below, which would be confusing at best
try
{
return 10;
}
catch (Exception e)
{
return 20;
}
finally
{
return 30;
}
What would the compiler return?
I'm sorry to say this but your question is vague and hard to answer. Your code looks over complicated. Anyway it's holiday time. Maybe below will help you along. No guarantees though.
public IEnumerable<PriceOfMetal> GetPrice(int id, DateTime time)
{
DateTime timenew = time.AddDays(-1);
var allPrice = from c in db.PriceOfMetal
select c;
where c.Date.Date == timenew.Date
and c.ListOfMetal_Id == id
if (!allPrice.Any())
{
try
{
var price = WcfProvider.MetalsPrices(id, time, time).Tables[0].AsEnumerable()
.Select(a =>new PriceOfMetal
{
Date = a.Field<DateTime>("Date"),
ListOfMetaL_Id = a.Field<int>("MetalId"),
Value = a.Field<System.Double>("Price")
})
.ToList().Single();
db.PriceOfMetal.Add(price);
db.SaveChanges();
}
catch
{
// Eating exceptions like this is really poor. You should improve the design.
}
}
return db.PriceOfMetal;
}

How to fix a boolean method that returns true everytime asp.net

I designed my webpage to read a data string then display the results on labels in an html table. I am attempting to highlight the row that my database reads as a current order. My only problem is only one record is set to be active but they all highlight as if they were active. I use an array to set my data and I also use the label to get the ID I need (all is in code below). I have posted my method and where I use it in the asp page load. How can I fix my method to return correctly?
The implementing of the method in page load
if (lineData.IsCurrentOrderFind(L68.Text))
{
myTable.Rows[1].Cells[0].BgColor = "#FE2E2E";
myTable.Rows[1].Cells[1].BgColor = "#FE2E2E";
myTable.Rows[1].Cells[2].BgColor = "#FE2E2E";
myTable.Rows[1].Cells[3].BgColor = "#FE2E2E";
myTable.Rows[1].Cells[4].BgColor = "#FE2E2E";
}
Here is method that label above gets passed to
public bool IsCurrentOrderFind(string itemNumber)
{
StringBuilder sqlString = new StringBuilder();
sqlString.Append("SELECT * ");
sqlString.Append("FROM WorkOrder ");
sqlString.Append("WHERE LineNumber = " + ConfigurationManager.AppSettings["Line"] + " AND LineCompleted = 0 AND (ScaleGroup LIKE '%1' OR ScaleGroup LIKE '%3') ");
sqlString.Append(" AND CaseGenNum6 = #CaseGenNum6");
SqlDataReader reader = null;
SqlConnection dbConn = App_Code.DBHelper.getConnection();
SqlParameter[] parameters = new SqlParameter[] { new SqlParameter("#CaseGenNum6", itemNumber) };
try
{
reader = App_Code.DBHelper.executeQuery(dbConn, sqlString.ToString(), parameters);
while (reader.Read())
{
IsCurrentOrder = (reader["IsCurrentOrder"] != DBNull.Value && !string.IsNullOrEmpty(reader["IsCurrentOrder"].ToString())) ? true : false;
}
reader.Close();
reader.Dispose();
dbConn.Close();
dbConn.Dispose();
}
catch (Exception ex)
{
throw ex;
}
finally
{
if (dbConn != null)
{
try { dbConn.Close(); dbConn.Dispose(); }
catch { }
}
if (reader != null)
{
try { reader.Close(); reader.Dispose(); }
catch { }
}
}
if (IsCurrentOrder == true) I realize this is not necessary
{
return true;
}
else
{
return false;
}
}
The problem could be with this expression:
!string.IsNullOrEmpty(reader["IsCurrentOrder"].ToString())
Instead of calling ToString(), try simply casting it to a string:
!string.IsNullOrEmpty((string)reader["IsCurrentOrder"])
Possibly even better (the previous line might throw an exception if it's not really a string):
!string.IsNullOrEmpty(reader["IsCurrentOrder"] as string)
The reason being is that if the string is really null, calling ToString() will return a non-null string "null".
IsCurrentOrder is not declared locally. It seems to be declared at a higher scope. When you enter this function, nothing is initializing the variable (back to false). So, it is remaining at its last setting. Try this code instead:
public bool IsCurrentOrderFind(string itemNumber)
{
bool IsCurrentOrder = false;
//and the rest of your source code
the line
IsCurrentOrder = (reader["IsCurrentOrder"] != DBNull.Value && !string.IsNullOrEmpty(reader["IsCurrentOrder"].ToString())) ? true : false;
}
It's not actually checking the value of the field, only that it's not null or empty.
Try
if(
(reader["IsCurrentOrder"] != DBNull.Value
&&
!string.IsNullOrEmpty(reader["IsCurrentOrder"].ToString()))
)
{
IsCurrentOrder = reader["IsCurrentOrder"];
}
else
IsCurrentOrder = false;
I think there is a lot of refactoring you could do to this method though that will simplify the logic.

how to use try catch blocks in a value returning method?

I am checking the uploaded image in a registration form , where i need to use try catch blocks. here is my code:
public bool CheckFileType(string FileName)
{
string Ext = Path.GetExtension(FileName);
switch (Ext.ToLower())
{
case ".gif":
return true;
break;
case ".JPEG":
return true;
break;
case ".jpg":
return true;
break;
case ".png":
return true;
break;
case ".bmp":
return true;
break;
default:
return false;
break;
}
}
please suggest me how to use the try catch blocks here.
thanks in advance.
It would be better to do it this way,
public bool CheckFileType(string FileName)
{
bool result = false ;
try
{
string Ext = Path.GetExtension(FileName);
switch (Ext.ToLower())
{
case ".gif":
case ".JPEG":
case ".jpg":
case ".png":
case ".bmp":
result = true;
break;
}
}catch(Exception e)
{
// Log exception
}
return result;
}
There are plenty of ways that you can use exceptions in methods that return values:
Place your return statement outside the try-catch For example:
T returnValue = default(T);
try
{
// My code
}
catch
{
// Exception handling code
}
return returnValue;
Put a return statement inside your catch
try
{
// My code
}
catch
{
// Handle exception
return default(T);
}
Throw an exception
You don't have to return a value, the method simply has to end (e.g. reach a return statement or a throw statement). Depending on the exception its not always valid to return a value.
You should think carefully about when and how to catch and handle exceptions:
What might fail?
Why / how can they fail?
What should I do when they fail?
In your case:
The only statement that can fail is string Ext = Path.GetExtension(FileName);, which according to the documentation can fail if FileName contains. (Note that GetExtension doesn't return null, even if FileName is null).
This might happen if the user supplied a string that contains these invalid characters.
If this happens, I guess that we should return false, to indicate that the path is not valid (however this depends on the application).
So I'd probably handle exceptions like this:
public bool CheckFileType(string FileName)
{
string Ext;
try
{
Ext = Path.GetExtension(FileName);
}
catch (ArgumentException ex)
{
return false;
}
// Switch statement
}
Note that we only catch the exception that we are expected (ArgumentException), and we only place the try statement around the statement that we expect the exception to be thrown from.
In fact its a good idea to avoid throwing and catching exceptions wherever possible - not only do they incur a performance penalty (which can cause serious problems if this method is called inside a loop), but you might inadvertently catch and handle an exception that you didn't anticipate, masking a more serious problem.
In this case we can avoid throwing the exception entirely by checking ourselves to see if FileName contains any invalid characters:
public bool CheckFileType(string FileName)
{
if (FileName == null)
{
return false;
}
if (FileName.IndexOfAny(System.IO.Path.GetInvalidPathChars()) >= 0)
{
return false;
}
// Your original method goes here
}
As you're not actually testing the file type (only the extension of the filename), I'd first start by renaming the method. You can make an extension method to handle it:
public static bool HasImageExtension(this string fileName)
{
try
{
if (fileName == null) return false;
string[] validExtensions = new string[] { ".gif", ".jpg", ".jpeg", ".png", ".bmp" };
string extension = Path.GetExtension(fileName);
return validExtensions.Contains(extension);
}
// catch the specific exception thrown if there are
// invalid characters in the path
catch (ArgumentException ex)
{
// do whatever you need to do to handle
// the fact there are invalid chars
throw;
}
}
Which you can then call, like so:
string fileName = "testFileName.jpg";
bool hasImageExtension = fileName.HasImageExtension();
This should work:
public bool CheckFileType(string FileName)
{
try
{
string Ext = Path.GetExtension(FileName).ToLower();
string[] okExt = ".gif|.jpg|.jpeg|.png|.bmp".Split('|');
foreach(var item in okExt)
{
if(Ext == item)
return true;
}
return false;
}
catch(Exception ex)
{
throw;
}
}
And remember: never catch exceptions you're not going to handle. (or atleast re-throw them)

C# short if statement

Is there a way to do this in C# without making a new method to overload for every var type there is?
$box = !empty($toy) : $toy ? "";
The only ways I can think of to do it is either:
if (toy != null)
{
box += toy;
}
or this:
public string emptyFilter(string s) ...
public int emptyFilter(int i) ...
public bool emptyFilter(bool b) ...
public object emptyFilter(object o)
{
try
{
if (o != null)
{
return o.ToString();
}
else
{
return "";
}
}
catch (Exception ex)
{
return "exception thrown":
}
}
box += this.emptyFilter(toy);
I basically wanna check to make sure that the variable/property is set/not empty/exists/has value/etc... and return it or "" without some ridiculous about of code like above.
You could use the conditional operator (?:):
string box = (toy != null) ? toy.ToString() : "";
return variable ?? default_value;
That what you're going for? I'm a little confused considering you're showing PHP code and tag this with C#.
There's also the Nullable<T> type you can use.
How bout an extender class?
public static class ToStringExtender
{
public static String ToStringExt(this Object myObj)
{
return myObj != null ? myObj.ToString() : String.Empty;
}
}
var myobject = foo.ToStringExt()
DEMO
I'm not sure of what he wants, BUT:
string str = String.Empty;
str += true;
str += 5;
str += new object();
str += null;
This is perfectly legal. For each one adition the ToString() will be called. For null, simply nothing will be added.
The value of str at the end: True5System.Object
or,
var s = (toy?? "").ToString();
or
var s = (toy?? string.Empty).ToString();
i think there may be a slight misunderstanding about how var is used; but that's a separate topic.
maybe this below will help:
box += (toy ?? "").ToString();

Categories

Resources