C# how to log file inside a DLL? - c#

I'm developing a DLL and I want to log some data it generates.
I wanted to use "Log4Net", but I found the problem that in a DLL I don't have an "App.config" file where I can write the XML code, so I don't know how to implement this (I'm new in this matters).
I read about "Singleton" but I saw it's better to avoid it since it has it's issues (i.e hide some visibility of the code, problems with unit tests, ...).
So my question is: How and what is the best way to create a log file for the data generated by my DLL?

A DLL - a class library - should never be logging by itself. Even the ones that are there for output - like the one containing Console or even logger code - should never decide to write their own logfile. Logging work - all output work - that is not controllable or even fully controlled by the programmer using your DLL, is just going to be vexing behavior. And you should never write something with Vexing behavior.
Logging is the job of the person using your code, not of your code. If you are writing a Library or really anything else that usually has no output (like a Windows Service), it is customary to have a wrapper project for debugging and testing.
If it is important enough it warants an Exception. If it is not important enough for a Exception - it is propably not important enough at all. It is a daunting challenge to write good Exception handling, nevermind good Exception throwing code. But there are two articles on the mater that I link very often. And I really think would help you get you on the right paths:
https://blogs.msdn.microsoft.com/ericlippert/2008/09/10/vexing-exceptions/
https://www.codeproject.com/Articles/9538/Exception-Handling-Best-Practices-in-NET
They really helped me get a handle on it. And thus far they helped countless others. And their ideas are not even tied to .NET only.

The config file will be connected in running module.
It will be in exe file if it's a console application,
or in web.config in case of web application.

To log the application flow in the DLL,
Just create a Class that create and access the log text file.
In that class, declare the object LoggingClass loggingObject; and then use this instance to access the log file.
In creating object for it, you can use,
public static LoggingClass createOrGetObject()
{
return (loggingObject == null)? new LoggingClass() : loggingObject;
}
Now, just you can call this method to get the same instance that access the log file to write the log.
In this example, Log4Net is not used but works fine for logging.

You don't say who you expect to use your dll.
If it will be used by lots of other people and if the logging is useful to them, then may not want to be forced to use log4net or this may cause problems if they want to use a different version of log4net than you are using.
I have seen several dlls which use Common.Logging to avoid this issue which allows the consumers to use whichever logging package they want.
Having said that, see Configure log4net logging in dll for another possible solution.

Related

What is the similar alternative for VB App.StartLogging and App.LogEvent in .Net C#?

I have to implement equivalent code of Visual Basic "App.StartLogging" and "App.LogEvent" in .NET C#.
App.StartLogging has the two parameters i.e. logTarget and logMode.
(https://learn.microsoft.com/en-us/previous-versions/visualstudio/visual-basic-6/aa267165(v=vs.60))
I tried to find out same type of logging event in C#, but unfortunately not able to get.
System.
On some website, found like System.Diagnostics.EventLog is the alternate of App.StartLogging.
But not getting how ? App.StartLogging help to log data in local file, but i didn't get same behavior in System.Diagnostics.EventLog.
Can you please help me to solve my issue ?
There is no direct replacement, see https://www.vbmigration.com/resources/detmigratingfromvb6.aspx?Id=19,
A few App members are used to log application events - namely the LogMode and LogPath properties and the StartLogging and LogEvent methods. These members have no direct counterparts in the .NET Framework.
You will other have to write your equivalents, or pick a 3rd party logging tool that can do what you need.
For instance, nLog will allow you to log to both the file system and to the Event Viewer. Logging an event is simple you simply write to the log, the StartLogging event is going to be harder, I don’t know of any logging framework or library that creates an event for that, typically it starts before everything else.

How to handle dll dependency that may not be present? [duplicate]

I am not sure the best way to explain this so please leave comments if you do not understand.
Basically, I have a few libraries for various tasks to work with different programs - notification is just one example.
Now, I am building a new program, and I want it to be as lightweight as possible. Whilst I would like to include my notification engine, I do not think many people would actually use its functionality, so, I would rather not include it by default - just as an optional download.
How would I program this?
With unmanaged Dlls and P/Invoke, I can basically wrap the whole lot in a try/catch loop, but I am not sure about the managed version.
So far, the best way I can think of is to check if the DLL file exists upon startup then set a field bool or similar, and every time I would like a notification to be fired, I could do an if/check the bool and fire...
I have seen from the debug window that DLL files are only loaded as they are needed. The program would obviously compile as all components will be visible to the project, but would it run on the end users machine without the DLL?
More importantly, is there a better way of doing this?
I would ideally like to have nothing about notifications in my application and somehow have it so that if the DLL file is downloaded, it adds this functionality externally. It really is not the end of the world to have a few extra bytes calling notification("blabla"); (or similar), but I am thinking a lot further down the line when I have much bigger intentions and just want to know best practices for this sort of thing.
I do not think many people would
actually use its functionality, so, I
would rather not include it by default
- just as an optional download.
Such things are typically described as plugins (or add-ons, or extensions).
Since .NET 4, the standard way to do that is with the Managed Exensibility Framework. It is included in the framework as the System.ComponentModel.Composition assembly and namespace. To get started, it is best to read the MSDN article and the MEF programming guide.
You can use System.Reflection.Assembly and its LoadFile method to dynamically load a DLL. You can then use the methods in Assembly to get Classes, types etc. embedded in the DLL and call them.
If you just check if the .dll exists or load every .dll in a plugin directory you can get what you want.
To your question if the program will run on the user's machine without the dlls already being present - yes , the program would run. As long as you dont do something that needs the runtime to load the classes defined in the dll , it does not matter if the dll is missing from the machine. To the aspect you are looking for regarding loading the dll on demand , I think you are well of using some sort of a configuration and Reflection ( either directly or by some IoC strategy. )
Try to load the plugin at startup.
Instead of checking a boolean all over the place, you can create a delegate field for the notification and initialize it to a no-op function. If loading the plugin succeeds, assign the delegate to the plugin implementation. Then everywhere the event occurs can just call the delegate, without worrying about the fact that the plugin might or might not be available.

Can I track the use of ConfigurationManager settings

I am trying to clean up the web.config in multiple projects, but am worried that I may remove an appsetting/connectionstring that is being used somewhere.
For example, I want to know if ConfigurationManager.AppSettings["MySetting"]) is used.
I can of course do a global find for ConfigurationManager or Appsettings, but that doesn't check in compiled dlls (this project has some dlls referenced that i know are looking for certain keys).
I would love to be able to 'log' (text file, db, anywhere) the use of the .config file, minimally logging the key name, but ideally the namespace/method that called it. If this is possible, I could come back in some amount of time and check the log to see what is used.
Deleting the settings and seeing if the app throws an exception is tempting :), but not a realistic option.
Thanks in advance!
You can try to use aspect to log that a method was called.
I'm not sure if you will be able to get which configuration or key was retrieved but having all the places that's called is already a starting point.
Hope that helps.
Give a try for PostSharp or Unity.

Design principles to consider when wrapping a 3rd party logger like log4net

I'm creating a logger for a company that has several types of .NET projects (Windows Services, ASP.NET, etc), and I was considering using log4net as my logger, but I don't want to be married to log4net, so I was thinking of wrapping it in my own assembly. I realize some developers don't recommend wrapping log4net because that would be an anti-pattern, but assuming I was going that route anyway, I had some questions:
I am planning to use the design principles mentioned in this article to design my wrapper (using factory method, interfaces, and reflection, I can simply decide which logger I want to use (whether log4net, elmah or something else) by specifying in the config file:
https://www.simple-talk.com/dotnet/.net-framework/designing-c-software-with-interfaces/
Question is:
Should I create this logger project in a separate Visual Studio solution and just use the dll in my client applications? If so, where would the configuration details for log4net go? Would that be supplied by the client application's config file? If so, is that good design? For instance, if I decided to switch away from log4net to a different logging framework, I would not only have to change the config setting to specify the new concrete logger's assembly/class name, but would also have to remove the log4net config entries (and perhaps add the new logger's config entries). Is this considered as an acceptable design approach?
Oh my goodness your timing is awesome. And that article is very relevant to me so thanks! I am doing this very same thing right now. I realized that log4net is a decent logger, but a terrible library for making a logger.
I agree with the article, in that you should not directly expose to log4net. Unless this is a small app it would be too difficult to switch later. And log4net is showing age so that may happen. I like the interface approach overall.
But, wrapping log4net it is a pain in the butt. So in doing my prototype wrapper I feel like I rewrote 50% of log4net, and discarded 25%. Some issues I found:
log4net will grab the "caller information" for you. Normally that is great. But if you wrap log4net, the caller information will point to your logger. So you will have to explicitly grab it yourself. But log4net doesn't provide a way for you to override the caller information. So now you will have to create your own fields for the caller's file, line number, class, and package. Thus, not only do you not gain the benefit here, but it is actually more work than just doing it yourself.
Log4net uses the old pre C#-4.0 method of grabbing the caller information which is slow.
Your will be unable to completely wrap log4net without wrapping the configuration. The caller has to configure the loggers either in code or in their app.config. If they do it in their app.config then they are putting log4net specific stuff in their app, so you failed to hide it with your wrapper. But if you have your wrapper code automatically perform the configuration, you just lost the flexibility of log4net. The third option is to make your own configuration, but then what good did log4net do for you? You just rewrote another piece of it.
You are stuck with the log levels that come with log4net. In our app, we want "categories" instead of "levels" which I then have to map to the log4net "levels" under the hood. Now, all the predefined log4net filters are of no use to me.
Anyone using your wrapper still has to reference log4net in their project anyway.
If your wrapper needs a way to handle errors, or pass them back to the caller, you will have trouble. log4net has its own internal error handling and you will need to hook into that and provide your own. Otherwise, errors (like a misconfigured appender) will just go out to the console. If it was designed as a library for making loggers, it would just throw the exception back up or provide a simple event.
One thing we wanted to get out of log4net is the ability to write to different outputs without us us having to write that code ourselves. Ex: I've never written to the event log, and I think log4net can do that. But it might be easier for me to rip out the Event logging code, rather than to try and wrap that. Same thing with filters.
There are some other problems I had with log4net that aren't directly related to trying to wrap it necessarily.
The code is old. The interfaces don't use generics where they should. Lots of object.
They use the old System.Collections collections. Similar to #1.
It has ifdefs for .NET 1 versus 2, and ifdefs for the obsolete compact framework. ugh.
It is designed to log strings, not structured objects. I made my own code to do so, and so did these people: http://stephenjamescode.blogspot.com/2014/01/logging-custom-objects-and-fields-with.html and http://element533.blogspot.com/2010/05/mapping-message-object-properties-to.html but this feels like basic functionality.
It doesn't support CSV and it is cumbersome to add. http://element533.blogspot.com/2010/05/writing-to-csv-using-log4net.html
It doesn't have any kind of logging "service"
It doesn't provide a way to read or parse the log.
I found it was more effort to configure the appenders than to write your own. Ex: I mapped a bunch of fields to the AdoNetAppender, but it would have taken me less time to just rewrite AdoNetAppender. Debugging a database field mapping in XML is harder than trying to debug the equivalent C# + ADO.NET code. The XML is more verbose and less type safe. This might be specific to me because I had a very structured set of data and a lot of fields.
Sorry for the really long post, I have lots and lots of thoughts on this topic. I don't really dislike log4net, I just think it is out of date and if you are wrapping it, you might be better off writing your own.

Merging DLL's and changing managing namespaces

I want to create a single dll that is merged with a 3rd party dll. This means end consumers will only have to deal with 1 dll instead of 2.
For augments sake lets say that the 3rd party dll is nLog. How do I deal with cases where the consumer of the merged dll already has NLog as a reference in their project?
Ideally what I would like to be able to do is change NLog namespace within my project to "XyzNLog", meaning that the user wouldn't need to do any aliasing... Any idea how I might do this?
Now I know I can add aliases to my project for NLog so that I have to refer to it as XyzNLog, but I want the same to carry over to consumers of the merged dll so that there is never a conflict.
UPDATE - Solution
http://blog.mattbrailsford.com/2010/12/10/avoiding-dependency-conflicts-using-ilmerge/
Bingo! So by using ILMerge, it becomes
possible to merge the third-party
libraries DLLs in with the Providers
own DLL, meaning we will only have one
DLL to deploy. But that’s not all, we
can actually go one step further, and
tell ILMerge to internalize all
dependencies. What this does it
converts all the third party classes
to be declared as internal, meaning
they can only be used from within the
final DLL. Woo hoo! problem solved =)
Given this the problem where the consumer of my dll could also have NLog goes away... as my referenced NLog shifts to being all internal! This is exactly what I want.
Does anyone have any feedback or thoughts on this?
I agree with Hans, I would strongly suggest releasing with registering the DLLs separately.
Otherwise, you could be in DLL hell which would drive your consumers away.
You could then devise some clever deploy methods to detect if the DLL is already registered, etc.
I have to agree with #Hans Passant (and here's some info about the oft-discussed DLL hell), but since you've asked the question, I'll try to answer it.
You can bundle the third-party DLL as a resource. Please see this question for details.
As far as your other questions, I'd just expose the relevant classes from a third-party DLL under your own namespace, and maybe use extension methods to provide whatever additional functionality you want.
For instance, you can provide access to NLog's Log() method using a static method in your class, say XyzNLog.Logger.Log(), taking care of initialization, and whatever else internally, inside your code (static constructor or whatever else you fancy up).
Since you load the NLog assembly using the method above, you'll be the only one having access to the embedded NLog assembly directly and the user won't be able to access it. Now, you don't get the benefit of having all classes autoexposed from NLog, you still have to expose them manually in this case.
EDIT: Another approach would be to try to use ILMerge with /internalize flag as described here. You may not be able to completely resolve the issue, but look at this article to see if you can avoid the pitfalls the author described. Spoiler alert: it's not all peaches'n'cream on this one either, but it may work, with enough extra effort.

Categories

Resources