Thursday, November 26, 2009

Use TraceSource and traceListeners in .NET 2.0

The first part contains the C# code that writes trace events to TextWriterTraceListener, ConsoleTraceListener and EventLogTraceListener. The second part does exactly the some thing but using configuration file to achieve it.
-----------
Part 1
-----------
//using System;
//using System.Diagnostics;
private static void TraceTest()
{
TraceSource ts = new TraceSource("TestConsole");
SourceSwitch sw = new SourceSwitch("testSwitch");
//the level determines what events are sent to listerners,
//currently events level of Information and up.
sw.Level = SourceLevels.Information;
ts.Switch = sw;

//Remove the default DefaultTraceListener
ts.Listeners.Clear();

TextWriterTraceListener twtl= new TextWriterTraceListener(@"testLog.log");
twtl.Name = "text";
//Events of Warning level or up are written to log file
EventTypeFilter etf1 = new EventTypeFilter(SourceLevels.Warning);
twtl.Filter = etf1;
ts.Listeners.Add(twtl);

// set false to write to standard output stream
ConsoleTraceListener ctl = new ConsoleTraceListener(false);
ctl.Name = "console";
//Events of Information level or up are written to console
EventTypeFilter etf2 = new EventTypeFilter(SourceLevels.Information);
ctl.Filter = etf2;
ts.Listeners.Add(ctl);

//An event log source should not be created and immediately used.
//There is a latency time to enable the source, it should be created
//prior to executing the application that uses the source.
//To create an event source in Windows Vista, Windows XP Professional,
//or Windows Server 2003, you must have administrative privileges.
//MySource is the source used in code to reference the new event log.
//MyNewLog is the name shown in the Event View
//Run the following line only once and set a break point after it to allow enough time to create the event log
EventLog.CreateEventSource("MySource", "MyNewLog");

EventLogTraceListener evetl = new EventLogTraceListener("MySource");
evetl.Name = "eventLog";
//Events of Error level or up are written to event log
EventTypeFilter etf3 = new EventTypeFilter(SourceLevels.Error);
evetl.Filter = etf3;
ts.Listeners.Add(evetl);
//TraceEventType used here is first filtered by sw.Level
//to determine if the trace event should be sent to a listener.
//The TraceEventType has to be at the sw.Level or up to be sent.
//When a listener receives the event, it outputs only those events
//to which the listener's filter(s) matches. If no filter is defined
//on the filter, the listener outputs all events that send to it.
ts.TraceEvent(TraceEventType.Error, 1, "error message");
ts.TraceEvent(TraceEventType.Warning, 2, "warning message");
ts.TraceEvent(TraceEventType.Information, 3, "information message");
ts.Flush();
ts.Close();
}

----------
Part 2
---------
//using System;
//using System.Diagnostics;
private static void TraceTest()
{
TraceSource ts = new TraceSource("TestConsole");

ts.TraceEvent(TraceEventType.Error, 1, "error message");
ts.TraceEvent(TraceEventType.Warning, 2, "warning message");
ts.TraceEvent(TraceEventType.Information, 3, "information message");

ts.Flush();
ts.Close();
}
---- Code above uses the configuration settings below ---
<system.diagnostics>
    <sharedListeners>
        <add name="text" type="System.Diagnostics.TextWriterTraceListener" initializeData="testLog.log">
            <filter type="System.Diagnostics.EventTypeFilter" initializeData="Warning" />
        </add>
        <add name="console" type="System.Diagnostics.ConsoleTraceListener" >
            <filter type="System.Diagnostics.EventTypeFilter" initializeData="Information" />
        </add>
        <add name="eventLog" type="System.Diagnostics.EventLogTraceListener"          initializeData="MyNewLog">
            <filter type="System.Diagnostics.EventTypeFilter" initializeData="Error" />
        </add>
    </sharedListeners>
    <sources>
        <source name="TestConsole" switchName="testSwitch" switchType="System.Diagnostics.SourceSwitch">
            <listeners>
                <add name="text" />
                <add name="console" />
                <add name="eventLog" />
                <remove name="Default"/>
            </listeners>
       </source>
    </sources>
    <switches>
           <add name="testSwitch" value="Information"/>
    </switches>
</system.diagnostics>

Thursday, November 19, 2009

Using fuslogvw.exe on Windows 2008

1. Set Registry key:
C:\mytemp>reg add HKLM\Software\Microsoft\Fusion /v EnableLog /t REG_DWORD /d 1
The operation completed successfully.

2. Right click Visual Studio 2008 command Prompt and select Run as Administrator to open command window.
C:\Program Files\Microsoft Visual Studio 9.0\VC>fuslogvw.exe will open the tool.

3. Keep all default settings. Click Settings click Log All Bindings to Disk then select Enable custom log path. Enter a valid folder path such as "c:\MyFusionLog" in the Custom log path textbox. Make sure the folder is empty. When it starts to work, you can change the log setting as you desired.

4. Give full access to "c:\MyFusionLog" folder for Administrator account which should be the account you are running under.

5. Run a .Net application then click Refresh button to view binding log entries. Clicking each entry will open browser based log views which are stored under "c:\MyFusionLog\default"

Wednesday, November 18, 2009

Assembly Binding - Probing

Search Steps :

Determine the right version by using publisher policy file and configuration files

Search Global assembly cache

<CodeBase> defined in policy file overwrite the one defined in configuration file below

<Configuration><Runtime><AssemblyBinding><DependentAssembly><CodeBase> defined in configuration file.The url could be location in the intranet or internet, but the referenced assemply must be strongly named. Otherwise (private assembly) the url must be relative to the application directory.

If culture is included, following folders are searched:
[application base] / [culture] / [assembly name].dll [application base] / [culture] / [assembly name] / [assembly name].dll

Without culture, following folders are searched:
[application base] / [assembly name].dll
[application base] / [assembly name] / [assembly name].dll

<Configuration><Runtime><AssemblyBinding><DependentAssembly><Probing>: semicolon seperated paths below application base defined by AppDomain.CurrentDomain.BaseDirectory. When defined, followng folders are searched:
If culture is included, the following directories are probed:
[application base] / [binpath] / [culture] / [assembly name].dll
[application base] / [binpath] / [culture] / [assembly name] / [assembly name].dll
If culture information is not included, the following directories are probed:
[application base] / [binpath] / [assembly name].dll
[application base] / [binpath] / [assembly name] / [assembly name].dll

If an assembly uses the LoadFrom method to reference another assembly, the calling assembly's location is considered to be a hint about where to find the referenced assembly (this would be in different loading context from above).

Saturday, November 14, 2009

Type.FindMembers Method Explained

Syntax

public virtual MemberInfo[] FindMembers
(
     MemberTypes memberType,
     BindingFlags bindingAttr,
     MemberFilter filter,
     Object filterCriteria
)
MemberTypes enum: type of members to be included such as Constructor, Field, Method;
BindingFlags enum (FlagAttributes=bitwise combination): Flags to define the scope of members to be   included. Must specify Instance or Static along with Public or NonPublic or no members will be returned.
MemberFilter delegate: Used to filter qualified members based on the filterCriteria.
public delegate bool MemberFilter
(
     MemberInfo m,
     Object filterCriteria
)
Each qualified member (passed as MemberInfo) is compared to filterCriteria and included in the output if the comparison returns true.
The filter can be obtained from: Type.FilterAttribute, Type.FilterName, Type.FilterNameIgnorCase.
TheFilterAttribute uses the fields of FieldAttributes, MethodAttributes, and MethodImplAttributes as search criteria, and the other two delegates use String objects as the search criteria
Object filterCriteria: Passed into MemberFilter as filterCriteria. Its value depends on the type of filter used as described above. This parameter is more powful when used with FilterName and FilterNameIgnorCase since it can take the wild card form like "*" or "fun*".

Example
public class c1
{
     private int privateF1;
     public static int publicF1=2;
     public void method1(){ }
     private void method12(){ }
     private void method2(){ }
}
MemberInfo[] mi =
typeof(c1).FindMembers(MemberTypes.Field, BindingFlags.Public |

BindingFlags.Static, Type.FilterAttribute, FieldAttributes.Public);

// mi includes a single memeber: publicF1

MemberInfo[] mi =
typeof(c1).FindMembers(MemberTypes.Method, BindingFlags.Public |

BindingFlags.NonPublic |
BindingFlags.Instance, Type.FilterName, "method1*");

//mi includes two members: method1 and method12

jw