Sunday, March 20, 2011

Inaugural DevReady event on MVVM

There has been a tremendous amount of hype recently around the MVVM (Model-View- Viewmodel)pattern. Miguel Castro and DevExpress put together a developer day that shows the hype is backed by substance. There was a sold out crowd this past Saturday to see this event at the Microsoft office in Malvern PA. There was a convivial atmosphere created by the three
hispanic presenters: Miguel, Dani Diaz the Microsoft developer evangelist, and Seth Juarez, a DevExpress developer evangelist. The backgrounds of the three speakers, respectively Cuba, Dominican Republic, and Mexico family backgrounds, provided an ongoing source of levity and continuity. The back and forth between the speakers, both light-hearted and technical, helped make the event cohere into a single focused event, not a variety of individual topics like a code camp.


The MVVM pattern was first articulated by Martin Fowler, see http://martinfowler.com/eaaDev/PresentationModel.html. Martin named this the Presentation Model pattern. The MVVM pattern, despite being a really awkward palindrome, is a valuable pattern that has emerged in the rich client area. Web applications, with the need for routing preeminent, tend to emphasize the MVC pattern. Many developers are familiar with what a model and view are by this team. A Model represents the business logic of an application and a View represent a visual interface to an area of the application. The role of the ViewModel is to represent a logical representation of the visual interface.


The core of the event was Miguel’s three sessions on Xaml and MVVM. His Xaml talk really was an overview of WPF development. Attending this talk is a must for developers new to WPF, Silverlight, and WP7. It will be given again at Philly Code Camp on April 9, so check it out there! I can’t quantify just how much time it would have saved me in learning WPF. He talked a lot about layout,which is much different than in Windows Forms or other rich client development. I initially misconstrued the Grid as something like a DataGrid, when it is really intended purely for layout. As Miguel pointed out, the Grid is much like a table in HTML. Miguel drove the point that WPF layout is really driven a lot by how HTML and CSS combine to represent web markup. Miguel showed how using a drag and drop approach adds a lot of bad markup to the XAML. He did point out that the DevExpress WPF tools really are a great way to allow devs to deal with layout less. Miguel pointed out that the pain points in the native .NET DataGrid control for WPF is an area where the DevExpress grid really shines. I think investing in a good control library can be the most well-spent money in a project.


Dani Diaz gave a presentation that focused on Microsoft’s efforts to support multitargeting .NET applications. I personally think that this will be the most important reason for developers to use the MVVM pattern. The approach in MVVM to support a loosely coupled architecture increases the ease of reuse by cordoning off direct GUI dependencies into the view. Dani’s presentation focused on WPF, Silverlight, and WP7 multitargeting. I actually think that is likely that two platforms not discussed in this event, IPhone and Android will drive MVVM adoption by allowing developers to work in a .NET shop and still target the most popular mobile platforms. Right now, iPhone and Android development with .NET means through use of Novell’s MonoTouch and MonoDroid development tools, As Dani pointed out, write once run everywhere is a myth. Users, myself included, want apps that behave natively to its OS. MVVM is the perfect pattern to allow multitargeting.


Dani talked about the upcoming Microsoft effort to support what they call Portable Library Tools. The Portable Library Tools are in a CTP stage right now but probably aren’t that useful yet. As Dani explained, Microsoft is still in the process of adding .NET framework elements that exist in a compatible way on multiple platforms. At the moment, the ObservableCollection class is not publicly supported by the CTP but it is expected that future releases will include this class. The ObservableCollection class is pretty essential in taking advantage of data binding.


The final presentation of the day was by Seth Juarez of DevExpress. Seth writes about his research in Machine Learning here. Seth’s approach was to give himself a crash course in Prism and share the results with us. Seth’s candor in talking about his experiences in dealing with Microsoft’s effort to support composite application development was refreshing. Prism can be a little difficult to get ones head around and appreciate. Seth showed that presenting a topic as a newby, it can be a good way to provide a quickstart to using Prism. Miguel also made a good point in his talk that Prism itself doesn’t provide any support for validation. Miguel is working on a MVVM framework built on top of Prism that adds validation. Seth used CodeRush throughout his talk illustrating just how much of a performance boost a developer can get by using a tool like CodeRush to support refactoring and minimize typing. It was pretty impressive although I still find the giant arrows that CodeRush uses to be garish and over the top. A little subtlety would be preferable, and less of a distraction.

Tuesday, March 8, 2011

FileHelpers is my new best friend

I have gained countless tools and information over the years from Scott Hanselman’s blog . My new favorite tool is now Marcos Meli's FileHelpers . It is great tool for dealing with delimited or fixed length field messages. Despite the name, it is extremely useful in dealing with messages that are memory-based as well. I wish I had this tool years ago, it would have saved my countless hours of development! In particular, dealing with problems in data or record length changes is a teeth-gnashing, prototypically “bejabbers” experience.

As a longtime C++ developer, the only feature I missed in .NET is the ability to have structures/union of character arrays to deal with fixed length field messages. In C++, this feature relies on the ability to directly access memory. FileHelpers gives me a similar capability using reflection and attributes to accomplish this task. You adorn a class and fields with FileHelpers specific attributes and it knows how to do the rest. The FileHelpers documentation is superb, unlike many open source project, so I’ll just include a brief excerpt of the documentation here to whet your appetite.

[FixedLengthRecord()]   
 public class Customer   
 {   
     [FieldFixedLength(5)]   
     public int CustId;   
        
     [FieldFixedLength(20)]   
     [FieldTrim(TrimMode.Right)]   
     public string Name;   
}

As cool as reflection is, performance is always a potential concern. FileHelpers is a great illustration of how .NET can create highly-performant code. Many times developers, including myself, only think of reflection as a way to access methods, properties, and fields dynamically. Using Reflection.Emit, as FileHelpers does, is a mechanism to allow code to be generated at runtime. Combined with caching, dynamic code generation allows excellent performance.

To work with FileHelpers I create a wrapper around usage of the fixed length record.


using System;
using System.Collections.Generic;
using System.Text;
using FileHelpers;
    /// <summary>
    /// This generic class provides convenience functions for the FileHelpers library.
    /// This class implements the Facade design pattern by encapsulating the FileHelpers
    /// engine and providing a simple interface to that functionality.
    /// </summary>
    /// <typeparam name="T">the class type representing a message. This type must use the 
    /// FixedLengthRecord attribute</typeparam>
    public class FixedLengthMessageParser2<T>  where T:class
    {
        FileHelperEngine engine;
        /// <summary>
        /// Initializes a new instance of the <see cref="FixedLengthMessageParser&lt;T&gt;"/> class.
        /// It creates the file helper object.
        /// </summary>
        public FixedLengthMessageParser2()
        {
            engine = new FileHelperEngine(typeof(T));
        }
        /// <summary>
        /// Parses the specified aggregate data.
        /// </summary>
        /// <param name="aggregateData">The aggregate data.</param>
        /// <param name="records">The records found to be contained in the data</param>
        /// <param name="resultText">Results of parsing. Empty string if 
        /// successful, or exception details otherwise</param>
        /// <returns>True if able to parse, False otherwise.</returns>
        public bool Parse(string aggregateData, out T[] records, out string resultText)
        {
            records = null;
            resultText = String.Empty;
            try
            {
                records = (T[])engine.ReadString(aggregateData);
            }
            catch (Exception ex)
            {
                resultText = "entry " + typeof(T) + " [" + aggregateData
                    + "]couldn't be read due to error " + ex.ToString();
                return false;
            }
            return true;
        }
 
        /// <summary>
        /// Provides a string representation of a record.
        /// </summary>
        /// <param name="msg">The MSG received as input.</param>
        /// <returns>String representation of a record.</returns>
        public string ReturnToString(T msg)
        {
            string retVal;
            retVal = engine.WriteString(msg.AsEnumerable());
            retVal = retVal.Substring(0, retVal.Length - 2); //trim end of line characters
            return retVal;
        }
 
 
        /// <summary>
        /// Parses a single record
        /// </summary>
        /// <param name="singleData">A single data record.</param>
        /// <param name="fixedLengthRecord">The fixed length record.</param>
        /// <param name="resultText">Results of parsing. Empty string if 
        /// successful, or exception details otherwise</param>
        /// <returns></returns>
        public bool ParseSingle(string singleData, out T fixedLengthRecord, out string resultText)
        {
            T [] records = null;
            fixedLengthRecord = null;
            resultText = String.Empty;
            try
            {
                records = (T[])engine.ReadString(singleData);
                if (records.Length == 0)
                {
                    resultText  = "entry " + typeof(T) + " [" + singleData
                       + "]couldn't be read due to empty data set";
                    return false;
 
                }
                fixedLengthRecord = records[0];
            }
            catch (Exception ex)
            {
                resultText = "entry " + typeof(T) + " [" + singleData
                    + "]couldn't be read due to error " + ex.ToString();
                return false;
            }
            return true;
        }
    }

Wrasslin with Log4Net

I have a love-hate relationship with Log4Net. It is powerful, capable of doing everything I have ever wanted, yet configuration is always a challenge for me to get right. I wish there was a good, free GUI configuration tool available for it. In this post I will share the current Log4Net configuration that I am using. It is a moderately sophisticated configuration, relative to many of the posted samples. This example shows use of console appenders, event log appenders, file appenders, and multiple loggers. I also illustrate how to call Log4Net in a way that allows logging configuration changes to take effect immediately while a process is running.

Here are some points of interest. As I stumble through a configuration, the log4net.Internal.Debug AppSettings key is very helpful in showing me where my mistake lies. In order to take advantage of multiple loggers, it took me a while to figure out the secret sauce that made things work. First, loggers are hierarchical in nature. I found that I needed to specify all appenders used at the root logger level. Then each logger name I used specified the ones I used it for it. The key here was setting Additivity=”FALSE” otherwise I got an error indicating that the appender was closed.
I also found the concept of a single log message being able to be processed by multiple appenders to be powerful. One use was that I use a ConsoleAppender while I am testing to see the Log4Net output without having to pull up a log file. The message is still written to logs too, so I can verify that I log precisely what I intend. At the other end of the logging severity, I log all errors (both ERROR and FATAL) to a file but also log fatal errors to the Windows Event log for easy processing.
A couple of items on my to-do list are exploring buffered file appending and rolling over logs after they reach a maximum size. The BufferingForwardingAppender allows you to utilize the Unit of Work pattern to by aggregating a bunch of messages for the expensive, synchronous act of logging. The drawback to using this approach is that if you are concerned about troubleshooting program abends, you might lose the last few entries in this scenario. Also, although Log4Net is generally threadsafe, this appender is not.

<?xml version="1.0"?>
<configuration>
  <configSections>
    <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
  </configSections>
  <appSettings>
    <!--if having trouble getting log4net to work turn its detailed internal logging on-->
    <!--<add key="log4net.Internal.Debug" value="true"/>-->
  </appSettings>
  <log4net>
    <root>
      <level value="ALL" />
      <appender-ref ref="FatalFile" />
      <appender-ref ref="ErrorFile" />
      <appender-ref ref="WarningFile" />
      <appender-ref ref="DebugFile" />
      <appender-ref ref="SomeInfoFile" />
      <appender-ref ref="SomeExtraFile" />
    </root>

    <logger name="PrimaryLogs" additivity="FALSE">
      <level value="ALL" />
      <appender-ref ref="FatalFile" />
      <appender-ref ref="ErrorFile" />
      <appender-ref ref="WarningFile" />
      <appender-ref ref="DebugFile" />
      <appender-ref ref="SomeInfoFile" />
    </logger>

    <logger name="ExtraLogs" additivity="FALSE">
      <level value="ALL" />
      <appender-ref ref="SomeExtraFile" />
    </logger>
    <appender name="FatalFile" type="log4net.Appender.EventLogAppender">
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%date [%5thread] %type{1}.%method() - %message%newline%exception" />
      </layout>
      <filter type="log4net.Filter.LevelRangeFilter">
        <levelMin value="FATAL" />
        <levelMax value="FATAL" />
      </filter>
    </appender>
    <appender name="SomeExtraFile" type="log4net.Appender.RollingFileAppender">
      <file value="C:\logs\ AppLateMessage.txt" />
      <lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
      <appendToFile value="true" />
      <staticLogFileName value="false" />
      <rollingStyle value="Date" />
      <datePattern value="'.'yyyyMMdd-HH'.log'" />
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%date [%5thread] %type{1}.%method() - %message%newline%exception" />
      </layout>
      <filter type="log4net.Filter.LevelRangeFilter">
        <levelMin value="WARN" />
        <levelMax value="WARN" />
      </filter>
    </appender>
    <appender name="ErrorFile" type="log4net.Appender.RollingFileAppender">
      <file value="C:\logs\ AppError.txt" />
      <lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
      <appendToFile value="true" />
      <staticLogFileName value="false" />
      <rollingStyle value="Date" />
      <datePattern value="'.'yyyyMMdd-HH'.log'" />
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%date [%5thread] %type{1}.%method() - %message%newline%exception" />
      </layout>
      <filter type="log4net.Filter.LevelRangeFilter">
        <levelMin value="ERROR" />
        <levelMax value="FATAL" />
      </filter>
    </appender>
    <appender name="SomeInfoFile" type="log4net.Appender.RollingFileAppender">
      <file value="C:\logs\ AppSomeInfoFile.txt" />
      <lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
      <appendToFile value="true" />
      <staticLogFileName value="false" />
      <rollingStyle value="Date" />
      <datePattern value="'.'yyyyMMdd-HH'.log'" />
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%date [%5thread] %type{1}.%method() - %message%newline%exception" />
      </layout>
      <filter type="log4net.Filter.LevelRangeFilter">
        <levelMin value="INFO" />
        <levelMax value="INFO" />
      </filter>
    </appender>
    <appender name="WarningFile" type="log4net.Appender.RollingFileAppender">
      <file value="C:\logs\AppWarning.txt" />
      <lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
      <appendToFile value="true" />
      <staticLogFileName value="false" />
      <rollingStyle value="Date" />
      <datePattern value="'.'yyyyMMdd-HH'.log'" />
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%date [%5thread] %-5level %type{1}.%method() - %message%newline%exception" />
      </layout>
      <filter type="log4net.Filter.LevelRangeFilter">
        <levelMin value="WARN" />
        <levelMax value="FATAL" />
      </filter>

    </appender>
    <appender name="DebugFile" type="log4net.Appender.ConsoleAppender">
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%-5level %type{1}.%method() - %message%newline%exception" />
      </layout>
      <filter type="log4net.Filter.LevelRangeFilter">
        <levelMin value="DEBUG" />
        <levelMax value="ERROR" />
      </filter>
    </appender>
  </log4net>
</configuration>