The new Enterprise Library for .NET 2.0 has disabled instrumentation by
default.
It is very reasonable to do this because in low trust scenarios you are
not able to install Performance Counters, Windows Event Logs/Sources or
update
WMI schemas. The previous version had "configurable" instrumentation by
some #ifdefs in the source code. To change instrumentation you had to
recompile
the whole library every time you wanted to target a different
deployment and therefore
trust scenario. This time the Enterprise Library team had more time to
make it
really configurable. The outcome is remarkable easy to use. You can
enable/disable the following
instrumentation settings:
- Error logging of all Application Blocks to the Windows
Event Log.
- Performance Counter writes.
- Firing of WMI Events.
To configure Instrumentation you can use in the Enterprise Library
Configuration Tool.
Use the context menu to add a new "Application Block" which is named
Instrumentation.
You can now enable WMI, Error Event Logging or Performance Counters by
editing a config file. This time no recompilation of the library is
necessary. This is really great work from the Patterns &
Practices Team at Microsoft.

The following table lists the WMI events that are fired by the
application blocks when WMI is enabled.
All event classes are registered under the WMI namespace
root/EnterpriseLibrary.
| WMI Event |
Properties |
|
Used by Application Block |
| AuthorizationCheckPerformedEvent |
UserName, TaskName, InstanceName |
|
Security |
| AuthorizationCheckFailedEvent |
UserName, TaskName, InstanceName |
|
Security |
| SecurityConfigurationFailureEvent |
ExceptionMessage, InstanceName |
|
Security |
| SecurityCacheReadPerformedEvent |
EntityType, TokenUsed, InstanceName |
|
Security |
| LoggingConfigurationFailureEvent |
ExceptionMessage |
|
Logging |
| LoggingFailureLoggingErrorEvent |
ErrorMessage, ExceptionMessage |
|
Logging |
| LogEntryV20 |
All public properties of LogEntry object. Fired by
WmiTraceListener |
|
Logging |
| ConnectionFailedEvent |
ConnectionString,
ExceptionMessage, InstanceName |
|
Data |
| CommandFailedEvent |
CommandText, ConnectionString,
ExceptionMessage, InstanceName |
|
Data |
| DataConfigurationFailureEvent |
ExceptionMessage, InstanceName |
|
Data |
| CacheFailureEvent |
ErrorMessage, ExceptionMessage,
InstanceName |
|
Caching |
| CacheScavengedEvent |
ItemsScavenged, InstanceName |
|
Caching |
| CacheCallbackFailureEvent |
Key, ExceptionMessage, InstanceName |
|
Caching |
| CacheConfigurationFailureEvent |
ExceptionMessage, InstanceName |
|
Caching |
| ExceptionHandlingConfigurationFailureEvent |
PolicyName, ExceptionMessage |
|
Exception Handling |
| ExceptionHandlingFailureEvent |
ExceptionMessage, InstanceName |
|
Exception Handling |
| SymmetricOperationFailedEvent |
ErrorMessage, ExceptionMessage,
InstanceName |
|
Cryptography |
| HashMismatchDetectedEvent |
InstanceName |
|
Cryptography |
| CryptographyConfigurationFailureEvent |
ExceptionMessage, InstanceName |
|
Cryptography |
How to listen to a WMI Event
The following sample code shows how to listen to one WMI event fired by
the
Enterprise Library. Additonally a new WMI Event is defined and fired
(not the Enterprise Library way).
using System;
using
System.Management.Instrumentation;
using
System.Management;
using System.ComponentModel;
using
System.Configuration.Install;
// WMI Schema
namespace (normally defined in AssemblyInfo.cs
[assembly: Instrumented("root/EnterpriseLibrary")]
// You need to add the default installer
to your project to be able to add your own WMI event to the system
during install
[RunInstaller(true)]
public
class Installer
: System.Management.Instrumentation.DefaultManagementProjectInstaller
{
}
// define our
own WMI Event
[InstrumentationClassAttribute(InstrumentationType.Event)]
public class
EntlibStartEvent
{
public
string
startMessage;
}
class WmiListener
{
public
static int
Main(string[] args)
{
// you could listen to your
own event by using
EntlibStartEvent as input for the WqlEventQuery
WqlEventQuery
eventQuery = new
WqlEventQuery("LogEntryV20"); //
fired by WMI Trace Listener of Logging Block
ManagementEventWatcher
watcher = new ManagementEventWatcher(new ManagementScope(@"root\EnterpriseLibrary"),
eventQuery);
watcher.EventArrived
+= new EventArrivedEventHandler(Arrived);
watcher.Start();
// fire our own WMI
event
for (int i = 0; i
< 100; i++)
{
EntlibStartEvent
cl = new
EntlibStartEvent();
cl.startMessage
= "Speeding up development";
System.Management.Instrumentation.Instrumentation.Fire(cl);
}
// Wait some time to give the
delegate a chance to recieve
events
System.Threading.Thread.Sleep(20000);
// You must stop it every
time. Otherwise you will get
errors RPC not availiable
// from the WMI service!
Remember this even when you debug.
watcher.Stop();
return 0;
}
public
static void
Arrived(object
sender, EventArrivedEventArgs
e)
{
ManagementBaseObject
ev = e.NewEvent;
if (ev != null)
{
// print all properties of the WMI
event
foreach (PropertyData
data in
ev.Properties)
{
Console.WriteLine("{0}:[\"{1}\"]:
{2}", data.Origin, data.Name, data.Value);
}
}
}
}
WMI Security Issues
Unexpected Security exceptions can be really frustrating. To prevent
further pain I share some of the experiences I made with WMI.
- Only the administrator can (should be able to) update the
WMI schema.
- Before you can fire WMI events you must update the WMI
schema by calling installutil <YourAssemblyName>
- Every ManagementEventWatcher instance which has called
Start must
call Stop or the WMI Service will go down. This is especially bad when
you debug.
To configure WMI security you need to find the WMI administration tool
in the first place. It is well hidden
in the Control Panel -> Administrative Tools -> Computer
Management then right click on WMI and select "Properties" from
the context menu. Alternatively you can start the MMC snapin from the
command line with wmimgmt.msc. The WMI database is
organized in logical namespaces. Here you can allow/deny access
to all WMI namespaces and below or only a specific namespace. Below is
a screen shot of the WMI security configuration
tool.

Performance Counters
They can help you to find in deployment scenarios possible
performance bottlenecks
or if the system does function properly.
To get an
overview of your current system status you can use Perfmon of Windows
or one of the many free resource measurement programs. Programmatic
access is possible but
a little more difficult since Performance Counters are instance
specific. The Enterprise
Library Performance Counters have as instance name the executable name
plus a postfix. You need to know
what instance name your counter of interest has to read from it. Below
is a small code example how to access a Windows Performance Counter
from C#
PerformanceCounter
PC = new
PerformanceCounter();
PC.CategoryName
= "Process";
PC.CounterName =
"Private Bytes";
PC.InstanceName
= "Explorer";
MessageBox.Show(PC.NextValue().ToString());