Introducing the SmartBag for ASP.NET MVC. . . and soliciting feedback

To get objects from an ASP.NET MVC controller to a view, you put the objects in a dictionary of sorts called ViewData.  ViewData is sort of a misnomer because it’s not meant to contain data at all.  It’s meant to contain objects.   By the way, if you like this post, you can subscribe to my RSS at http://feeds.feedburner.com/jeffreypalermo.

There are some challenges with ViewData as it stands now:

  • A key is required for every object, both in the controller and view.
    ViewData.Add(“conference”, conference);
  • A cast is required to pull out object by key.
    (ScheduledConference)ViewData[“conference”]
  • The ViewPage<T> solution discards the valuable flexibility of the objectbag being passed to the view.
    <%=ViewData.DaysUntilStart.ToString() %> where ViewData is of type ScheduledConference

Facts (or my strong opinions):

  • Repeated keys from controller and view increase chance for typos and runtime errors.
  • Casting every extraction of an object in the view is annoying.
  • Strong-typing ViewPage only works for trivial scenarios.
    – For instance, suppose once logged in, every view will need the currently logged in user.  Perhaps the user name is displayed at the top right of the screen in the layout (master page).  Since the layout shares the viewdata with the page, we immediately have the need for a flexible container that supports multiple objects.  A strongly typed ViewPage<T> won’t work without an elaborate hierarchy of presentation object that are themselves flexible object containers able to support everything needed.  Once you get there, you are almost back to the initial dictionary.

My proposed draft solution, the SmartBag:  (and a follow-up here)

  • The SmartBag is currently only in CodeCampServer, but when it has proven it’s worth, I’ll move it into MvcContrib.  It’s used in the ConferenceController and the ShowSchedule view.  You can check out CodeCampServer at http://codecampserver.org.
  • public class SmartBag : Hashtable
    {
    public T Get<T>()
    {
    return (T)Get(typeof(T));
    }

    public object Get(Type type)
    {
    if (!ContainsKey(type))
    {
    string message = string.Format("No object exists that is of type '{0}'.", type);
    throw new ArgumentException(message);
    }

    return this[type];
    }

    public void Add(object anObject)
    {
    Type type = anObject.GetType();
    if (ContainsKey(type))
    {
    string message = string.Format("You can only add one default object for type '{0}'.", type);
    throw new ArgumentException(message);
    }

    Add(type, anObject);
    }

    public bool Contains<T>()
    {
    return ContainsKey(typeof (T));
    }
  • The smartbag implements IDictionary through HashTable, so it’s flexible, just like ViewData, but it has a powerful convention:  If you are passing one object/type to the view, we don’t need a key because the SmartBag can use the type as the key.  If you really need a Top conference and a Bottom conference, then you are back to using your keys, but for 80% (statistic I pulled out of my behind) cases, this works.
  • If we introduce a layer supertype for our views, then we can just use it:
  • public class ViewBase : ViewPage<SmartBag>
    {

    }
  • Then, all my views inherit from ViewPage<SmartBag>.

I’d appreciate feedback on this solution.  To me, it seems to be a good foundation and convention, but I’m sure it can be improved.  If this solution hasn’t been proven to be worthless, I’ll port it to MvcContrib so it can be used by MvcContrib clients.

About Me

Jeffrey Palermo is a Managing Partner & CEO of Clear Measure, Inc, a software engineering firm in Austin, TX.  At Clear Measure, Jeffrey manages the software engineering practice which includes new system development, legacy system upgrades, performance/scalability improvements and system rescues.  Previously, Jeffrey has held executive positions at various firms including President, COO, CIO, CTO, Chief Architect, and VP of Engineering.



Jeffrey has been recognized by Microsoft as a “Microsoft Most Valuable Professional” (MVP) each year since 2006.  He has spoken and facilitated at industry conferences such as VSLive, DevTeach, the Microsoft MVP Summit, and Microsoft Tech Ed. He also speaks to user groups around the country as part of the INETA Speakers’ Bureau. A graduate of Texas A&M University, an Eagle Scout, and an Iraq war veteran, Jeffrey has published many magazine articles, and he has written three editions of his book, ASP.NET MVC in Action.

Subscribe to Jeffrey’s blog feed here: http://feeds.jeffreypalermo.com/jeffreypalermo

Read about Clear Measure.

Austin Code Camp 2008 scheduled for May 17, 2008

The Austin .Net User Group is hosting its third annual code camp on May 17th, 2008.  Our past two code camps have been around 150 in size and contained several sessions running side-by-side.

This years code camp is going to have more than just presentations and will include and open space portion. 

Details are sparse at this time, but there will be more information to come as the date draws nearer.

Headspring welcomes Jimmy Bogard

I haven’t posted much about the goings-on of my company, Headspring Systems, but this is worth mentioning. 

Jimmy Bogard just joined us!  Yes, I’m excited.  Those in Austin know him from the Austin .Net User Group and AgileAustin, and others know him as one of the NBehave team members and blogger on LosTechies.  He attended the AltNetConf and leads book clubs in Austin, TX.  His current book club is studying Domain-Driven Design by Eric Evans.

Jimmy started yesterday, and the first day was like all first days – setting up the good old workstation.  We’re excited to have Jimmy on board.  He’ll definitely be an asset on the .Net consulting projects we do.

Jimmy’s post here.

Reading in config files _one_ way – what’s the path?

Executive summary:  AppDomain.CurrentDomain.SetupInformation.ApplicationBase

Subscribe here: http://feeds.feedburner.com/jeffreypalermo.

In a console app, this directory is where the assemblies are.  In ASP.NET, this directory is where the web.config file is, not the assemblies.  Other methods seem to be less reliable and rely on the current directory.  This can change whether the code is executing stand-alone or through Visual Studio.  the above API seems to be very consistent.

Please share your experiences.

CodeCampServer OSS project call for participation

Officially announcing a new open-source project, CodeCampServer.  As usual, you can subscribe to my RSS feed to keep up-to-date with more information about this here: http://feeds.feedburner.com/jeffreypalermo.  The mission of the first release is to provide an ASP.NET MVC Framework solution that can serve as the CodeCamp website for a user group.  The project will be able to track and manage multiple conferences for a single user group.  This project is a consumer of the MvcContrib project. 

At this point, we have a project workspace on GoogleCode, and we have a backlog.  Feel free to participate in the project’s discussion list and suggest stories.  We’ll add them to the backlog and prioritize appropriately.  We are intentionally focusing the release 1 in order to get some usable software out quickly.  We will be maintaining a healthy code base with full NUnit test coverage.  You will be able to track the project’s CI with CCTray by referencing the CCNet server on build.codecampserver.org soon (after I set it up).  We already have the NAnt automated build in place, but the domain isn’t set up yet.

Ben Scheirman is one of the lead developers on the project, and I’m serving as project coordinator and developer.  Eric Hexter has set up the CCNet build.  The easiest way to contribute is to grab a high-priority story off the backlog, communicate on the discussion list that you want to work on it, and then work toward submitting a patch.  If you are interested in becoming a committer, then please start by committing patches so we can get to know each other.

When you link to the project, please link to http://codecampserver.org/.

ASP.NET MVC Framework episode on DNRTV available

Subscribe here: http://feeds.feedburner.com/jeffreypalermo.

For those of you interested in the ASP.NET MVC Framework, Carl Franklin and I recorded a DNRTV show where I demonstrate building a full vertical slice of the application.  I don’t dumb it down, and if you aren’t familiar with NUnit testing, automated builds, IoC containers, DI, interface-based programming, etc, you’ll probably have to do a bit of research to follow along, but my goal was to show techniques I’d use on a real client project, not just show a _demo_.  I hope you enjoy.

If you want to know more about the ASP.NET MVC Framework, look backwards in my blog and also at the following places:

Improve maintainability of ASP.NET databinding

Most of us (I think) don’t have full browser automated testing through Watir or Selenium.  Because of that, even though we have tons of automated NUnit tests, we could still have problem in web pages in ASP.NET because these aren’t fully tested with the build.

Even with Resharper, refactoring often leaves bad property references in databinding code that looks like this:

<%# Eval(“EmailAddress”) %>

If we get rid of the EmailAddress property on the object we’re binding (or rename it), this would break.

If we convert the above line of code to the following, we benefit from strong typing (and Resharper helps us out a little more).  We can precompile the web application to ensure all references in web pages still work.  After all, compilation is a low-level form of testing.  It would alert us of a bug.

<%# ((Customer)Container.DataItem).EmailAddress %>

ASP.NET MVC podcast from .Net Rocks!

Thanks to Richard and Carl for having me on the show.  It was fun.  Can you pick out the parts that were _supposed_ to be editted out? 

We talked about the CTP for the ASP.NET MVC framework and why I find it interesting.  We discussed separation of concerns and the IoC container support in the MvcContrib OSS project.  Check it out.

Subscribe to my blog: http://feeds.feedburner.com/jeffreypalermo

Easily extend post-commit hook in Subversion using NAnt – email anyone?

There are several scripts floating around the Net regarding publishing an email to the development list every time someone commits a revision to Subversion.

In other cases, you may want to post the commit log entry directly to your project tracking system, such as trac, Rally, Gemini, Mingle, etc.  Anything under the sun can be coded into a post-commit action with Subversion.

Here’s how it works.  Here is how to send post commit email from Subversion while running on Windows:

In your subversion repository, there is a hooks folder.  This contains some template files for you.  On a Windows system, you’ll want a file called post-commit.bat.  This batch command will be run immediately after Subversion commits a transactional revision to the repository.  You can do work on other events, but I’ll focus on post-commit for this post.

Here is my post-commit.bat file that will call NAnt (which is placed inside the hooks folder for simplicity):

pushd .
cd DRIVELETTER:svnrepositoriesrepositorynamehooks
nantnant.exe -buildfile:postcommitemail.build -D:path.repository=%1 -D:revision=%2 > lastpostcommitrun.txt
popd

Notice how we are merely calling nant.exe.  The rest of the interesting work is done by NAnt.  Now that we are within NAnt, we can script out any action we might need.  In this case, I’m going to use some SVN command line tools to build up a simple email that with send developers what was included in the last commit:

<?xml version="1.0" encoding="utf-8"?>
<project name="commit" default="build" xmlns="http://nant.sf.net/release/0.85/nant.xsd">
    <target name="build">

        <exec program="svnlook" commandline="author ${path.repository} -r ${revision}" output="author.txt"/>        
        <exec program="svnlook" commandline="info ${path.repository} -r ${revision}" output="message.txt"/>
        <echo message=" " file="message.txt" append="true"/>
        <exec program="svnlook" commandline="changed ${path.repository} -r ${revision}" output="message.txt" append="true" />
        <exec program="svnlook" commandline="diff ${path.repository} -r ${revision} --no-diff-deleted --no-diff-added" output="message.txt" append="true"/>
        
        <loadfile file="author.txt" property="author"/>
        <loadfile file="message.txt" property="message"/>
        <mail tolist=jeffrey@mydomain.com
            from=build@mydomain.com 
            subject="SVN ${path.repository} - ${author}" 
            message="${message}" 
            mailhost="smtp.mydomain.com"/>
    </target>

</project>

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

That’s all it takes.  I can write anything I need to in order to perform custom actions when things happen with my Subversion repository.  In this case, I’m sending email to a list, and the email contains the last commit.