Comments In Code Aren't Evil. Bad Comments Are.

Jun
06
2009

I've been watching an exchange of articles over the last couple of days stemming from 10 Commandments for Creating Good Code. It's a pretty good list, but several people (including me) think he may have missed the mark with his take on code comments.

I posted a comment on the followup, but thought I'd take a few minutes to tinker with doing some video as a response as well. Steve Borsch suggested that I should start video blogging and I figured I'd give it a shot. So, here's the video version.

ASP.NET MVC Plugins

Dec
05
2008

One of the last things I posted here was how I was toying with flexible content and template solutions in ASP.NET MVC. For that project, we're going forward with the solution that emerged from that experimentation and I'm excited to see how it turns out. 

Along the way, an interesting question about how to create what are essentially plugins for the MVC framework. Basically, if what you're building is an MVC app that will be deployed in dozens, hundreds or thousands of independent implementations, it becomes obvious pretty quickly that you need most of the pieces of the application to be modular so they can added/removed/overridden at least to a minimal level.

I've come up with what I think is a workable solution, which is pretty much just gathering up some of the other ideas already out there into a quick-n-dirty working prototype. The basic idea is this:

Put an encapsulated set of model classes (or none if you depend on central model classes), controller classes and a set of views into its own DLL. The views (using the default WebForms view engine, they're aspx files) go in as resources.

Pull that DLL into your MVC application and the MVC stack inside your "plugin" will work just like if those bits had been a "natural" part of the base MVC application. In fact actually creating the pieces from inside the main app and then moving them over to their own project is the quickest way I found to actually create the bits for the plugins.

When the question came up, I vaguely remembered seeing a question on StackOverflow about how to put views into an assembly/DLL. That question along with one on VirtualPathProviders provided most of the kernel of what I needed.

So, on to how to actually do this.
Read the rest of this entry »

Archiving My Twitter History

Nov
05
2008

I've been using Twitter off and on since late 2006 and have racked up almost 2000 entries in that time. Earlier this year, when Twitter hit stretches where the service was out for entire days at a time, I started using Friendfeed to do the actual posting and pushed those posts over to Twitter.

Part of what sent me over to Friendfeed was a sinking feeling that most of those early posts would go down with the ship and I wanted to get some redundancy in where that ephemera was showing up online. Most of those posts were throwaway (see Sturgeon's Law) but I also know how much I enjoy going through slices of complete ordinariness after my memory of the events has faded. So, I want to keep a copy of all of this stuff and figure out later what's interesting.

At any rate, given Twitter's problems, I tried to get those old posts out whenever things would work for a patch. Unfortunately, even when things were working, if you went back through the pages of the archive, you'd get about 10 pages in and hit a wall. Given that my Twitter history is about 100 pages long, that left the vast majority of my posts behind that wall, possibly never to be seen again.

However, not wanting to resign myself to just having an archive going forward, I put an entry on my calendar to keep trying every few weeks, just in case they eventually fixed things. So, tonight, the reminder popped up and, what do you know? I could go through all 99 pages of my archive.

Not wanting to lose what very well may be a 1-time window of opportunity (they've pretty much said that the instant messaging isn't coming back), I banged out a quick console app to grab all of my posts into files for later processing.

It's mostly copy-n-paste stuff (don't judge, it was written while I was eating curly fries and a roast beef sandwich), but I did include bits to hold off for an hour and wait if it gets throttled by the 100 requests per hour limit from Twitter. If you've got a lot of stuff on Twitter, running this may best be done overnight.

At any rate, it grabs the posts 20 at a time and saves them to a directory as .atom files. You set the Twitter username and password in the app.config file like this:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <appSettings>
    <add key="TwitterUsername" value="jwynia"/>
    <add key="TwitterPassword" value="IM_NOT_THAT_DUMB"/>
  </appSettings>
</configuration>

And then a basic console app (with some extra namespaces from stuff I threw away still in there), looks like this. I didn't bother with any of the API wrappers, just using basic .NET code to do it.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Configuration;
using System.Collections.Specialized;
using System.Security;
using System.Net;
using System.IO;
using System.Xml;
using System.Xml.XPath;

namespace TwitterArchiver
{
    class Program
    {
        public static String Username {get;set;}
        public static String Password { get; set; }
        public static NetworkCredential TwitterCredential { get; set; }
        static void Main(string[] args)
        {
            NameValueCollection appSettings = ConfigurationManager.AppSettings;
            Username = appSettings.Get("TwitterUsername");
            Password = appSettings.Get("TwitterPassword");
            TwitterCredential = new NetworkCredential(Username, Password);
            String OutputDir = Username + "-export";
            Directory.CreateDirectory(OutputDir);

            int NumberOfPages = GetUserPageCount();
            for (int i = 1; i <= NumberOfPages; i++)
            {
                String ArchivePage = GetArchivePage(i);
                WriteStringToFile(ArchivePage, OutputDir + "/" + Username + "-page-" + i.ToString() + ".atom");
                System.Threading.Thread.Sleep(1000);
            }

            Console.WriteLine("=====Press any key to continue=====");
            Console.ReadLine();

        }
        public static void WriteStringToFile(String InputString, String Filename)
        {
            StreamWriter sw = new StreamWriter(Filename);
            sw.WriteLine(InputString);
            sw.Close();
        }
        public static String GetArchivePage(int PageNumber)
        {
            Uri TwitterBaseUri = new Uri("http://twitter.com/statuses/user_timeline/" + Username + ".atom?page=" + PageNumber.ToString());
            CredentialCache myCache = new CredentialCache();
            myCache.Add(TwitterBaseUri, "Basic", TwitterCredential);

            WebRequest request = WebRequest.Create(TwitterBaseUri);
            request.Credentials = myCache;
            string responseFromServer;
            try
            {
                HttpWebResponse response = (HttpWebResponse)request.GetResponse();
                Console.WriteLine(response.StatusDescription);
                Stream dataStream = response.GetResponseStream();
                StreamReader reader = new StreamReader(dataStream);
                responseFromServer = reader.ReadToEnd();
                reader.Close();

                dataStream.Close();
                response.Close();
            }
            catch
            {
                System.Threading.Thread.Sleep(1000 * 3600);
                responseFromServer = GetArchivePage(PageNumber);
            }
            return responseFromServer;
        }
        public static int GetUserPageCount(){
            Uri TwitterBaseUri = new Uri(" http://twitter.com/users/show/" + Username + ".xml");
            CredentialCache myCache = new CredentialCache();
            myCache.Add(TwitterBaseUri, "Basic", TwitterCredential);

            WebRequest request = WebRequest.Create(TwitterBaseUri);
            request.Credentials = myCache;
            int NumberOfPages = 0;
            try
            {
                HttpWebResponse response = (HttpWebResponse)request.GetResponse();
                Console.WriteLine(response.StatusDescription);
                Stream dataStream = response.GetResponseStream();
                XPathDocument ResponseDoc = new XPathDocument(dataStream);
                XPathNavigator ResponseNavigator = ResponseDoc.CreateNavigator();
                XPathNodeIterator ResponseIterator = ResponseNavigator.Select("//user/statuses_count");
                ResponseIterator.MoveNext();
                int PostCount = int.Parse(ResponseIterator.Current.Value);
                dataStream.Close();
                response.Close();
                NumberOfPages = PostCount / 20;
                if ((PostCount % 20) > 0)
                {
                    NumberOfPages++;
                }
            }
            catch
            {
                System.Threading.Thread.Sleep(1000 * 3600);
                NumberOfPages = GetUserPageCount();
            }
            return NumberOfPages;
        }

    }
}

Build and run that and you, too, can see what you ate for dinner 2 years ago. I think I might put together a highlight post of my personal favorites from my archive to make this worthwhile.

At any rate, I need to get back to more pressing matters (the economy might be slow, but I'm busier than ever right now and what looks like into 2009, so I shouldn't complain). Later.

Ideas for Content Management in ASP.NET MVC

Oct
05
2008

I've been working on quite a few projects where I'm either already directly developing within the ASP.NET MVC Framework or where the framework is prominently featured in my design/architecture documents.

Because the framework is so new, there are still a few kinks and the patterns for how to do some common things haven't yet sorted themselves out. One of those areas is how to handle content in web applications.

All of these projects are web applications that *do* stuff. Most of these apps are filled with pages to edit things, retrieve data, manage queues, etc. In other words, the custom business logic that's unique to my clients' and my businesses. However, every single one also needs a batch of "pages" that *are* just basic content, with a few variables (like who's logged in) sprinkled through them.

The pattern that appears to be recommended by the ASP.NET team (via what is in the project template for the "home" and "about us" pages) basically requires a new view and a new action in a controller for each page, which, for those playing along at home, also requires rebuilding the app and redeploying.

Experience has taught me that solutions like that inevitably lead to pain. Once deployed, people always want to add pages, change them and otherwise mess with things more often than anyone wants to go through the build/deploy cycle. That leaves me looking for something that has the content more separated from the aspx setup than the default pattern seems to suggest.

It's at this point in the conversations I've had about this topic that a variety of ASP.NET content management systems are brought up. The problem with all of them that I've checked out from this angle boils down to what you consider the "center" of the app.

If your app is mostly content, with some custom functionality, these CMS solutions can work well. That's because all of them push you to do your custom functionality as a plugin to their framework. Beyond that, most of them don't handle or do well with things like variables being embedded in random paragraphs, extreme personalization, switching out paragraphs based on roles, etc.

OK, so that leads to using a CMS *library*. I looked at a few of those too. Several didn't do variables at all, another few were basically just wiki article storage, another few made everything "news" or "blog posts" and shoehorned it into that. The choices left me a little cold.

After looking at all of these possibilities, I wanted to take a stab at exploring a solution in a "hands-on" way as that approach tends to let me really get inside the problem. Often after working through a proof of concept, even if I end up going with one of the pre-packaged solutions, I can do a much better job of picking the right one and understanding the pro's and con's of each.

So, I took a bit of time to run through this problem and work it out in POC code.

The first place I looked was at the alternate view engines for MVC. Several of them look interesting, but I'm planning on sticking with the default WebForms engine for all of the non-content functionality. That actually means not using the alternative view engine that actually implements the technology that I ended up using in my POC.

There are reasons for sticking to the WebForms view engine for at least the short term. One of them is that the default path inside the MVC ecosystem is going to get the most attention to work through patterns that work. Another is to leverage familiarity in the area where the hardest work has to be done in these apps (the custom business logic and rules). Several of the projects involve other devs, so going to MVC is already going to be an adaptation for them (though one I think is worth it).

OK. On to what I did in my POC. I knew that I wanted to leverage a templating system in some way. One that came up over and over when doing research was Jakarta Velocity, a Java solution from the Apache Foundation (a group that usually thinks things through pretty carefully).

NVelocity brings that engine to .NET, but hasn't been updated since 2003. Fortunately, the folks over at the Castle Project picked NVelocity up and have been maintaining it improving it as well. As I mentioned earlier, NVelocity is also one of the alternate view engines. Though I have reasons for not using it in that way, it is an additional vote of confidence for it.

NVelocity templates are written in the Velocity Templating Language, which gives all of the elements I need for the problems I'm looking at right now.

The first problem I did run into when using NVelocity inside of my POC MVC app was that the basic Castle implementation wants the NVelocity templates on the disk as files. That defeats most of my purpose here as I want the templated content to come out of the database and be editable there as well.

Fortunately, this CodeProject code adds the ability to use NVelocity with a template that comes from
a string instead of having to have them in individual files on disk by creating a memory-based engine implementation.

I basically aimed to have pages made up of snippets for this POC. A PageController action of Details() takes a string I called "Slug" which is the URL-based name of the requested page. That base page is loaded and is parsed for tokens that point to template snippets. Those snippets are then integrated into the composite template before feeding it to the NVelocity engine.

I chose a token for handling includes (double braces on each side of the named key). My initial proof of concept only did one level of inclusion: a page and snippets of content, but this method could handle whatever level of recursion that's necessary.

So, a page named "home" could have a token:

{{user-details}}

which would be replaced by the snippet of template code that has the unique key "user-details" from the content repository. The recursion would be handled by tracing through the tree of those included tokens for a given page until the nested tree is built.

The controller needs to build up objects that fulfill all of the variables in the templates. A production implementation of this would need to provide a way to report on the dependencies that a given composite template requires to avoid empty slots.

However, since NVelocity handles doing things like passing objects more complex than basic strings, this can be much easier than it might be otherwise. So, you can do something like pass (User)CurrentUser to the template, which can have properties pulled into the template from there. By passing that one object, you can have a template like:

The account for $CurrentUser.FirstName $CurrentUser.LastName is currently $CurrentUser.AccountStatus with a balance of $CurrentUser.AccountBalance

That ability also handles one of the peripheral problems I hadn't included as part of the scope of this POC, but became an obvious fit along the way: internationalization. If you provided an object with all of the label text, button text, menu names, etc. as UTF-8 text in the properties, you could fill all of those bits in as:

$Labels.Home | $Labels.AboutUs | $Labels.MyAccount

Overall, I like the flexibility and don't see anything really standing out as a roadblock to this solving the CMS needs I have in this range of projects. There will definitely have to be some work on the back-end administration of this content to catch missing objects and judicious use of caching of both objects and composite templates to keep it from slowing things down, but I think those are definitely solvable.

NVelocity handles the kind of dictionary objects I'd like to hand off to CMS pages, conditional rules, basic looping, etc. At the same time, it lets you manage most of this stuff outside of code (provided that you provide some decent structure to the objects available to the PageController for all of the pages (things like CurrentUser, SiteSettings, ThemeInformation, etc.).

That ThemeInformation object actually hits on one other requirement of one of the projects in particular where I need user-defined theming for things like fonts and colors, thus lining up the birds nicely for a stone to be thrown.

The template language is pretty much just basic HTML with simple variables and loops, making it pretty easy for people outside of the dev team to work with as well, without a WYSIWYG editor (which would make the back end a much bigger pain to develop). It also can be re-used for template-based emails from these same systems pretty much wholesale.

At this point, I'd really like input on the approach and opportunities to improve it. Solving this problem well is something that will make all of my MVC projects much easier and be really re-usable.

Standardized ASP.NET MVC Controller Actions with Visual Studio Item Templates

Sep
07
2008

First, I think that this may be the longest title for any post on this site. I ditched 2-3 other variations for the only one that accurately describes this post.

Anyway, over the last couple of months, I've been working on getting better with screencasting tools. I learned a lot doing the last one and took that into the tinkering I've done with another one over the past week or so.

It stretched out over that timeframe because of a bunch of other stuff going on as well as some time spent on one-time tasks, like creating a Keynote theme to use for future screencasts that's a bit better thought out than the one I used on the last screencast. This look is something I'm much happier with and gives me a basis for more consistent look and feel going forward.

There's none of my shining face because I lent my webcam to a friend. I do see the value in adding that to the recording, but am not sure the best way to do it.

Anyway, on to the topic I actually covered in this video.

In ASP.NET MVC, the Controllers often end up with an Action method for all of the really common bits of functionality: Create, Insert, Update, Delete, etc. Stephen Walther put together a list of suggested standardized naming and usage for these Actions and I've been using them in the couple of ASP.NET MVC projects I'm working on.

In the process, I created a Visual Studio Item Template to make creating a new Controller that follows that convention easy. When I showed it to a co-worker, he expressed interest in how I did it and I saw an opportunity to explain something that's actually useful.

So, if you've ever wondered how to get your own templates into that Visual Studio "Add New Item" dialog box next to "Class Library", "Application Config File", etc. This is the screencast for you.

Anyway, give it a watch and let me know what you think.


Creating Visual Studio Item Templates from J Wynia on Vimeo.

« Older Entries  

J Wynia

For better or worse, I'm the guy who runs things here. I'm a web consultant, software developer, writer and geek from Minneapolis, MN. This site is a fairly wide cross-section of the things I'm interested in and enjoy writing about.

Oh, and if you happen to be looking for hosting for your Subversion repositories or just web hosting in general, take a look at Dreamhost. It's what I use for Subversion and your signup helps me out.

Feeds and Links


www.flickr.com
This is a Flickr badge showing public photos from J Wynia. Make your own badge here.

Search


Pages

Archives

Computers Blog Directory
© 2003-2009 J Wynia. All original content is licensed under the terms of the Creative Commons Attribution license unless otherwise noted. Content from other sources is licensed under its original terms.