Posts
69
Comments
233
Trackbacks
162
April 2008 Entries
Enterprise Library 4 CTP - Improvements/Logging Application Block

The Enterprise Library 4 CTP and the feature list can be found at the Codeplex Home page.

General Features of Entlib 4 (Excerpt from Release Notes)

· Enterprise Library 4.0 takes advantage of the improved features in the .NET WMI 2.0 API to provide update capability for configuration exposed through the Manageable Configuration Source. Objects defined in the Enterprise Library configuration, such as databases, trace listeners, and cache backing stores, are exposed through WMI as a set of classes that you can query and update. Providing that you have the relevant Windows permission to update WMI values, any changes you make to the properties of these classes are reflected back through the Manageable Configuration Source and update the configuration information exposed to your application. Changes do not affect the original configuration file contents and may be overridden by Group Policy.

· In version 4.0, Enterprise Library has the Allow Partially-Trusted Caller attribute (APTCA) on all assemblies. This means that you can call the methods of Enterprise Library and the application blocks from an application running in a partial trust environment. You can do this with the signed assemblies provided with Enterprise Library. There is no longer any requirement, as there was in version 3.x, to recompile the source code and the source code for Object Builder then either use the unsigned binaries or strong-name them yourself.

That is good news for all medium trust ASP.NET web developers and Active Directory administrators that want to have an easy way to configure the application blocks in a central way.

New Logging Application Features (Excerpt from Release Notes)

· The application block now allows you to specify a value for the Filter property of each of the Trace Listeners. This property applies a filter that selects the level of message that it will detect. The valid values are All, Off, Critical, Error, Warning, Information, Verbose, and Activity Tracing. The setting effectively means "the specified level and everything more important." For example, the Warning setting will detect warnings, errors, and critical events. The default is All, which means that the behavior of the listener is the same as in previous versions of Enterprise Library if a value is not specified in the configuration.

· The application block now allows you to specify that the RollingFlatFileTraceListener will start a new file at midnight every day. To use this behavior, set the value of the RollInterval property of the RollingFlatFileTraceListener to Midnight.

· The application block contains performance improvements that include the following:

◦ Delayed gathering of context information until actually requested (except in distributed scenarios where context information is gathered even if not used).

◦ Automatic flushing is now configurable. However, the default is to flush always, which means that the behavior of the listener is the same as in previous versions of Enterprise Library if a value is not specified in the configuration. To disable automatic flushing, set the AutoFlush property of the Log Source to True. It is then your responsibility to ensure that all entries are flushed to the target, especially if an exception or failure occurs in the application. Otherwise, you will lose any cached logging information not yet written to the target.

· Log file names now support the use of environment variables. You can include environment variables such as %WINDIR%, %TEMP%, and %USERPROFILE% in the Filename property of the Flat File Trace Listener, Rolling Flat File Trace Listener, and XML Trace Listener.

The application block implements several new performance counters that you can use to monitor performance and operations. The new counters are Total Logging Events Raised, Total Trace Listener Entries Written, and Total Trace Operations Started.

First Impressions

The startup performance improvements with Unity (which is already released) are not done yet but I hope that this will help to make the usage of the application blocks nearly invisible. The new dependency injection mechanism which uses reflection like ObjectBuilder (slow) but uses dynamically generated IL code to call the actual constructors/getter/setter methods. That increases the object creation performance dramatically. I hope that this will make a noticeable difference in a real world application.

After doing a quick diff I found some improvements in the Logging Application Block. They do mainly concern the configuration via WMI and group policies with ADM templates. That enables to query and deploy logging configuration via an Active Directory without changing a physical file on the target machines. That is a nice feature but I have to yet to see if that does work in all scenarios. Low privileged users do not always have full WMI access which could hinder the usage of the new feature in low trust environments.

Writing to a log file seems to be very easy but it did take over three years (Jan. 2005 was the first release) to support environment variables in file names. The delivered code quality was always very good but why on earth did it take so long? Working agile with a very strict timeline does enable the P&P team to deliver top features on time but low priority features such as this one have been dropped. That is no problem since the community did deliver very quickly the missing features such as the Rolling File Trace Listener from Erwyn van der Meer which is in my opinion still the one of the cleanest implementations of a Rolling File Trace Listener. What I really miss is a backflow of great community extensions to the Enterprise Library main code base.

A really nifty feature of the new Rolling File Trace Listener is the roll interval Midnight to enable to start a new log file at every day. Although one should not expect a roll over exactly at midnight since the roll over is only performed when the next log call arrives after the time span has elapsed.

 

Logging Application Block Performance

The creation of LogEntry objects has become dramatically faster since the current values are only read when needed. That is good but not perfect (yet). The main observations I did make

 

  • LogEntry: Process Id, Process Name and AppDomain Name will never change during the lifetime of an application. They could be read only once and copied from static variables to the actual instance variables on demand.
  • LogEntry: The native and managed thread id is fetched on demand which could be too late if the output destination does asynchronous operations (queuing?).
  • Formatters: There is no progress in the text formatter performance. That is surprising to say the least since delayed LogEntry variable expansion does not help much if you use a TextFormatter with the default template to format your LogEntry. I whish so much I could check out the sources for TextFormatter ....

 

The Good/The Whishes/The Summary for Entlib 4

Good:

  • Many new features (central configuration, unity integration, ...)
  • Performance Improvements

Wishes

  • High quality community extensions should be included in the main code base.
  • Do NOT Authenticode sign the strong named binaries again. I really hate the 15s startup delays of non Internet connected machines! Yes I know with .NET 3.5 there is a way to turn Authenticode verification off in the App.config file but .NET 2.0 users will suffer from this.
  • Do include the pdb's for Release and Debug for all shipped binaries (ObjectBuilder too).

The next release of the Enterprise Library does deliver cool features such as Unity and support for group policy based configuration. Finally the Patterns & Practices team has found the time to fix some minor quirks which have been annoying but not mission critical. Since the new release seems to be API compatible with the previous versions you should definitely consider to upgrade as soon as possible. Have a look at the blog of Grigori Melnik for latest announcements about the upcoming release of Entlib 4.

  • Share This Post:
  • Share on Twitter
  • Share on Facebook
  • Share on Technorati
Posted On Wednesday, April 09, 2008 1:20 PM | Feedback (3)
Try/Finally Pattern - Take a different path when an exception has occurred.

Error handling is a difficult beast. And there is always one more way to do it. Thottam Sriram did write some nice examples what main cases you usually have to deal with. The most ugly case is the one where you cannot handle an exception but you need to do different cleanup logic in a finally block.

 

               public void Func()

        {

            bool cleanup = true;

 

            try

            {

                OtherFunc();

                cleanup = false;

            }

            catch (Exception)

            {

                // perform Cleanup on error

            }

            finally

            {

                if (cleanup)

                {

                    // perform cleanup on error

                }

            }

        }

 

The necessity to keep a state variable for a corner case does complicate the code quite a lot. You can get around that by knowing that .NET exceptions just wrap SEH (Structured Exception Handling) of Windows. The CLR does make extensive usage of SEH which you can read in the wonderful article from Chris Brumme. To sum it up in a few words if an exception is thrown an Exception Pointers structure is allocated. The actual exception processing is done two in two steps.

  1. Ask all exception handlers what about the current error can be done. If one says it can fix it the exception processing is stopped. No exception will ever happen.
  2. If no handler could fix it in the first pass they are actually invoked one by one and the stack unwinding does start.

C++ has special keywords for SEH named __try/__except/__leave which cannot be mixed with the regular try/finally C++ keywords within one function because only one exception handling chain within a function does make sense. Now you could ask how that complicated stuff can make by error handling easier? Well since we know that during an exception unwind scenario for the executing thread an Exception Pointers structure must exist we can check for its existence and we can distinguish the non exception case from the other. The BCL gives us direct access to this precious information via Marshal.GetExceptionPointers. Armed with that knowledge we can create a simple helper class that returns true if we are in an exception unwind case.

 

    public static class ExceptionHelper

    {

        /// <summary>

        /// Check if we are in a exception unwind scenario or not.

        /// </summary>

        public static bool InException

        {

            get

            {   // Errata: The red marked code seems to be necessary. Since unit tests with .NET 2.0

                // have shown that only checking for the Exception Pointers structure does not always work.

                return Marshal.GetExceptionPointers() == IntPtr.Zero &&

                       Marshal.GetExceptionCode() == 0 ? false : true;

            }

        }

    }

 

The code from above becomes now

 

        public void ImprovedFunc()

        {

            try

            {

                OtherFunc();

            }

            finally

            {

                if (ExceptionHelper.InException)

                {

                    // perform cleanup on error

                }

                else

                {

                    // Do normal cleanup in non exception case

                }

            }

        }

 

We did get rid of the catch clause and the state variable. That little trick can make your life easier in some situations. You can call the check property not only in a finally clause but also from a helper function because the Exception Pointers structure is thread local and visible as long exception processing is going on.

 

Remarks

 

At CLR IL (Intermediate Language) level there is the fault keyword which is similar. It acts like a finally block that is only executed when an exception has occurred. Besides the fact that C# does not support it is not really something that I would want. When an error happens I must execute nearly the same cleanup actions as in the non exceptional case. For that reason code sharing within one code block is essential to prevent code duplication both handlers. If you try to be smart and use the goto keyword (yes I won't dare to use it if it would have worked) to jump from a from a catch handler into the finally handler to skip a portion of the cleanup code you will get a compile error.

Since we have got our hands on the Exception Pointers structure we should be able to find there some reference to the managed exception and perhaps even return it. I tried that and failed. By looking at the Rotor source code I could not find evidence that this structure does contain any hints to the managed exception object. It looks like that the managed Thread implementation has it stored somewhere but since CLR objects are a mixture of IL code and C++ classes it is not feasible to use a simple fixed offset and cast it to the managed exception object.

If somebody has more info about that I am always interested to learn more ...

  • Share This Post:
  • Share on Twitter
  • Share on Facebook
  • Share on Technorati
Posted On Tuesday, April 08, 2008 11:37 AM | Feedback (3)