I want to get function name of the exception thrown from dll in asp.net.
You can create a StackTrace class from the exception and analyze the frames.
For example:
public void Throw()
{
throw new MyException();
}
public void CallThrow()
{
Throw();
}
[Test]
public void GetThrowingMethodName()
{
try
{
CallThrow();
Assert.Fail("Should have thrown");
}
catch (MyException e)
{
MethodBase deepestMethod = new StackTrace(e).GetFrame(0).GetMethod();
string deepestMethodName = deepestMethod.Name;
Assert.That(deepestMethodName, Is.EqualTo("Throw"));
}
}
You should be able to make use of the Stack Trace
Exception.StackTrace Property
StackTrace Class
Represents a stack trace, which is an
ordered collection of one or more
stack frames.
StackFrame Class
A StackFrame is created and pushed on
the call stack for every function call
made during the execution of a thread.
The stack frame always includes
MethodBase information, and optionally
includes file name, line number, and
column number information.
StackFrame information will be most
informative with Debug build
configurations. By default, Debug
builds include debug symbols, while
Release builds do not. The debug
symbols contain most of the file,
method name, line number, and column
information used in constructing
StackFrame objects.
You can try stacktrace object with the help of system.diagnostic namespace here is the linqpad testing source code that you can try out.
void Main()
{
try {
test();
}
catch(Exception ex) {
StackTrace st = new StackTrace();
st.GetFrame(1).GetMethod().Name.Dump();
}
}
// Define other methods and classes here
public void test()
{
throw new NotImplementedException();
}
Checkout StackTrace.GetFrame Method
Related
I've looked at other post concerning unit testing but none that I saw actually test what's in the exception when thrown. The main goal is to raise an exception and examine the details of the stack trace by sending a bad parameter to a helper class.
Since the original code wasn't throwing an exception I decided to do some online research on NUnit testing and come across a very nice piece of code that is lot shorter then what I wrote but failes to examine the error object. I need to be able to Assert a presence of certain verbiage in the stack trace.
Originally this is what the code looked like, but I must admit it is not very pretty:
[Test]
public void TestExceptionHandling()
{
try
{
DoExceptionScenario(new SomeCustomRadioButtonControl(), FieldManager.GetField("access_mode"));
}
catch (Exception ex)
{
Assert.IsInstanceOf(typeof(CustomException), ex);
string details = Util.GetExceptionDetails((CustomException)ex);
Assert.IsTrue(details.Contains("Detail Name=\"ControlName\" Description=\"SomeCustomRadioButtonControl\""));
}
}
The problem as you may see is a possiblity of bunch of false positives.
The other way I modified the test is like this:
[Test]
public void TestExceptionHandling()
{
Assert.That(() => DoExceptionScenario(new SomeCustomRadioButtonControl(), FieldManager.GetField("access_mode")),
Throws.TypeOf<CustomException>());
}
This will fail if there is no exception. But if there is an exception how do I capture that and examine its contents? Something along lines of (the if statement would work in this case):
[Test]
public void ShouldControlNameBeListedInStackTrace()
{
bool exceptionStatus = Assert.That(() => DoExceptionScenario(new SomeCustomRadioButtonControl(), FieldManager.GetField("access_mode")),
Throws.TypeOf<CustomException>());
if (exceptionStatus != true)
{
string details = Util.GetExceptionDetails((CustomException)ex);
Assert.IsTrue(details.Contains("detail name=\"controlname\" description=\"SomeCustomRadioButtonControl\""));
}
}
Assume a CustomException class that looks like this. It doesn't do much of anything... just overrides the "Message" property from the base Exception class:
public class CustomException : Exception
{
private string message;
public override string Message
{
get { return string.Format("{0}: {1}", DateTime.Now, message); }
}
public CustomException(string message)
{
this.message = message;
}
}
And assume you have a method that throws the exception, such as this:
public class ProductionClass
{
public void SomeMethod()
{
throw new CustomException("Oh noz!");
}
}
Here's a few sample tests you can use in nUnit. You want the last one.
[TestFixture]
public class MyTests
{
private ProductionClass p;
[SetUp]
public void Setup()
{
p = new ProductionClass();
}
// Use the ExpectedException attribute to make sure it threw.
[Test]
[ExpectedException(typeof(CustomException)]
public void Test1()
{
p.SomeMethod();
}
// Set the ExpectedMessage param to test for a specific message.
[Test]
[ExpectedException(typeof(CustomException), ExpectedMessage = "Oh nozzzz!")]
public void Test2()
{
p.SomeMethod();
}
// For even more detail, like inspecting the Stack Trace, use Assert.Throws<T>.
[Test]
public void Test3()
{
var ex = Assert.Throws<CustomException>(() => p.SomeMethod());
Assert.IsTrue(ex.StackTrace.Contains("Some expected text"));
}
}
The Assert.Throws<T> method works with any Exception. It executes the delegate in the parentheses and detects whether or not it threw the exception.
In the above test, if it did throw, it then tests the stack trace for the specified contents too. If both steps pass, the test passes.
I wonder whether there is a short and simple way for checking whether variable/property values match some condition?
Currently one of the most popular line in my code is similar to this one:
if (string.IsNullOrWhiteSpace(someFileName))
{
throw new NullReferenceException("'someFileName' must not be null.");
}
then the exception gets logged in the catch part and the execution continues and so on.
I don't like writing this line all over the place and just changing the variable name. It would be great if one could write something like this:
Assert.IsNotNullOrWhiteSpace(someFileName);
and it threw an exception saying that "{my variable} must not be null" with maybe some additional information like the parent class etc. that would help you to debug the code if you only have the logs available.
The problem with writing such a utility class that I encountered was that the thrown exception had of course the wrong stack trace like it happened in the utility method and not inside the method that called the assertion function.
This kind of value checking is required to especially work at runtime because I most of the time check user input like settings, paths, inputs etc.
EDIT:
I think I should have given an example of what I try to achieve:
public class FileExtractor {
public Form MainForm { get; set; }
public void ExtractFile(string fileName) {
Assert.IsNotNullOrWhiteSpace(fileName);
Assert.IsNotNull(MainForm);
// ...
}
}
and the let's call it Assert library should do this:
public static Assert {
public static void IsNotNullOrWhiteSpace(this string value) {
if (string.IsNullOrWhiteSpace(value)) {
// throw an exception like it occured in the ExtractFile
// the message should contain a hint like: "fileName must not be null"
}
}
public static void IsNotNull(this object value) {
if (value == null) {
// throw an excaption like it occured in the ExtractFile,
// the messagge should contain a hint like: "FileExtractor.MainForm must not be null."
}
}
EDIT-2
#CodeCaster - unfortunately I cannot not use C# 6 yet.
After some research and inspirated by two other questions here on stackoverflow
How to get Property Value from MemberExpression without .Compile()?
and
get name of a variable or parameter
I came up with this so far:
namespace ExceptionTest
{
class Program
{
static void Main(string[] args)
{
object test = null;
Assert.IsNotNull(() => test);
}
}
static class Assert
{
public static void IsNotNull<T>(Expression<Func<T>> expression)
{
MemberExpression memberExpr = expression.Body as MemberExpression;
var constExpr = memberExpr.Expression as ConstantExpression;
var value = (memberExpr.Member as FieldInfo).GetValue(constExpr.Value);
if (value == null)
{
throw new ArgumentNullException(memberExpr.Member.Name);
}
}
}
}
It almost does what I need. The last thing is to modify the stack trace so that it points to the Main method and not to the IsNotNull
You could use Debug Methods (http://msdn.microsoft.com/en-us/library/System.Diagnostics.Debug_methods%28v=vs.110%29.aspx), which however only work when compiling in debug mode.
Maybe Debug.WriteLineIf(Boolean, String) does what you need?
http://msdn.microsoft.com/en-us/library/y94y4370%28v=vs.110%29.aspx
How about applying attributes to the properties
http://msdn.microsoft.com/en-us/library/dd901590(VS.95).aspx
I think that you should try with Fody library library. For null-guards there is a package that you can find here. All libs are available via Nuget.
Fody is some kind AOP library that uses "weaving" technique to manipulate IL of an assembly and inject additional code.
So NullReferenceExcpetion (or maybe NullArgumentException) will be thrown exactly from your method.
Example from GitHub:
Your code
public void SomeMethod(string arg)
{
// throws ArgumentNullException if arg is null.
}
public void AnotherMethod([AllowNull] string arg)
{
// arg may be null here
}
What gets complied
public void SomeMethod(string arg)
{
if (arg == null)
{
throw new ArgumentNullException("arg");
}
}
public void AnotherMethod(string arg)
{
}
I have a multicast OnExceptionAspect from Postsharp which is applied on the assembly level. This naturally means that all methods, upon throwing an exception, will invoke the Aspect.
Within the Aspect I'm logging the exception details including the values of the parameters passed when the exception occured, this is working properly.
However because this is applied to all methods in the assembly a log entry is created for each method in the stack as the exception bubbles up through each.
I'm out of ideas on how to prevent this, initially I was going to compare the exception (to see if it's the same one) but this just seems messy. Someone must have had this problem before, any ideas?
There are two solutions to this problem.
A. Use a thread-static field to store any exception that has already been logged.
[Serializable]
public class MyAspect : OnExceptionAspect
{
[ThreadStatic]
private static Exception lastException;
public override void OnException(MethodExecutionArgs args)
{
if(args.Exception != lastException)
{
string msg = string.Format("{0} had an error # {1}: {2}\n{3}",
args.Method.Name, DateTime.Now,
args.Exception.Message, args.Exception.StackTrace);
Trace.WriteLine(msg);
lastException = args.Exception;
}
}
}
B. Add a tag to the Exception object.
[Serializable]
public class MyAspect : OnExceptionAspect
{
private static object marker = new object();
public override void OnException(MethodExecutionArgs args)
{
if(!args.Exception.Data.Contains(marker))
{
string msg = string.Format("{0} had an error # {1}: {2}\n{3}",
args.Method.Name, DateTime.Now,
args.Exception.Message, args.Exception.StackTrace);
Trace.WriteLine(msg);
args.Exception.Data.Add(marker, marker);
}
}
}
FYI--Gael is a PostSharp guru because he is employed there...just so you are aware.
For what it is worth you can always tell where the exception originated by examining the StackTrace. The StackTrace is made available via args.Exception.StackTrace. You may try what Dustin Davis (another PostSharp employee) recommends here: PostSharp - OnExceptionAspect - Get line number of exception
Parse the StackTrace (via the method outlined here: How to split a stacktrace line into namespace, class, method file and line number?) then compare the args.Method.Name with the parsed results. If your args.Method.Name is the same as the originating method (found via parsing the StackTrace) then you know you should log it otherwise ignore.
Here is some code to make my solution more concrete (building on the prior two solutions cited):
[Serializable]
public class ExceptionWrapper : OnExceptionAspect
{
public override void OnException(MethodExecutionArgs args)
{
var st = new StackTrace(args.Exception, true);
var frame = st.GetFrame(0);
var lineNumber = frame.GetFileLineNumber();
var methodName = frame.GetMethod().Name;
if(methodName.Equals(args.Method.Name))
{
string msg = string.Format("{0} had an error # {1}: {2}\n{3}",
args.Method.Name, DateTime.Now,
args.Exception.Message, args.Exception.StackTrace);
Trace.WriteLine(msg);
}
}
}
(Or, honestly, you could just use one of Gael's recommended solutions.)
One way i could see this being done would be to define a custom exception and just throw that one in your aspect. then also in your aspect check the exception before loggin, if it's not your custom exception log it, otherwise don't log it and (re-throw?).
That's what the example code would look like:
[Serializable]
public class DatabaseExceptionWrapper : OnExceptionAspect
{
public override void OnException(MethodExecutionArgs args)
{
if(!(args.Exception is CustomException))
{
string msg = string.Format("{0} had an error # {1}: {2}\n{3}",
args.Method.Name, DateTime.Now,
args.Exception.Message, args.Exception.StackTrace);
Trace.WriteLine(msg);
}
throw new CustomException("There was a problem");
}
}
Of course you'd still have to define that exception and everything. :)
I am fully aware that what I am about to ask is not good practice... but:
Let's say I have a class containing a function that I want to always return a value, but store any exceptions that might occur for later processing. Something Like:
public Exception _error { get; set; }
public bool IsValid()
{
try
{
//do something here to cause exception
return true;
}
catch (Exception ex)
{
_error = ex;
return false;
}
}
Now that I have stored the exception, is it at all possible to throw the exception from an outside method while maintaining both the original stack trace and exception type?
throw _error; //lose stack trace
throw new Exception("", _error) //lose type
Thanks for looking or answering.
EDIT:
Thanks to some additional points, I realize that the below idea only takes away information and doesn't really add or simplify the situation. Thanks again to everyone.
After pondering Pieter's answer and comments, I'm now wondering if making a wrapper Exception class like the below could be a partial solution. This overrides as much of the exception as possible to make the New exception look like its innerexception, including the stacktrace.. dirty I know, but interesting:
public class ExceptionWrapper : Exception
{
private Exception _innerException;
public ExceptionWrapper(Exception ex) : base("", ex)
{
_innerException = ex;
this.Source = ex.Source;
this.HelpLink = ex.HelpLink;
}
public override string StackTrace
{
get
{
return _innerException.StackTrace;
}
}
public override System.Collections.IDictionary Data
{
get
{
return _innerException.Data;
}
}
public override string Message
{
get
{
return _innerException.Message;
}
}
public new Exception InnerException
{
get
{
return _innerException.InnerException;
}
}
}
No, this is not possible.
However, you normally solve this is by wrapping the exception in a new exception:
throw new MyException("Wrapper", _error);
This does maintain the stack trace of _error, but you do get a new exception. Your solution in your second example is the correct way of handling these cases.
Consider using reflection to create a wrapper exception of the correct type (Activator.CreateInstance) and calling the constructor that will accept the inner exception you have stored.
For example:
[Test]
public void test()
{
Exception ex = new ArgumentNullException();
Exception wrapped = (Exception)Activator.
CreateInstance(ex.GetType(), "wrapped", ex);
Type expectedType = typeof(ArgumentNullException);
Assert.IsInstanceOf(expectedType, wrapped, "Is ArgumentNullException.");
Assert.AreEqual(ex, wrapped.InnerException, "Exception is wrapped.");
}
Update
In order to mitigate the constructor issue, you could consider using the default constructor (should be there for an exception that follows design guidelines, but not mandatory) and then patching up the new instance by setting its fields via reflection.
I agree the approach is highly "meh" it's more an exploration of an idea. I wouldn't recommend it.
The exception design guidelines require a default constructor, so this sort of behaviour may go on in the framework somewhere anyway. Perhaps for some sort of icky serialization\deserialization of exceptions across some sort of communications boundary?
It seems that .net-4.5 added a new API for capturing stack/info about exceptions and rethrowing them in different contexts. This is called ExceptionDispatchInfo. It is useful if you find yourself needing more control over running tasks indirectly, like if you do manual thread management for jobs or Task does not exactly fit your needs. In your example, it should look like this:
public ExceptionDispatchInfo _error { get; private set; }
public bool IsValid()
{
try
{
//do something here to cause exception
return true;
}
catch (Exception ex)
{
_error = ExceptionDispatchInfo.Capture(ex);
return false;
}
}
/// <summary>Throw underlying exception if invalid.</summary>
public void AssertWasValid() => _error?.Throw();
Now, it doesn’t preserve the original caller. The displayed stack trace shows the calls from the original try block into the code in there, a statement breaking the original and new parts of the stack, and then the calls into ExceptionDispatchInfo.Throw() itself as the new part of the shown stack. This seems similar to how traces with async code look. If you care about the original caller, seems this won’t work. But if you care about getting the line/method that threw the exception, this should be sufficient.
I am trying to get the list of calls made from the beginning of a try block to the exception. In the code below, when I fall into the Catch block, the StackTrace in the Exception object is the following :
at ConsoleApplication.Program.MethodC() / at
ConsoleApplication.Program.Main(String[] args).
This is totally expected, but doesn't help me to get the history of calls. Does anybody have an idea on how I could do this?
static void MethodA() { }
static void MethodB() { }
static void MethodC() { throw new Exception(); }
static void Main(string[] args)
{
try
{
MethodA();
MethodB();
MethodC();
}
catch (Exception e)
{
// Get list of calls
throw;
}
}
I was surprised to see that the StackTrace property of the Exception object isn't StackTrace object. Is there any reason for this?
In the end, the purpose of all this is simple. If an exception is thrown during the execution of the code, I want to look at the meta data (attribute) of each of the methods called.
As I understand your question, you want to be able to know which methods was called before MethodC in your try block. I don't think you can do that without adding code to your methods.
When MethodA finishes executing, it is no longer on the stack, so there is nowhere you can get the information from. Same goes for MethodB, and only MethodC is on the stack when the Exception occurs.
It seems you're not going to be able to get a stack trace for each method called with the try block unless you add custom logging code to each method. However, you can create a System.Diagnostics.StackTrace option easily from an exception simply by passing the Exception object to the constructor. This will make available all the information about the stack trace including whether the exception was thrown from MethodA/MethodB/MethodC, which might be at least somewhat helpful to you.
Example code:
static void MethodA() { }
static void MethodB() { }
static void MethodC() { throw new Exception(); }
static void Main(string[] args)
{
try
{
MethodA();
MethodB();
MethodC();
}
catch (Exception e)
{
System.Diagnostics.StackTrace callStack = new System.Diagnostics.StackTrace(e);
System.Diagnostics.StackFrame frame = null;
System.Reflection.MethodBase calledMethod = null;
System.Reflection.ParameterInfo[] passedParams = null;
for (int x = 0; x < callStack.FrameCount; x++)
{
callStack.GetFrame(x);
calledMethod = frame.GetMethod();
passedParams = calledMethod.GetParameters();
foreach (System.Reflection.ParameterInfo param in passedParams)
System.Console.WriteLine(param.ToString());
}
}
}
(You can see this SO thread for the original answer containing the code. I've just slightly modified it.)
Hope that's at least a partial solution to your question.
You can easily get a StackTrace object from anywhere in your code but as has already been pointed out you can not get the full history of method calls.