Super-simple Object Mapper

If you need a full-featured object mapper with minimal set up, I recommend you take a look at AutoMapper on Codeplex.  If you need a quick-and-dirty solution, maybe the following code could help you out.

First off, why am I not using AutoMapper?  At my current client, there are strict rules as to the use of open source software.  There's a process in place for requesting the use of a particular open source tool, but with the red-tape of the approval process (reviews, signatures, justification, etc…), it could literally take 3 – 6 months.  It's just not worth it for what I need right now.  So I rolled my own.

This mapper is super-simple, not very smart and may have a bug or two in it, but it works for what I need it to do and reduces a lot of hand coding.  USE AT YOUR OWN RISK!

It uses two simple rules to map data between two objects:

  1. If a property name and type on the source match the name and type of a destination property, the value is copied.
  2. If the user has defined a custom mapping action, use that to copy data (but rule #1 is always executed first).

Let's dig into the details.

First, I set up a generic class that takes in a couple of types – my source and destination types.  I added a clause on the destination type that it must be 'new-able' so that I could provide a utility function that would create a destination object, map it's values from a source and return it to you.

public class Mapper<TSource, TDest> where TDest : new()
{
 
}

Copying Properties

When copying data from a source object to a destination object, we get all public instance properties of the destination and see if they have a matching (same name and same type) property on the source.  If so, we set the value on our destination object:

protected virtual void CopyMatchingProperties(TSource source, TDest dest)
{
    foreach(var destProp in typeof(TDest).GetProperties(BindingFlags.Public | BindingFlags.Instance).Where(p => p.CanWrite))
    {
        var sourceProp =
            typeof (TSource).GetProperties(BindingFlags.Public | BindingFlags.Instance).Where(p => p.Name == destProp.Name && p.PropertyType == destProp.PropertyType).
                FirstOrDefault();
        if( sourceProp != null)
        {
            destProp.SetValue(dest, sourceProp.GetValue(source, null), null);
        }
    }
}

Custom Transformations

I want the ability to define my own transformation for special cases.  This is simply a list of Action<TSource, TDest> delegates:

protected readonly IList<Action<TSource, TDest>> mappings = new List<Action<TSource, TDest>>();
 
public virtual void AddMapping(Action<TSource, TDest> mapping)
{
    mappings.Add(mapping);
}

Again, simple yet functional.

Perform Mappings

The last thing we need is a couple of methods to execute the actual mapping:

public virtual TDest MapObject(TSource source, TDest dest)
{
    CopyMatchingProperties(source, dest);
    foreach(var action in mappings)
    {
        action(source, dest);
    }
 
    return dest;
}
 
public virtual TDest CreateMappedObject(TSource source)
{
    TDest dest = new TDest();
    return MapObject(source, dest);
}

You'll see that "CreatedMappedObject" was the reason we needed to have the new-able clause on the TDest generic parameter.

Usage

Now let's put this into action!  Given a simple domain object and view model:

public class DomainObject
{
    public string Name { get; set; }
    public DateTime DOB { get; set; }
    public int Age { get; set; }
    public string Address { get; set; }
}
 
public class ViewModel
{
    public string Name { get; set; }
    public int Age { get; set; }
}

As you can see, our view model only needs the Name and Age.  Our mapping code looks like this:

var mapper = new Mapper<DomainObject, ViewModel>();
var viewModel = mapper.CreateMappedObject(domainObject);

if the view model is created somewhere else and pre-populated with other data, we would use the MapObject method instead of creating a new instance of ViewModel:

var mapper = new Mapper<DomainObject, ViewModel>();
var viewModel = InitializeViewModel();
viewModel = mapper.MapObject(domainObject, viewModel);

Now let's assume we want to add the user's birth year to the view:

public class ViewModel
{
    public string Name { get; set; }
    public int Age { get; set; }
    public int BirthYear { get; set; }
}

Yes, we could pass along the entire date of birth, but this way the view model is getting only what it needs and doesn't need to do any additional processing to get the year:

var mapper = new Mapper<DomainObject, ViewModel>();
mapper.AddMapping((source,dest) => dest.BirthYear = source.DOB.Year);
var viewModel = mapper.CreateMappedObject(domainObject);

To encourage re-use and centralize the setup of any custom transformations, I create a subclass of my Mapper class:

public class DomainModelToViewModelMapper : Mapper<DomainObject, ViewModel>
{
    public DomainModelToViewModelMapper()
    {
        this.AddMapping((s, d) => d.BirthYear = s.DOB.Year);
    }
}

Posted by PSteele | 7 comment(s)
Filed under:

Castle Windsor: Turn Off Automatic Property Injection

Suppose you have the following component:

public class SomeComponent
{
    public IEmailSender EmailSender { get; set; }
}

Further, you're using Windsor for IoC and have registered both this component and an IEmailSender in the container.  Whenever 'SomeComponent' is resolved, it's EmailSender will automatically be set by the container.  If you don't want this behavior, you can tell Windsor, on a per-property basis, to not auto-resolve the property with the "DoNotWire" attribute:

public class SomeComponent
{
    [DoNotWire]
    public IEmailSender EmailSender { get; set; }
}
Source: Turn off property injection/resolution
Technorati Tags: ,,,
Posted by PSteele | 1 comment(s)
Filed under: ,

New Language for 2010: Java?

No, I'm not going to pick Java as a "language to learn" in 2010.  However, I did a little Java development in 2009 (Blackberry, specifically) and was also the developer for the Blackberry version of the CodeMash mobile-application "MobiMash".

imageMy journey into Blackberry development started about March of 2009 when I got my first Blackberry, the Storm.  One of the first things I wanted to get was a Twitter client.  I had previously used PocketTwit on my WinMobile device and wanted something similar.  In particular, I wanted to see the entire tweet.  At the time, the most popular Twitter client for the Blackberry I found was TwitterBerry.  However, one thing that annoyed me was the inability to see the entire tweet.  You saw as much as was possible based on your device's width and then a "...".  You would have to click on the actual tweet to get a detail screen that showed the whole thing

Image Source: Matt Stratton

I tried a few other clients, but at that time, the Storm was still somewhat new and not many apps supported the large touch-screen.  So I thought, "Hey, I'm a programmer.  I could write my own twitter client!".

I spent some free time over the next month or so (maybe 6 or 8 hours a week) setting up RIM's Java Development Environment and learning about Java on the Blackberry devices.  It's definitely an interesting platform.  I had frustrations many times, but overall, it was a fun learning experience.

My ResultsColorFILL1

I never finished my twitter client.  TwitterBerry was eventually updated to view the entire tweet.  And since then, other twitter clients for the Blackberry have emerged – notably, UberTwitter.  This is what I'm currently using and I like it a lot.

After I abandoned my twitter client, I wanted another project to develop for my Storm.  Any time my kids were around their uncle, they bugged him to let them play Flood-It! on his iPhone.  I checked out the game and realized it was pretty simple concept with a basic UI and decided to tackle that.

After a few weeks, I released my version of Flood-It for the Blackberry Storm called "ColorFILL" (yeah, pretty imaginative, huh?).  I've gotten some requests to add features to it and I'd like to get back to it someday.  I still play it from time to time when I bored.

MobiMash

My most recent Blackberry project was MobiMash.  The MobiMash website can explain in more detail, but it was another very fun project and allowed me to lean more about some advanced layout options as well as XML parsing and data persistence on the Blackberry.  One thing that was tricky with MobiMash is that I had to make sure it worked with both the Storm and non-Storm (Pearl, Curve, etc…) Blackberry's.  I wanted a single codebase so I had to resort to preprocessing directives – how 1990's!

Java in 2010

So I'll probably continue to play around with Java development on the Blackberry.  The 5.0 Storm OS has a lot of nice UI improvements to help your apps "pop" (probably due to the competition from the iPhone).  I'd like to play around with those.  And I may even go back and polish up the MobiMash UI since it was thrown together pretty quickly.  Custom controls is definitely something to learn if you want your Blackberry apps to stand out.

Technorati Tags: ,,
Posted by PSteele | 2 comment(s)
Filed under: ,

Using the CodeDom With .NET 3.5 Features

Here it is 2010 and I just noticed while trying to use the CodeDom features of .NET that it defaults to using the .NET 2.0 compiler.  You have to specifically tell it to use .NET 3.5.  Thanks to LukeH and a Stack Overflow question, it was an easy solution:

var providerOptions = new Dictionary<string, string> {{"CompilerVersion", "v3.5"}};
CodeDomProvider provider = new VBCodeProvider(providerOptions);

Yeah, I had to do some integration with some VB.NET code…

Technorati Tags: ,
Posted by PSteele | 2 comment(s)
Filed under:

Live Capture of Log4Net Logging

I recently had to whip up a small diagnostics application for a client.  We were having some connection problems with a component so we wanted to wrap a WinForms GUI around the component and display some debugging information to try and diagnose it.

The component was already configured to do some logging using log4net.  The GUI was going to do some additional logging of status information directly in the UI.  The end result was a textbox in the GUI and a log file generated with log4net.  Not bad, but the client asked if we could log everything (specifically, the log4net output) into the GUI – i.e. a single place to review all of the log messages.

It took a little bit of searching, but I found an easy way to programmatically add a root appender.  All I needed was an object that implemented IAppender.  Since this was quick-and-dirty and I didn't have a lot of time, my solution was as follows:

The main GUI form implemented IAppender:

public partial class MainForm : Form, IAppender

This interface has a single method – DoAppend.  Implementing this interface doesn't give you all of the bells and whistle's (like PatternLayout or filtering– derive from AppenderSkeleton if you're looking for that), but since this was done in the interest of speed, a quick String.Format was all I needed:

public void DoAppend(log4net.Core.LoggingEvent loggingEvent)
{
    ReportProgress(String.Format("log4net - {0}: {1}", loggingEvent.Level.Name, loggingEvent.MessageObject.ToString()));
}

The ReportProgress method simple appends messages to a textbox in the GUI.

Finally, in my application's "main", I initialize log4net and then add the main form to the collection of root appenders:

XmlConfigurator.Configure();
 
var mainForm = new MainForm();
((log4net.Repository.Hierarchy.Hierarchy)log4net.LogManager.GetLoggerRepository()).Root.AddAppender(mainForm);    
Application.Run(mainForm);

Success!  My log4net messages now appear live in the GUI as the components logs them.

Posted by PSteele | 5 comment(s)
Filed under: ,

Know Your Context

Another home appliance repair story that has parallels to software development.

A few days ago, I opened the dishwasher to remove the clean dishes.  However, I noticed the dishes weren't very clean.  They still had some food particles left on them.  We'd never had this problem with the dishwasher.  Then my wife pointed something out: "Oh look.  The soap dispenser didn't open".

That explained the dirty dishes.  Now I had to figure out why it didn't open.  There's a release button on the soap dispenser so I pushed that in and the dispenser popped open.  I slid the door shut and opened it again.  I did this a few times to make sure nothing was sticking.  Everything looked okay so I ran the dishwasher again.

Later that evening, I checked and the dishwasher and the dispenser had still not opened.  So now I had a new item on my to-do list.  I hopped on the computer and went to Repair Clinic.com.  It's a great site that helps you diagnose problems with your appliances.  In fact, they had a section specific to my problem.  I was leaning towards a possible problem with the linkage mechanism, but it was late and I didn't want to start taking the dishwasher apart.  I'll tackle it some night later in the week.

At dinner the next day my wife made a small comment: "I fixed the dishwasher today".  "Really?", I asked.  Not that I'm saying she isn't technically capable of taking apart the dishwasher, but appliance repair has just been something she's perfectly comfortable leaving to me.  "How did you fix it?", I asked.  She smiled and said "It was on the wrong cycle.  It was set for rinse and hold."

Now I look back and think of all the time I spent researching a problem in which I had not taken the time to know the entire context in which the problem was occurring.  A simple check to make sure the dishwasher was set for the proper cycle would have identified the issue right away.

If you're in a QA field, make sure your bug reports accurately describe the context in which a problem is occurring.  If you're in development, make sure you know the context under which a bug has been reported to make sure you're approaching the problem from the proper angle!

Technorati Tags: ,
Posted by PSteele | 1 comment(s)
Filed under:

Looking Forward to 2010

Yes, the first month of 2010 is almost gone and I'm just now getting around blogging about the past year and the year ahead.  I guess time management should be on my to-do list for this year?

The CodeMash Website

One of the coolest projects I've worked on in 2009 was the CodeMash websiteBrian Prince and Jim Holmes asked SRT if they wanted to help design a new website for CodeMash.  Brian will be the first to admit that he's an evangelist first, a developer second and a web developer third.  They gave us pretty much free reign to come up with a new idea as well as the freedom to implement the solution however we wanted.

We worked with a Inner Circle Media to help plan the new look and feel of the site.  They deserve kudos for the new look.  On the back-end, I used ASP.NET MVC 1.0 along with SQL Server, Linq2SQL and Castle Windsor for my IoC container.  We also integrated with the existing Sharepoint installation for sponsor maintenance, news and session submissions.  User registration was all done in SQL.

This was a great learning project.  Registering for a conference is usually a simple process (from the registrants standpoint).  On the back-end, when you're dealing with varying registration costs (based on the current date), discount codes, PayPal, and other things, it can get pretty complicated.  A large suite of unit tests helped us catch a lot of stuff in the beginning, but a few bugs slippped through.  Luckily, nothing major!

I want to also thank fellow SRT developers Marina Fedner and Ben Barefield.  Marina helped me out on the user registration portion and Ben was responsible for the REST feed that we all used for our mobile CodeMash applications.

Stepping Down from GANG

After being involved with the Great Lakes Area .NET Users Group (GANG) for many, many years (webmaster, VP and this last year as President), I did not run for re-election.  There were some other projects I was taking on and last year's vice president David Giard was willing to take the reigns of the group.  Dave did an amazing job last year as VP and is continuing to do great things with GANG in 2010.  I'll still be around to help out from time to time, but Dave is the man in charge now!

VSM's C# Corner

After helming Visual Studio Magazine's C# Corner for a number of years, Bill Wagner decided he wanted to devote his time to other things.  He offered my name as a possible successor!  I talked it over with him and VSM Editor in Chief Michael Desmond.  Everything fell into place and I'm now honored to be following in Bill's footsteps as a VSM author.  My first column has been published (Interface-Based Programming in C#) and I've got some positive feedback so far.  My next article is in-process and I have to have the first draft done by February 1st or I'll be on someone's naughty list (and it won't be Santa's!).

Microsoft C# MVP

I was pleasantly surprised on January 1st to receive an email from Microsoft telling me I've received an MVP award for my C# and community work in 2009.  Thanks to Microsoft and other community members I work closely with!

2010 Plans

  • One of the big conferences for 2010, CodeMash, has already come and gone.  It was a great conference and you CAN NOT beat the price.  The amount of content and learning available is unheard of for the price you pay.  I'm already looking forward to CodeMash 2.0.1.1.
  • In February, I'll be attending the MVP Summit in Redmond.  A great chance to get in touch with new technologies, talk with Microsoft reps and mix it up with other MVP's.
  • Michael Eaton is already planning this year's Ann Arbor Give Camp.  I've offered my assistance again this year and will post more on this even as it gets closer.
  • Speaking: I'd like to do more speaking this year.  While I usually get compliments on my presentations, I'm very hard on myself.  I may be a good speaker, but I want to be a great speaker.  That will come with practice.  I've got some idea's for presentations on topics I'm passionate about (specifically, Inversion of Control and Mocking).

I'm really looking forward to 2010!

Technorati Tags: ,,,
Posted by PSteele | with no comments

And SRT Grows by One!

Great news!  MVVM-Guru Brian Genisio is joining SRT in February!  I first met Brian in-person at CodeMash last year.  In fact, he was the one that convinced me to get on Twitter.  Since then, I've been reading his blog and trying to catch his presentations at local user groups.  He'll be giving his great MVVM talk at CodeMash in January.

Congratulations Brian.  I'm looking forward to working with you!

Posted by PSteele | 1 comment(s)
Filed under:

CodeMash REST Endpoints Updated

You spoke, we listened.  We've got updates to the CodeMash REST endpoints!

We've added two new pieces of information to the Sessions feed: Track and Room.  Track exposes what track a session is part of (for filtering, etc…) and Room indicates which room the session will be held in.  Note that the room information and start time have not been finalized and are subsequently empty.

Also, the speaker submission form was designed during a heated battle for control of a coconut tree so we forgot to ask speakers for their twitter handle and blog URL.  We're collecting that info now and as it trickles in, we'll get our database updated and you'll see the information in the REST feeds.

Technorati Tags: ,,,
Posted by PSteele | 1 comment(s)
Filed under:

Use Dependency Injection To Simplify Application Settings

We've all seen and written code that accesses data from our app.config or web.config file.  We'll throw some simple settings in there:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <appSettings>
        <add key="enableLogging" value="true" />
        <add key="startDate" value="12/1/2010" />
        <add key="baseFee" value="157.50" />
    </appSettings>
</configuration>

And then we'll use the ConfigurationManager to pull the data out when we need it:

public class Foo
{
    public void DoSomething()
    {
        bool enableLogging = Convert.ToBoolean(ConfigurationManager.AppSettings["enableLogging"]);
        DateTime startDate = Convert.ToDateTime(ConfigurationManager.AppSettings["startDate"]);
        decimal baseFee = Convert.ToDecimal(ConfigurationManager.AppSettings["startingFee"]);
    }
}

Now that Inversion of Control and Dependency Injection are part of my everyday development, I don't do it this way anymore.  It's messy and doesn't allow me to easily plug in different values during testing.

These days, I create a simple interface for my application settings:

public interface IApplicationSettings
{
    bool EnableLogging { get; }
    DateTime StartDate { get; }
    decimal BaseFee { get; }
}

And create an implementation of this interface that pulls data from app.config:

public class AppConfigSettings : IApplicationSettings
{
    public AppConfigSettings()
    {
        this.EnableLogging = Convert.ToBoolean(ConfigurationManager.AppSettings["enableLogging"]);
        this.StartDate = Convert.ToDateTime(ConfigurationManager.AppSettings["startDate"]);
        this.BaseFee = Convert.ToDecimal(ConfigurationManager.AppSettings["startingFee"]);
    }
 
    #region IApplicationSettings Members
 
    public bool EnableLogging { get; private set; }
    public DateTime StartDate  { get; private set; }
    public decimal BaseFee { get; private set; }
 
    #endregion
}

I register my types with my IoC container.  During production, dependency injection takes over and automatically gives me my AppConfigSettings instance.  For testing, I generate a mock IApplicationSettings.  And using these settings just got a whole lot cleaner:

public class Foo
{
    public Foo(IApplicationSettings applicationSettings)
    {
        
    }
}
Posted by PSteele | 7 comment(s)
Filed under: , ,
More Posts Next page »