In this Article we have these technical points:
1- What is a plug-in? and how to be implemented in out case (Logging Plugin Manager)?<o:p __designer:dtid="1407374883553308">
2- What will be the benefits of implementing singleton pattern in our case?<o:p __designer:dtid="1407374883553315">
3- How to load assemlies dynamically in a configurable way?<o:p __designer:dtid="1407374883553322">
4- How to configure MSEL 2 Logging block on the fly without need for the pre-setting with MS configuraiton tool?<o:p __designer:dtid="1407374883553329">
<o:p __designer:dtid="1407374883553332">
What is a plug-in? and how to be implemented in out case (Logging Plugin Manager)?<o:p __designer:dtid="1407374883553337">
.NET allows the dynamic loading of assemblies that is necessary for a good plug-in implementation.
Plug-in systems provide extensibility and flexibility. By using our Plug-in we will be able to attach more than implementation for many logging 3rd parties. And use the selector to select or activate one of them. <o:p __designer:dtid="1407374883553342">
<o:p __designer:dtid="1407374883553345">
How to build a plug-in?<o:p __designer:dtid="1407374883553349">
This part contains a lot of old and well known information; but it is nice chance to refresh our knowledge. <o:p __designer:dtid="1407374883553352">
The first step in making the logging plug-in, after creating a solution workspace, is to create a common project LoggingManager.ExceptionsHandlerInterface. You'll use it to hold classes that will be accessed by both the plug-ins and the application that calls them. The object of doing this is to keep the dependencies down; there is little advantage in creating plug-ins if the application has to refer to the plug-in project to compile or run.<o:p __designer:dtid="1407374883553355">
<o:p __designer:dtid="1407374883553358">
The interface used here is IExceptionsHandler. interface has a main method: Log() with 4 overloads:<o:p __designer:dtid="1407374883553361">
1- Simple logging with only choosing the target. <o:p __designer:dtid="1407374883553364">
bool Log(LogTarget oLogTarget, string LoggedString);<o:p __designer:dtid="1407374883553370">
<o:p __designer:dtid="1407374883553373">
2- Logging with choosing the target and the severity level. <o:p __designer:dtid="1407374883553376">
bool Log(LogTarget oLogTarget, string LoggedString, LoggedDataLevel oLoggedDataLevel);<o:p __designer:dtid="1407374883553383">
<o:p __designer:dtid="1407374883553386">
3- Logging with choosing the target and type for the logged info.<o:p __designer:dtid="1407374883553389">
bool Log(LogTarget oLogTarget, string LoggedString, LoggedDataType oLoggedDataType);<o:p __designer:dtid="1407374883553396">
<o:p __designer:dtid="1407374883553399">
4- Logging with choosing the target and type for the logged info and everity.<o:p __designer:dtid="1407374883553402">
bool Log(LogTarget oLogTarget, string LoggedString, LoggedDataType oLoggedDataType, LoggedDataLevel oLoggedDataLevel); <o:p __designer:dtid="1407374883553411">
<o:p __designer:dtid="1407374883553414">
<o:p __designer:dtid="1407374883553417">
Now I would like to attach some of 3rd parties logging tools and dlls to my project . <o:p __designer:dtid="1407374883553421">
For each tool (log4net and MSEL for example): I will create its own plug-in (interface implementation).<o:p __designer:dtid="1407374883553426">
Each plug-in is in its own separate project, as it will be in its own assembly that is loaded by the application. The project for each plug-in uses a project reference to refer to the main interface.<o:p __designer:dtid="1407374883553431">
So we will create a project LoggingManager.MSELexpceptionsHandling and implement our logging interface in the class MSELExceptionsHandler.cs<o:p __designer:dtid="1407374883553435">
<o:p __designer:dtid="1407374883553438">
What will be the benefits of implementing singleton pattern in our case?<o:p __designer:dtid="1407374883553443">
Why to use Singleton pattern or model ?<o:p __designer:dtid="1407374883553447">
To ensure that a class has only one instance and provide a global point of access to it.<o:p __designer:dtid="1407374883553450">
<o:p __designer:dtid="1407374883553453">
How to Implement Singleton ? <o:p __designer:dtid="1407374883553459">
1- Simply by making a static global instance of the class and check is it found or not? For example the next code:<o:p __designer:dtid="1407374883553466">
class Singleton
{
private static Singleton instance;\\private variable declared
// Note: Constructor is 'protected'
protected Singleton()
{
}
public static Singleton Instance()\\property declared which is used to access the privateVariable
{
// Use 'Lazy initialization'
if (instance == null)
{
instance = new Singleton();
}
return instance;
}
}<o:p __designer:dtid="1407374883553489">
2- Or by making a static constructor or Static ctor <o:p __designer:dtid="1407374883553496">
<o:p __designer:dtid="1407374883553499">
And in our application we used Static ctor because it is thread safe according to ECMA standard section 9.5.3 For More information take a look at this page. <o:p __designer:dtid="1407374883553502">
http://jilc.sourceforge.net/ecma_p2_cil.shtml#_Toc524940486 <o:p __designer:dtid="1407374883553507">
How to load assemlies dynamically in a configurable way?<o:p __designer:dtid="1407374883553514">
In the configuration file (for example web.config or app.config) we define the assembly name for each of our plugins:<o:p __designer:dtid="1407374883553517">
<add key="MSELPlugin" value="MSELexpceptionsHandling.dll"/><!-- MSLE Plugin --><o:p __designer:dtid="1407374883553534">
<add key="Net4LogPlugin" value="N4LexpceptionsHandling.dll"/><!-- N4L Plugin --><o:p __designer:dtid="1407374883553551">
<o:p __designer:dtid="1407374883553554">
Then we have a selector Key (this key will be the key which is called from our code) <o:p __designer:dtid="1407374883553557">
And set its value with the desired plug-in name. <o:p __designer:dtid="1407374883553560">
<add key="SelectedExHPlugin" value="MSELPlugin"/><!--MSLE Plugin--><o:p __designer:dtid="1407374883553575">
<o:p __designer:dtid="1407374883553578">
Then our call in the code will be simply finding the value of this key:<o:p __designer:dtid="1407374883553581">
// Read the selected plugin (web config key) from the web config <o:p __designer:dtid="1407374883553584">
string strSelectedExHPlugin = ConfigurationManager.AppSettings["SelectedExHPlugin"];<o:p __designer:dtid="1407374883553590">
<o:p __designer:dtid="1407374883553593">
Finally we build our configurable solution <o:p __designer:dtid="1407374883553596">
<v:shapetype id="_x0000_t75" __designer:dtid="1407374883553599" coordsize="21600,21600" o:spt="75" o:preferrelative="t" path="m@4@5l@4@11@9@11@9@5xe" filled="f" stroked="f"><v:stroke joinstyle="miter"><v:formulas><v:f eqn="if lineDrawn pixelLineWidth 0"><v:f eqn="sum @0 1 0"><v:f eqn="sum 0 0 @1"><v:f eqn="prod @2 1 2"><v:f eqn="prod @3 21600 pixelWidth"><v:f eqn="prod @3 21600 pixelHeight"><v:f eqn="sum @0 0 1"><v:f eqn="prod @6 1 2"><v:f eqn="prod @7 21600 pixelWidth"><v:f eqn="sum @8 21600 0"><v:f eqn="prod @7 21600 pixelHeight"><v:f eqn="sum @10 21600 0"><v:path o:extrusionok="f" gradientshapeok="t" o:connecttype="rect"><o:lock v:ext="edit" aspectratio="t">
<o:p __designer:dtid="1407374883553601">
<o:p __designer:dtid="1407374883553604">
How to configure MSEL 2 Logging block on the fly without need for the pre-setting with MS configuraiton tool?<o:p __designer:dtid="1407374883553607">
<o:p __designer:dtid="1407374883553610">
What will the benefits which we will gain from using this methodology ?<o:p __designer:dtid="1407374883553614">
1- Simply we will put our known readable keys in our web/app.config file for example:<o:p __designer:dtid="1407374883553617">
<o:p __designer:dtid="1407374883553620">
<add key="LoggingFile" value="c:\Logging.txt"/><o:p __designer:dtid="1407374883553633">
<add key="LoggingFileSeperator" value="--------------------"/><o:p __designer:dtid="1407374883553647">
<o:p __designer:dtid="1407374883553650">
Wihtout need to use the external tool or know external XML scehams and node will be added in external config file or evern our web/app.config file. <o:p __designer:dtid="1407374883553653">
<o:p __designer:dtid="1407374883553656">
2- We will use more Sink (event logging method : event viewer ; file ; mail etc) in a more simple parameterized way without setting up policies and choose policies from the code. <o:p __designer:dtid="1407374883553659">
We will simply build our LoggingType enum and choose the suitable value to log from its values. <o:p __designer:dtid="1407374883553662">
<o:p __designer:dtid="1407374883553665">
Then how to configure the MSEL on the fly?<o:p __designer:dtid="1407374883553668">
Special thanks for Alois Kraus for his most valuable article on his blog:
http://geekswithblogs.net/akraus1/archive/2006/02/16/69784.aspx
<o:p __designer:dtid="1407374883553676">
We built our ConfigLessLogger to configure the MSEL programatically (Add/Remove/Choose sinks)
Then we built an overlay class which is the implementer of our main logging interface. MSELExceptionsHandler.cs which will be used to build our MSEL assembly plugin; then we programmatically load this assembly from our code:
<o:p __designer:dtid="1407374883553684">
// use the returned web-config key name from the above step in getting the assembly name of <o:p __designer:dtid="1407374883553687">
// the selected implementation for the base ExH interface from the web config.<o:p __designer:dtid="1407374883553690">
System.Reflection.Assembly asmSelectedPlugin = System.Reflection.Assembly.LoadFrom(ConfigurationManager.AppSettings[strSelectedExHPlugin]);<o:p __designer:dtid="1407374883553697">
<o:p __designer:dtid="1407374883553700">
I hope that you Enjoy the code J