I have implemented several "stock" Microsoft Code Analysis rules. However they were lacking in one area that they didn't have detection in a catch to see if logging was implemented.
So my test project has these two methods. I would expect to see one of them raise my custom error while the other passes.
public void CatchTestNoLogging()
{
try
{ string A = "adsf"; }
catch (Exception ex)
{ throw; }
}
public void CatchTestLogging()
{
try
{ string A = "adsf"; }
catch (Exception ex)
{
log.Error("Test Error");
throw;
}
}
My custom rule is able to detect if there is a catch but I can't see how I detect if the Logging is used?
This is a SNIP of the custom rule:
if (iList[i].OpCode == OpCode._Catch)
{
isCatchExists = true; //this gets hit as I want
//so the question is what can I do to detect if logging is implemented in the catch?
}
Just a quick pointer on how I access would be great.
Thank You
Well,
It's not perfect but here is what I got. I knew / had a framework from Google of how to look for a catch block...Well that's half what I needed so I started there and that code looked like this:
if (item.OpCode == OpCode._Catch)
{
isCatchExists = true;
}
So I stepped through in the debugger to see what a catch with logging (log4net) looked like compared to no logging and see if something tangible jumps out. Well I did find this:
Exploring the log4net object I see this:
So I didn't see a way to determine that the log.error was in the catch but I can determine if there is one present. SO I wrote this:
public override ProblemCollection Check(Member member)
{
Method method = member as Method;
bool isCatchExists = false;
bool isLogError = false;
if(method != null)
{
//Get all the instrections of the method.
InstructionCollection iList = method.Instructions;
foreach (Instruction item in iList)
{
#region Check For Catch
if (item.OpCode == OpCode._Catch)
{
isCatchExists = true;
}
#endregion
#region Check for Error Logging (log4net)
if (item.Value != null)
{
if (item.OpCode == OpCode.Callvirt && item.Value.ToString() == "log4net.ILog.Error")
{
isLogError = true;
}
}
#endregion
}
if (isCatchExists && !isLogError)
{
Problems.Add(new Problem(this.GetNamedResolution("AddLogging", member.FullName)));
}
}
return this.Problems;
}
This works but with some caveats.
This is hardcoded to log4net.
a. I don't like the hard code but I would likely add a different rule for other logging methodologies anyway.
I can't determine if the log.error is IN the catch block.
a. So a person could have a log.error in the try block and my rule would pass it.
Related
The MessageBox.Show call below shows "Inner". Is this a bug?
private void Throw()
{
Invoke(new Action(() =>
{
throw new Exception("Outer", new Exception("Inner"));
}));
}
private void button1_Click(object sender, EventArgs e)
{
try
{
Throw();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message); // Shows "Inner"
}
}
I had a look at the reference source for System.Windows.Forms.Control, and the code that deals with Invoke looks like this:
try {
InvokeMarshaledCallback(current);
}
catch (Exception t) {
current.exception = t.GetBaseException();
}
GetBaseException:
public virtual Exception GetBaseException()
{
Exception inner = InnerException;
Exception back = this;
while (inner != null) {
back = inner;
inner = inner.InnerException;
}
return back;
}
So apparently it's like this by design. The comments in the source offer no explanation as to why they do this.
EDIT: Some site that is now gone claims this comment came from a guy at Microsoft:
Based on the winform comfirmation in the record, our analysis is
correct of the root cause and this behavior is intended. The reason was to
prevent the user from seeing too much of the Windows.Forms internal mechanisms.
This is because the winform's default error dialog also leverages Application.ThreadException to show the exception details. .Net Winform
team trims the other exceptions information so that the default error
dialog will not display all the details to the end user.
Also, some MSFTs have sugguested to change this behavior. However, .Net
Winform team thinks that changing the exception to throw is a breaking
change and for this reason WinForms will keep sending the innermost exception to the Application.ThreadException handler.
The OP doesn't seem to be interested in a work-around. Anyhow, this is mine:
public static object InvokeCorrectly(this Control control, Delegate method, params object[] args) {
Exception failure = null;
var result = control.Invoke(new Func<object>(() => {
try {
return method.DynamicInvoke(args);
} catch (TargetInvocationException ex) {
failure = ex.InnerException;
return default;
}
}));
if (failure != null) {
throw failure;
}
return result;
}
In the below code i got an error "Object reference not set to an instance of an object" in the line of the 'if' condition. Can any one help me with what is wrong with my code.
public string MemberLogOut()
{
string ret = string.Empty;
try
{
if (HttpContext.Current.Session.Count > 0)
HttpContext.Current.Session.Clear();
ret="1";
}
catch (SqlException ex)
{
throw new Exception(ex.Message);
ret="2";
}
return ret;
}
As long as you have System.Web referenced in your using statements, then you should be able to use this:
if (Session != null) {Session.Clear();}
Or
if (Session != null) {Session.Abandon();}
Im not sure why you would you return a string which holds an integer though. A boolean value would make more sense, but you really shouldn't need anything in this context.
Also, your exception handler is attempting to catch a sqlexception, which could also be a source of an object reference error, as you don't appear to have any SQL objects in this function.
I'd probably do this following:
protected bool MemberLogOut()
{
try {
if (Session != null) {Session.Abandon();}
//do any logging and additional cleanup here
return true;
} catch {
return false;
}
}
Edit: if you are in fact calling from outside of your web project, you can just pass the current httpcontext to the following method:
protected bool MemberLogOut(HttpContext context)
{
try {
if (context != null && context.Session != null) {
context.Session.Abandon();
}
//do any logging and additional cleanup here
return true;
} catch (Exception ex) {
//log here if necessary
return false;
}
}
Can any one help me with what is wrong with my code
I guess that you are running this code outside an ASP.NET application. HttpContext.Current exists only inside the context of a web application. If you ever attempt to run this code outside (for example in a console, desktop, unit test, ...) it's never gonna work.
So if this is some sort of code that is in a class library intended to be reused across different applications you will have to remove the dependency on the HttpContext from it.
Side remark: your if condition seems kinda useless as you are doing exactly the same thing in the else as well as in the if -> clearing the session.
try that code
public string MemberLogOut()
{
string ret = string.Empty;
try
{
if (HttpContext.Current.Session!=null)
{HttpContext.Current.Session.Clear();}
}
catch (SqlException ex)
{
throw new Exception(ex.Message);
}
return "1";
}
I am wondering can try..catch force execution to go into the catch and run code in there?
here example code:
try {
if (AnyConditionTrue) {
// run some code
}
else {
// go catch
}
} catch (Exception) {
// run some code here...
}
try{
if (AnyConditionTrue){
//run some code
}
else{
throw new Exception();
}
}
catch(){
//run some code here...
}
But like Yuck has stated, I wouldn't recommend this. You should take a step back at your design and what you're looking to accomplish. There's a better way to do it (i.e. with normal conditional flow, instead of exception handling).
Rather than throwing an Exception in the else, I would recommend extracting the code from your catch into a method and call that from your else
try
{
if (AnyConditionTrue)
{
MethodWhenTrue();
}
else
{
HandleError();
}
}
catch(Exception ex)
{
HandleError();
}
Yes, you have to throw exception :
try
{
throw new Exception("hello");
}
catch (Exception)
{
//run some code here...
}
An effective way to throw an Exception and also jump to Catch as so:
try
{
throw new Exception("Exception Message");
}
catch (Exception e)
{
// after the throw, you will land here
}
if(conditiontrue)
{
}
else{
throw new Exception();
}
Yes, if you throw the exception that you intend to catch from within the try, it will be caught in the catch section.
I have to ask you why you would want to do this though? Exception handling is not meant to be a substitute for control flow.
I think what you want is a finally block: http://msdn.microsoft.com/en-us/library/zwc8s4fz(v=vs.80).aspx
see this
try
{
doSomething();
}
catch
{
catchSomething();
throw an error
}
finally
{
alwaysDoThis();
}
This is different if/when you do this:
try
{
doSomething();
}
catch
{
catchSomething();
throw an error
}
alwaysDoThis();// will not run on error (in the catch) condition
the the this last instance, if an error occurs, the catch will execute but NOT the alwaysDoThis();. Of course you can still have multiple catch as always.
As cadrel said, but pass through an Exception to provide more feedback, which will be shown in the innerException:
try
{
if (AnyConditionTrue)
{
MethodWhenTrue();
}
else
{
HandleError(new Exception("AnyCondition is not true"));
}
}
catch (Exception ex)
{
HandleError(ex);
}
...
private void HandleError(Exception ex) {
throw new ApplicationException("Failure!", ex);
}
public class CustomException: Exception
{
public CustomException(string message)
: base(message) { }
}
//
if(something == anything)
{
throw new CustomException(" custom text message");
}
you can try this
You could throw an exception to force a catch
throw new Exception(...);
why are you catching an exception? Why not just run the code in your "else" block? If you MUST do it that way, just throw a new exception
throw new Exception();
Slight resurrection, but I wanted to add both a sample (primarily like others) and a use case.
public int GetValueNum(string name)
{
int _ret = 0;
try
{
Control c = (extendedControls.Single(s => s.ValueName == name) as Control);
if (c.GetType() == typeof(ExtendedNumericUpDown))
_ret = (int)((ExtendedNumericUpDown)c).Value;
else
throw new Exception();
}
catch
{
throw new InvalidCastException(String.Format("Invalid cast fetching .Value value for {0}.\nExtendedControllerListener.GetValueNum()", name));
}
return _ret;
}
In my case, I have custom controls - a handful of controls that use a base Windows.Forms control, but add two bools and a string for tracking, and also automatically get registered to a Singleton List<T> so they can be properly fetched without drilling down through control containers (it's a tabbed form).
In this case, I'm creating some methods to easily get values (.Value, .Text, .Checked, .Enabled) by a name string. In the case of .Value, not all Control objects have it. If the extended control is not of type ExtendedNumericUpDown, it IS an InvalidCastException as the method should not be called against that type of control. This isn't flow, but the prescribed usage of invalid cast. Since Control doesn't naturally have a .Value property, Visual Studio won't let me just force an attempt and fail after.
In Python, there is this useful exception handling code:
try:
# Code that could raise an exception
except Exception:
# Exception handling
else:
# Code to execute if the try block DID NOT fail
I think it's useful to be able to separate the code that could raise and exception from your normal code. In Python, this was possible as shown above, however I can't find anything like it in C#.
Assuming the feature or one like it doesn't exist, is it standard practice to put normal code in the try block or after the catch block?
The reason I ask is because I have the following code:
if (!IsReadOnly)
{
T newobj;
try
{
newobj = DataPortal.Update<T>(this);
List<string> keys = new List<string>(BasicProperties.Keys);
foreach (string key in keys)
{
BasicProperties[key] = newobj.BasicProperties[key];
}
}
catch (DataPortalException)
{
// TODO: Implement DataPortal.Update<T>() recovery mechanism
}
}
Which requires the normal code to be in the try block because otherwise if an exception was raised and subsequently handled, newobj would be unassigned, but it feels quite unnatural to have this much code in the try block which is unrelated to the DataPortalException. What to do?
Thanks
I would prefer to see the rest of the code outside the try/catch so it is clear where the exception you are trying to catch is coming from and that you don't accidentally catch an exception that you weren't trying to catch.
I think the closest equivalent to the Python try/catch/else is to use a local boolean variable to remember whether or not an exception was thrown.
bool success;
try
{
foo();
success = true;
}
catch (MyException)
{
recover();
success = false;
}
if (success)
{
bar();
}
But if you are doing this, I'd ask why you don't either fully recover from the exception so that you can continue as if there had been success, or else fully abort by returning an error code or even just letting the exception propagate to the caller.
Barbaric solution: create an Else class derived from Exception, throw an instance of it at the end of the try block, and use catch (Else) {...} to handle the other stuff.
I feel so dirty.
This will might get downvoted but doesn't c# have goto(note I have almost no c# knowledge so I have no idea if this works).
what about something like
try
{
...
}
catch(Exception ex)
{
...
goto Jump_past_tryelse
}
...//Code to execute if the try block DID NOT fail
Jump_past_tryelse:
...
C# does not have such a concept, so you are just left with three options,
put the else code inside the try.
put the else code outside the try catch block, use a local variable to indicate success or failure, and an if block around your else code.
put the else code in the finally block, use a local variable to indicate success or failure, and an if block arount you else code.
Allow me to repeat an idea from a similar StackOverflow question. You cannot do this directly, but you can write a method that encapsulates the behavior you need. Look at the original question to see how to implement the method (if you're not familiar with lambda expressions and Func delegates). The usage could look like this:
TryExceptRaise(() => {
// code that can throw exception
}, (Exception e) => {
// code to run in case of an exception
return (...);
}, () => {
// code to run if there is no exception
return (...);
});
Just put your "else" block before the catch. Then, it will only execute if code execution reaches that point:
try
{
fee();
fi();
foe();
fum();
/// put your "else" stuff here.
/// It will only be executed if fee-fi-foe-fum did not fail.
}
catch(Exception e)
{
// handle exception
}
Given that, I fail to see the use of try..catch...else unless there's something vital missing from the OP's description.
With C# version 7, you could use local functions to emulate this behaviour:
Example 1: (since C# version 7)
void Main()
{
void checkedCode()
{
try
{
foo();
}
catch (Exception ex)
{
recover();
return;
}
// ElseCode here
}
checkedCode();
}
If you prefer lambda syntax, you could also declare a run method
void Run(Action r) { r(); }
which only needs to be there once in your code, and then use the pattern for anonymous methods as follows
Example 2: (older C# versions and C# version 7)
Run(() => {
try
{
foo();
}
catch (Exception)
{
recover();
return;
}
// ElseCode here
});
whereever you need to enclose code in a safe context.
Try it in DotNetFiddle
Notes:
In both examples a function context is created so that we can use return; to exit on error.
You can find a similar pattern like the one used in Example 2 in JavaScript: Self-invoking anonymous functions (e.g. JQuery uses them). Because in C# you cannot self-invoke, the helper method Run is used.
Since Run does not have to be a local function, Example 2 works with older C# versions as well
You could do something like this:
if (!IsReadOnly)
{
T newobj = null;
try
{
newobj = DataPortal.Update<T>(this);
}
catch (DataPortalException)
{
// TODO: Implement DataPortal.Update<T>() recovery mechanism
}
if (newobj != null)
{
List<string> keys = new List<string>(BasicProperties.Keys);
foreach (string key in keys)
{
BasicProperties[key] = newobj.BasicProperties[key];
}
}
}
that would be the empty statement like hits
try
{
somethingThatCanThrow();
}
catch(Exception ex)
{
LogException(ex);
return;
}
ContinueFlow();
if (!IsReadOnly)
{
T newobj;
bool Done;
try
{
newobj = DataPortal.Update<T>(this);
List<string> keys = new List<string>(BasicProperties.Keys);
foreach (string key in keys)
{
BasicProperties[key] = newobj.BasicProperties[key];
}
Done = true;
}
catch (DataPortalException)
{
// TODO: Implement DataPortal.Update<T>() recovery mechanism
Done = false;
}
finally
{
if (newobj != null && Done == false)
{
List<string> keys = new List<string>(BasicProperties.Keys);
foreach (string key in keys)
{
BasicProperties[key] = newobj.BasicProperties[key];
}
}
}
}
I want to go once through a loop but only if an exception is thrown go back through the loop. How would I write this in C#?
Thanks
This smells of bad design to me. The general rule is: exceptions should not be used for flow control. There are a number of reasons for this; namely, there are usually better/more reliable methods that can be used to check things before an exceptions is thrown, and also it decreases efficiency.
Nonetheless, just for the sake of argument, you could do something like the following:
while (true)
{
try
{
// do stuff here
}
catch (MyException)
{
continue;
}
// all is good
break;
}
Again - this is not the recommended way. I would be happy to suggest something better if you could provide a bit more context/examples/
What about the following where you can set a retry count:
int tryCount = 0;
while (tryCount < 3)
{
try
{
someReturn = SomeFunction(someParams);
}
catch (Exception)
{
tryCount++;
continue;
}
break;
}
That really depends on what you're doing, and the type of exception being thrown. Many exceptions aren't something that would be fixed by just trying again with the exact same inputs/data, and thus looping would just keep generating the exception ad infinitum.
Instead, you should check for relevant exceptions and then handle them in an appropriate manner for those particular exceptions.
You could use Polly
and then you just need to configure the Policy with your exceptions and retry count:
var retryPolicy = Policy
.Handle<IOException>(x => x.Message.Contains("already exist"))
.Or<FormatException>()
.Retry(3);
and you use like this:
retryPolicy.Execute(() =>
{
throw new FormatException();
});
Why not call a function that actually does the loop, and have a catch after it that would call the function again.
private void loop() {
for(...) {
}
}
some other method:
try {
loop();
} catch(Exception e) {
loop();
}
Something like:
bool done = false;
while( ! done )
{
try
{
DoSomething();
done = true;
} catch(Exception ex)
{
HandleException(ex);
}
}
As Noldorin said, it smells like a bad design. You're using exceptions to control the flow of the program. Better to have explicit checks for the conditions that will cause you to repeat the operation.
So I am using this simple stuff :D
bool exceptionthrow = false;
while (!exceptionthrow)
{
try
{
value = Convert.ToInt32(Console.ReadLine()); //example
exceptionthrow = true;
}
catch (Exception)
{
exceptionthrow = false;
continue;
}
}
Hope it helps :)