I'm not quite sure how best ask this question, so please feel free to edit...
I have a "Utilities" class that contains common functionality used throughout my application. One of my methods logs exeptions like this:
internal static void logExeption(Type typeOfClass, string methodName, Exception exeption )
{
//Do some logging here
}
Then I'd like to call it throughout my application whenever I catch an exception like so:
try{
//perform some action
}
catch(Exception ex)
{
Utils.logExeption(this.GetType(), System.Reflection.MethodBase.GetCurrentMethod().Name, ex);
}
I would like to know if there's a way I can avoid passing in the first two parameters and just figure out the context of the Class/Method where the exception originated right in the logException method. This will make things cleaner for me in the long run.
So you want to determine the calling object and the function. Though it is not recommended it can be achieved. Use System.Diagnostics.StackTrace to walk the stack; then get the appropriate StackFrame one level up. Then determine which method was the caller by using GetMethod() on that StackFrame. Note that building a stack trace is a potentially expensive operation, and it's possible for callers of your method to obscure where things are really coming from.
StackFrame frame = new StackFrame(1);
MethodBase method = frame.GetMethod();
string message = String.Format("{0}.{1} : {2}",
method.DeclaringType.FullName, method.Name, message);
Console.WriteLine(message);
Please note that frame.GetMethod().DeclaringType can return null: sometime ago I faced with this problem only on release build of my application using NLog logger (GetCurrentClassLogger). Can't remember exactly the case. By the way, it is known issue.
There is an interesting trick in Apache log4net which allows to detect the caller info (class, method, etc.).
Please take a look at:
LocationInfo class (source) - the internal representation of caller location information.
public class LocationInfo
{
...
public LocationInfo(Type callerStackBoundaryDeclaringType)
{
// Here is the trick. See the implementation details here.
}
...
}
LogImpl class (source) - the logger implementation class - wrapper around ILogger interface - to do the trick it must not be subclassed!
public class LogImpl : LoggerWrapperImpl, ILog
{
...
public LogImpl(ILogger logger) : base(logger)
{
...
}
/// <summary>
/// The fully qualified name of this declaring type not the type of any subclass.
/// </summary>
private readonly static Type ThisDeclaringType = typeof(LogImpl);
virtual public void Error(object message, Exception exception)
{
Logger.Log(ThisDeclaringType, m_levelError, message, exception);
}
...
}
You can use StackTrace Class. See the example there which is very similar with your question.
Related
For a given class I would like to have tracing functionality i.e. I would like to log every method call (method signature and actual parameter values) and every method exit (just the method signature).
How do I accomplish this assuming that:
I don't want to use any 3rd party
AOP libraries for C#,
I don't want to add duplicate code to all the methods that I want to trace,
I don't want to change the public API of the class - users of the class should be able to call all the methods in exactly the same way.
To make the question more concrete let's assume there are 3 classes:
public class Caller
{
public static void Call()
{
Traced traced = new Traced();
traced.Method1();
traced.Method2();
}
}
public class Traced
{
public void Method1(String name, Int32 value) { }
public void Method2(Object object) { }
}
public class Logger
{
public static void LogStart(MethodInfo method, Object[] parameterValues);
public static void LogEnd(MethodInfo method);
}
How do I invoke Logger.LogStart and Logger.LogEnd for every call to Method1 and Method2 without modifying the Caller.Call method and without adding the calls explicitly to Traced.Method1 and Traced.Method2?
Edit: What would be the solution if I'm allowed to slightly change the Call method?
C# is not an AOP oriented language. It has some AOP features and you can emulate some others but making AOP with C# is painful.
I looked up for ways to do exactly what you wanted to do and I found no easy way to do it.
As I understand it, this is what you want to do:
[Log()]
public void Method1(String name, Int32 value);
and in order to do that you have two main options
Inherit your class from MarshalByRefObject or ContextBoundObject and define an attribute which inherits from IMessageSink. This article has a good example. You have to consider nontheless that using a MarshalByRefObject the performance will go down like hell, and I mean it, I'm talking about a 10x performance lost so think carefully before trying that.
The other option is to inject code directly. In runtime, meaning you'll have to use reflection to "read" every class, get its attributes and inject the appropiate call (and for that matter I think you couldn't use the Reflection.Emit method as I think Reflection.Emit wouldn't allow you to insert new code inside an already existing method). At design time this will mean creating an extension to the CLR compiler which I have honestly no idea on how it's done.
The final option is using an IoC framework. Maybe it's not the perfect solution as most IoC frameworks works by defining entry points which allow methods to be hooked but, depending on what you want to achive, that might be a fair aproximation.
The simplest way to achieve that is probably to use PostSharp. It injects code inside your methods based on the attributes that you apply to it. It allows you to do exactly what you want.
Another option is to use the profiling API to inject code inside the method, but that is really hardcore.
You could achieve it with Interception feature of a DI container such as Castle Windsor. Indeed, it is possible to configure the container in such way that every classes that have a method decorated by a specific attribute would be intercepted.
Regarding point #3, OP asked for a solution without AOP framework. I assumed in the following answer that what should be avoided were Aspect, JointPoint, PointCut, etc. According to Interception documentation from CastleWindsor, none of those are required to accomplish what is asked.
Configure generic registration of an Interceptor, based on the presence of an attribute:
public class RequireInterception : IContributeComponentModelConstruction
{
public void ProcessModel(IKernel kernel, ComponentModel model)
{
if (HasAMethodDecoratedByLoggingAttribute(model.Implementation))
{
model.Interceptors.Add(new InterceptorReference(typeof(ConsoleLoggingInterceptor)));
model.Interceptors.Add(new InterceptorReference(typeof(NLogInterceptor)));
}
}
private bool HasAMethodDecoratedByLoggingAttribute(Type implementation)
{
foreach (var memberInfo in implementation.GetMembers())
{
var attribute = memberInfo.GetCustomAttributes(typeof(LogAttribute)).FirstOrDefault() as LogAttribute;
if (attribute != null)
{
return true;
}
}
return false;
}
}
Add the created IContributeComponentModelConstruction to container
container.Kernel.ComponentModelBuilder.AddContributor(new RequireInterception());
And you can do whatever you want in the interceptor itself
public class ConsoleLoggingInterceptor : IInterceptor
{
public void Intercept(IInvocation invocation)
{
Console.Writeline("Log before executing");
invocation.Proceed();
Console.Writeline("Log after executing");
}
}
Add the logging attribute to your method to log
public class Traced
{
[Log]
public void Method1(String name, Int32 value) { }
[Log]
public void Method2(Object object) { }
}
Note that some handling of the attribute will be required if only some method of a class needs to be intercepted. By default, all public methods will be intercepted.
If you write a class - call it Tracing - that implements the IDisposable interface, you could wrap all method bodies in a
Using( Tracing tracing = new Tracing() ){ ... method body ...}
In the Tracing class you could the handle the logic of the traces in the constructor/Dispose method, respectively, in the Tracing class to keep track of the entering and exiting of the methods. Such that:
public class Traced
{
public void Method1(String name, Int32 value) {
using(Tracing tracer = new Tracing())
{
[... method body ...]
}
}
public void Method2(Object object) {
using(Tracing tracer = new Tracing())
{
[... method body ...]
}
}
}
If you want to trace after your methods without limitation (no code adaptation, no AOP Framework, no duplicate code), let me tell you, you need some magic...
Seriously, I resolved it to implement an AOP Framework working at runtime.
You can find here : NConcern .NET AOP Framework
I decided to create this AOP Framework to give a respond to this kind of needs. it is a simple library very lightweight. You can see an example of logger in home page.
If you don't want to use a 3rd party assembly, you can browse the code source (open source) and copy both files Aspect.Directory.cs and Aspect.Directory.Entry.cs to adapted as your wishes. Theses classes allow to replace your methods at runtime. I would just ask you to respect the license.
I hope you will find what you need or to convince you to finally use an AOP Framework.
Take a look at this - Pretty heavy stuff..
http://msdn.microsoft.com/en-us/magazine/cc164165.aspx
Essential .net - don box had a chapter on what you need called Interception.
I scraped some of it here (Sorry about the font colors - I had a dark theme back then...)
http://madcoderspeak.blogspot.com/2005/09/essential-interception-using-contexts.html
I have found a different way which may be easier...
Declare a Method InvokeMethod
[WebMethod]
public object InvokeMethod(string methodName, Dictionary<string, object> methodArguments)
{
try
{
string lowerMethodName = '_' + methodName.ToLowerInvariant();
List<object> tempParams = new List<object>();
foreach (MethodInfo methodInfo in serviceMethods.Where(methodInfo => methodInfo.Name.ToLowerInvariant() == lowerMethodName))
{
ParameterInfo[] parameters = methodInfo.GetParameters();
if (parameters.Length != methodArguments.Count()) continue;
else foreach (ParameterInfo parameter in parameters)
{
object argument = null;
if (methodArguments.TryGetValue(parameter.Name, out argument))
{
if (parameter.ParameterType.IsValueType)
{
System.ComponentModel.TypeConverter tc = System.ComponentModel.TypeDescriptor.GetConverter(parameter.ParameterType);
argument = tc.ConvertFrom(argument);
}
tempParams.Insert(parameter.Position, argument);
}
else goto ContinueLoop;
}
foreach (object attribute in methodInfo.GetCustomAttributes(true))
{
if (attribute is YourAttributeClass)
{
RequiresPermissionAttribute attrib = attribute as YourAttributeClass;
YourAttributeClass.YourMethod();//Mine throws an ex
}
}
return methodInfo.Invoke(this, tempParams.ToArray());
ContinueLoop:
continue;
}
return null;
}
catch
{
throw;
}
}
I then define my methods like so
[WebMethod]
public void BroadcastMessage(string Message)
{
//MessageBus.GetInstance().SendAll("<span class='system'>Web Service Broadcast: <b>" + Message + "</b></span>");
//return;
InvokeMethod("BroadcastMessage", new Dictionary<string, object>() { {"Message", Message} });
}
[RequiresPermission("editUser")]
void _BroadcastMessage(string Message)
{
MessageBus.GetInstance().SendAll("<span class='system'>Web Service Broadcast: <b>" + Message + "</b></span>");
return;
}
Now I can have the check at run time without the dependency injection...
No gotchas in site :)
Hopefully you will agree that this is less weight then a AOP Framework or deriving from MarshalByRefObject or using remoting or proxy classes.
First you have to modify your class to implement an interface (rather than implementing the MarshalByRefObject).
interface ITraced {
void Method1();
void Method2()
}
class Traced: ITraced { .... }
Next you need a generic wrapper object based on RealProxy to decorate any interface to allow intercepting any call to the decorated object.
class MethodLogInterceptor: RealProxy
{
public MethodLogInterceptor(Type interfaceType, object decorated)
: base(interfaceType)
{
_decorated = decorated;
}
public override IMessage Invoke(IMessage msg)
{
var methodCall = msg as IMethodCallMessage;
var methodInfo = methodCall.MethodBase;
Console.WriteLine("Precall " + methodInfo.Name);
var result = methodInfo.Invoke(_decorated, methodCall.InArgs);
Console.WriteLine("Postcall " + methodInfo.Name);
return new ReturnMessage(result, null, 0,
methodCall.LogicalCallContext, methodCall);
}
}
Now we are ready to intercept calls to Method1 and Method2 of ITraced
public class Caller
{
public static void Call()
{
ITraced traced = (ITraced)new MethodLogInterceptor(typeof(ITraced), new Traced()).GetTransparentProxy();
traced.Method1();
traced.Method2();
}
}
You can use open source framework CInject on CodePlex. You can write minimal code to create an Injector and get it to intercept any code quickly with CInject. Plus, since this is Open Source you can extend this as well.
Or you can follow the steps mentioned on this article on Intercepting Method Calls using IL and create your own interceptor using Reflection.Emit classes in C#.
I don't know a solution but my approach would be as follows.
Decorate the class (or its methods) with a custom attribute. Somewhere else in the program, let an initialization function reflect all types, read the methods decorated with the attributes and inject some IL code into the method. It might actually be more practical to replace the method by a stub that calls LogStart, the actual method and then LogEnd. Additionally, I don't know if you can change methods using reflection so it might be more practical to replace the whole type.
You could potentially use the GOF Decorator Pattern, and 'decorate' all classes that need tracing.
It's probably only really practical with an IOC container (but as pointer out earlier you may want to consider method interception if you're going to go down the IOC path).
you need to bug Ayende for an answer on how he did it:
http://ayende.com/Blog/archive/2009/11/19/can-you-hack-this-out.aspx
AOP is a must for clean code implementing, however if you want to surround a block in C#, generic methods have relatively easier usage. (with intelli sense and strongly typed code) Certainly, it can NOT be an alternative for AOP.
Although PostSHarp have little buggy issues (i do not feel confident for using at production), it is a good stuff.
Generic wrapper class,
public class Wrapper
{
public static Exception TryCatch(Action actionToWrap, Action<Exception> exceptionHandler = null)
{
Exception retval = null;
try
{
actionToWrap();
}
catch (Exception exception)
{
retval = exception;
if (exceptionHandler != null)
{
exceptionHandler(retval);
}
}
return retval;
}
public static Exception LogOnError(Action actionToWrap, string errorMessage = "", Action<Exception> afterExceptionHandled = null)
{
return Wrapper.TryCatch(actionToWrap, (e) =>
{
if (afterExceptionHandled != null)
{
afterExceptionHandled(e);
}
});
}
}
usage could be like this (with intelli sense of course)
var exception = Wrapper.LogOnError(() =>
{
MessageBox.Show("test");
throw new Exception("test");
}, "Hata");
Maybe it's to late for this answer but here it goes.
What you are looking to achieve is built in MediatR library.
This is my RequestLoggerBehaviour which intercepts all calls to my business layer.
namespace SmartWay.Application.Behaviours
{
public class RequestLoggerBehaviour<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
{
private readonly ILogger _logger;
private readonly IAppSession _appSession;
private readonly ICreateLogGrain _createLogGrain;
public RequestLoggerBehaviour(ILogger<TRequest> logger, IAppSession appSession, IClusterClient clusterClient)
{
_logger = logger;
_appSession = appSession;
_createLogGrain = clusterClient.GetGrain<ICreateLogGrain>(Guid.NewGuid());
}
public async Task<TResponse> Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate<TResponse> next)
{
var name = typeof(TRequest).Name;
_logger.LogInformation($"SmartWay request started: ClientId: {_appSession.ClientId} UserId: {_appSession.UserId} Operation: {name} Request: {request}");
var response = await next();
_logger.LogInformation($"SmartWay request ended: ClientId: {_appSession.ClientId} UserId: {_appSession.UserId} Operation: {name} Request: {request}");
return response;
}
}
}
You can also create performance behaviours to trace methods that take too long to execute for example.
Having clean architecture (MediatR) on your business layer will allow you to keep your code clean while you enforce SOLID principles.
You can see how it works here:
https://youtu.be/5OtUm1BLmG0?t=1
Write your own AOP library.
Use reflection to generate a logging proxy over your instances (not sure if you can do it without changing some part of your existing code).
Rewrite the assembly and inject your logging code (basically the same as 1).
Host the CLR and add logging at this level (i think this is the hardest solution to implement, not sure if you have the required hooks in the CLR though).
The best you can do before C# 6 with 'nameof' released is to use slow StackTrace and linq Expressions.
E.g. for such method
public void MyMethod(int age, string name)
{
log.DebugTrace(() => age, () => name);
//do your stuff
}
Such line may be produces in your log file
Method 'MyMethod' parameters age: 20 name: Mike
Here is the implementation:
//TODO: replace with 'nameof' in C# 6
public static void DebugTrace(this ILog log, params Expression<Func<object>>[] args)
{
#if DEBUG
var method = (new StackTrace()).GetFrame(1).GetMethod();
var parameters = new List<string>();
foreach(var arg in args)
{
MemberExpression memberExpression = null;
if (arg.Body is MemberExpression)
memberExpression = (MemberExpression)arg.Body;
if (arg.Body is UnaryExpression && ((UnaryExpression)arg.Body).Operand is MemberExpression)
memberExpression = (MemberExpression)((UnaryExpression)arg.Body).Operand;
parameters.Add(memberExpression == null ? "NA" : memberExpression.Member.Name + ": " + arg.Compile().DynamicInvoke().ToString());
}
log.Debug(string.Format("Method '{0}' parameters {1}", method.Name, string.Join(" ", parameters)));
#endif
}
I am implementing a custom XML formatter for log4.net
public class ISDSApplicationEventsLayout : XmlLayoutBase
{
protected override void FormatXml(...)
{
//Location Info
writer.WriteStartElement("Method");
writer.WriteString(**loggingEvent.LocationInformation.MethodName * *);
writer.WriteEndElement();
}
}
The problem is ... now when I call log method from my log wrapper class... called logging
public static void logEvent(string message)
{
log.Info(isdsLog);
}
I get the output....
<Method>logEvent</Method>
How is it possible to have the method name that called logEvent, rather than logEvent as the method name?
Thank you
Question Update:
If this above seems a bit complicated - what I am really asking is : How do you keep the context of the method that called the wrapping logging function in log4net...
example... method doWork()... calls -> logging wrapper --> calls log4net....
How do you make the methodname = doWork and NOT logging wrapper function....
Actually, you can fix this easily with out-of-the-box log4net. Your wrapper can call Logger.Log and pass the type of your wrapper class as the first parameter. So, your wrapper might look something like this:
public class MyLog4NetWrapper
{
ILog log = LogManager.GetLogger("WhateverYourLoggerNameIs");
public void logEvent(string message)
{
log.Logger.Log(typeof(MyLog4NetWrapper), LogLevel.Info, message, null);
}
}
When log4net logs a message, it traverses up the call stack until it gets to the method whose declaring type is equal to the type passed in as the first parameter of the Log method. The next method up the stack is the actual call site.
As far as wrapping the log4net logger, I'm not sure that I would recommend creating a static wrapper class. The main problem with that is that you can only have a single configurable logger in your app.config file. In other words, you won't be able to independently control the logging from different parts of your code. If you have class A and class B and both use your static wrapped logger, then both classes will log at the same level. If you wanted to turn logging on for class A and off for class B, you would not be able to do so.
I don't think you can easily fix this with out-of-the-box log4net. If we take a look at the ILog.Info method in the LogImpl class, that you are calling:
virtual public void Info(object message)
{
Logger.Log(ThisDeclaringType, m_levelInfo, message, null);
}
When a message is logged, log4net will walk the stacktrace of the current call in order to find the method that initiated the log operation. To do this Log4net uses the "ThisDeclaringType" type as the boundary of the search, the first call "above" calls within that type is chosen as the initiating method.
In your case, the first method encountered is the logEvent method. If you dropped the logEvent wrapper and used the logging methods directly you will get the desired information.
Wraper for log4net logger in 3 steps:
Add reference to log4net package( NugetPackage)
add your wrapper class , ensure to call log4net.Config.XmlConfigurator.Configure(); in static constructor of your wrapper class. This loads all configuration from your app.config .
add log4net configuration in your app.config
See the sample wrapper class below below.
public class Logger : ILogger
{
private static readonly log4net.ILog log;
static Logger()
{
log = log4net.LogManager.GetLogger(System.Reflection.MethodInfo.GetCurrentMethod().DeclaringType);
log4net.Config.XmlConfigurator.Configure();
}
public void Log(LogLevel logLevel, string message, params object[] args)
{
switch (logLevel)
{
case LogLevel.DEBUG: {
// log.Logger.Log helps logging actual method and the class which has called this method (Log(LogLevel logLevel, string message, params object[] args))
log.Logger.Log(typeof(Logger), log4net.Core.Level.Debug, string.Format(message, args), null);
break;
}
case LogLevel.INFO:
{
log.Logger.Log(typeof(Logger), log4net.Core.Level.Info, string.Format( message, args) , null);
break;
}
case LogLevel.ERROR:
{
log.Logger.Log(typeof(Logger), log4net.Core.Level.Error, string.Format(message, args), null);
break;
}
case LogLevel.WARN:
{
log.Logger.Log(typeof(Logger), log4net.Core.Level.Warn, string.Format(message, args), null);
break;
}
}
}
public void LogException(LogLevel logLevel, Exception exception)
{
Log(logLevel, exception.ToString());
}
}
I have a few extension methods that are fairly core to my app. I use them to route all calls to my OData service through a central Exception Handler. It looks like this:
var results = Entites.Customers.Where(x=>x.IsActive).Invoke();
The Invoke() is my extension method, and it all works great!
But when I get an exception, I would like to log it.
The problem I finding is that my ILogger cannot be resolved inside a static class (the class must be static for it to have extension methods.)
Is there any way to resolve a unity managed interface inside of a static Class? Or is the Dependency Injection pattern just not able to cope with this C# feature?
One option would be to just not have any implementation in the static class. Create a non-static class that contains the implementation of the method (not as an extension method) then have the extension method do nothing besides call the non-extension implementation.
After doing that the implementation is no longer in a static class.
public static class MyExtension
{
public static void Invoke<T>(this IQueryable<T> query)
{
MyExtensionImplementation.Invoke(query);
}
}
internal class MyExtensionImplementation
{
public static void Invoke<T>(IQueryable<T> query)
{
//actual work
}
}
A bad news - there is no way to do this, a good news - you don't need to log exceptions inside your extension methods. Just let an exception to be throwen outside the static class and handle it in a proper way.
IResult results;
try
{
results = Entites.Customers.Where(x=>x.IsActive).Invoke();
}
catch(YourOwnException ex)
{
Log(ex, "The Business logic error.");
}
catch(ArgumentException ex)
{
Log(ex, "Invalid arguments.")
}
...
catch(Exception ex)
{
Log(ex, "Unknown error.");
}
EDIT:
Most of them are communications related and would be handled in the
extension method. Just a few that are business related will be
rethrown.
If exceptions are "communications related" or 3-rd party, maybe you don't need to log them. In this case I would create a TryInvoke() method without logging, which returns TRUE for a success operation and has an OUT parameter. If you want to log them you should inject ILogger inside your Invoke() method.
if(Entites.Customers.Where(x=>x.IsActive).TryInvoke(out results))
{
// Success
}
Following the example in book and got the following slightly modified code:
class OutOfHoneyException : Exception
{
public OutOfHoneyException(string message) :base(message){}
}
class HoneyDeliverSystem
{
public void FeedHoneyToEggs()
{
if (true)
{
throw new OutOfHoneyException("This hive is Out Of Honey");
}
}
}
.....................................
HoneyDeliverSystem delivery = new HoneyDeliverSystem();
try
{
delivery.FeedHoneyToEggs();
}
catch (OutOfHoneyException ex)
{
Console.WriteLine(ex.Message);
}
What I understand when ever a specific exception is thrown by us in specific condition, the corresponding catch block handles that.
But please help me with a better example, maybe .NET exception's implementation will be really helpful.
And why are we passing the message to the base Exception class? Is it only for printing purpose?
There is a OOPS concept for child class calling base class constructor. Could you please name it and how it is related to custom exceptions example?
The best thing to do is put your new exception in it's own file and make it public. The base Exception class has 4 constructors and in most cases it'd be useful to implement at least the first 3:
public class OutOfHoneyException : Exception
{
public OutOfHoneyException()
: base()
{
}
public OutOfHoneyException(string message)
: base(message)
{
}
public OutOfHoneyException(string message, Exception innerException)
: base(message, innerException)
{
}
public OutOfHoneyException(SerializationInfo info, StreamingContext context)
: base(info, context)
{
}
}
You inherit from the Exception class, because it has all the basic exception implementation/behaviour that is expected when handling an custom exception.
You need to implement all 4 constructors to make your new custom exception feel even more like a typical .NET exception.
Two things to note when learning things about exceptions, is firstly that exceptions should be thrown only for exceptional behaviour and secondly that exceptions shouldn't be used to control program flow. These 2 rules kind of fit together.
For example if you were querying a stock control system to see how many cans of beans were in stock, then a result of 0 would be a common answer and although it wouldn't be a desirable answer for the customer, it's not exceptional. If you queried the stock system for cans of beans and the database server wasn't available, that's exceptional behaviour outside of the common result you were expecting.
You are not very far away from common practice. I would have done it like this:
class OutOfHoneyException : Exception {
public OutOfHoneyException() : base("This hive is Out Of Honey"){}
}
class HoneyDeliverSystem {
public void FeedHoneyToEggs() {
throw new OutOfHoneyException();
}
}
I mean, there in no reason to have a different message for an OutOfHoneyException, is there?
When you pass the message to the base class(Exception), the base class will set Message property of your exception and do all helpful stuff like keeping StackTrace.
So when you catch your custom exception (OutOfHoneyException), the message field will be set by your base Exception class. Checkout the following code from implementation:
/// <summary>
/// Initializes a new instance of the <see cref="T:System.Exception"/> class with a specified error message.
/// </summary>
/// <param name="message">The message that describes the error. </param>
public Exception(string message)
{
base..ctor();
this.Init();
this._message = message;
}
/// <summary>
/// Initializes a new instance of the <see cref="T:System.Exception"/> class with a specified error message and a reference to the inner exception that is the cause of this exception.
/// </summary>
/// <param name="message">The error message that explains the reason for the exception. </param><param name="innerException">The exception that is the cause of the current exception, or a null reference (Nothing in Visual Basic) if no inner exception is specified. </param>
public Exception(string message, Exception innerException)
{
base..ctor();
this.Init();
this._message = message;
this._innerException = innerException;
}
Rather than write an answer telling you how to create an exception I am going to try and answer your specific questions.
And why are we passing the message to the base Exception class? Is it only for printing purpose?
More or less. The message is to add context to the exception. There could be several reasons why the OutOfHoneyException is thrown - the bees are asleep, they are on holiday, an anteater ran out of ants and decided he liked bees instead, etc.
There is a OOPS concept for child class calling base class constructor. Could you please name it and how it is related to custom exceptions example?
No matter which constructor you use on the derived class the default constructor will always be called on the base class unless you specify a different one (which is what is happening here). This is basic constructor overloading which gives you a reasonable amount of flexibility when creating derived classes (also note that there is constructor chaining).
I currently have a class written in C# which does some simple error logging stuff. It's been used quite extensively throughout my project.
class LogError
{
//constructor
public LogError() { }
//public methods
public void saveToTextFile() { }
//other similar methods...
}
But, it doesn't seems a good design of this class, as every time I have to create an instance of LogError class before saveToTextFile() method can be used.
So I am thinking of re-designing this class. Would this be a good case to apply Singleton pattern? What about making it static class instead? Any suggestions? Thanks.
The problem with Singleton is that it's hard to use different logging behaviour. Image you want to introduce a "Send an email instead of write to text file" later. It's basically the same if you have
new LogError().DoSomething();
or
LogError.Instance.DoSomething();
except for performance and/or implementation of the LogError class itself.
If you want to add flexibility, you'd better use Dependency Injection (which makes your code clearer than with the Singleton, in addition) or Dependency Lookup (which is somewhere in between).
I would look at Apache log4net. You don't have to worry about anything. You can configure it to log to multiple targets from your configuration file (or in code). The log message template is fully customizable. You can filter and route different log levels (debug/info/warning/error). It's really not worth reinventing the wheel here.
Yes make it singleton and also thread safe
If you are using , any container ( Autofac, Unity etc) then you can make use of the container.
Singleton can be broken ( By using Reflection so be informed )
one of the implementation would be ( this would not required explicit locking )
public class MySingleton
{
private static readonly MySingleton _singtonInstance = new MySingleton();
private MySingleton()
{
}
public static MySingleton SingtonInstance
{
get { return _singtonInstance; }
}
}
You can use interface as your log system facade, like
interface ILoggerFacade{
void Error(Exception e);
void Warning(Exception e);
....
}
after that you need to make interface implementation
class SimpleLogger:ILoggerFacade{
void Error(Exception e){//logging error};
...
}
and finnaly you need enter point to your logger. I ussually use static class but singleton is variant also.
static class sample:
class StaticLogger{
private ILoggerFacade _logger;
StaticLogger(){
//choose ILoggerFacade implementation
_logger=new SimpleLogger();
}
public static ILoggerFacade Logger{
get{ return _logger;}
}
}
If you will use facade interface you can easy change loggers in your project if it will be need.
There is a solution where you have a logging method that is being called once there are exceptions happen anywhere in your application. All you need to have is a general or common exception handler. Here's how.
On your Program.cs (inside your Main() method before the Application.Run) add this code.
Application.ThreadException += CommonExceptionHandler;
Create CommonExceptionHandler event on your Program.cs file let's say next to Main method.
private static void CommonExceptionHandler(object sender, ThreadExceptionEventArgs t)
{
LogError(t.Exception);
}
Create LogError Method on your Program.cs
public static void LogError(Exception ex)
{
var errMsg = ex.Message;
errMsg += ex.InnerException != null ? ex.InnerException.Message : string.Empty;
//TODO: Do what you want if an error occurs
}
This will catch all exceptions occur in your application. You don't need to worry anymore whether you would call your error log class for every catch block in all of your methods